-
-
Notifications
You must be signed in to change notification settings - Fork 109
Added /rewrite for improving a message using AI #1378
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 1 commit
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
e4f888c
Feature: Implement /rewrite command for message improvement using Cha…
firasrg ef2626f
Merge remote-tracking branch 'origin/develop' into firasrg/feature-sl…
firasrg 5707f50
feature "rewrite-msg command": applies changes due to Zabu's first re…
firasrg a8a761e
feature "rewrite-msg command": applies changes due to Wazei's first r…
firasrg 311d060
feature "rewrite-msg command": applies changes due to Wazei's first r…
firasrg 0604f9b
feature "rewrite-msg command": applies changes due to Wazei's first r…
firasrg aebfa42
feature "rewrite-msg command": removing Optional and other adjustments
firasrg 2b55087
feature "rewrite-msg command" - reply to taz 2nd review;
firasrg 5eea861
ChatGptService: MAX_TOKENS value updated to 1000;
firasrg File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
107 changes: 107 additions & 0 deletions
107
application/src/main/java/org/togetherjava/tjbot/features/messages/RewriteMsgCommand.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,107 @@ | ||
| package org.togetherjava.tjbot.features.messages; | ||
|
|
||
| import net.dv8tion.jda.api.entities.MessageEmbed; | ||
| import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; | ||
| import net.dv8tion.jda.api.interactions.commands.OptionType; | ||
| import net.dv8tion.jda.api.interactions.commands.build.OptionData; | ||
| import org.slf4j.Logger; | ||
| import org.slf4j.LoggerFactory; | ||
|
|
||
| import org.togetherjava.tjbot.features.CommandVisibility; | ||
| import org.togetherjava.tjbot.features.SlashCommandAdapter; | ||
|
|
||
| import java.util.Arrays; | ||
| import java.util.Optional; | ||
|
|
||
| /** | ||
| * The implemented command is {@code /rewrite}, which allows users to have their message rewritten | ||
| * in a clearer, more professional, or better structured form using ChatGPT AI. | ||
| * <p> | ||
| * The rewritten message is shown as an ephemeral message visible only to the user who triggered the | ||
| * command, making it perfect for getting quick writing improvements without cluttering the channel. | ||
|
tj-wazei marked this conversation as resolved.
Outdated
|
||
| * <p> | ||
| * Users can optionally specify a tone/style for the rewrite. If not provided, defaults to CLEAR. | ||
|
tj-wazei marked this conversation as resolved.
Outdated
|
||
| */ | ||
| public final class RewriteMsgCommand extends SlashCommandAdapter { | ||
|
Zabuzard marked this conversation as resolved.
Outdated
|
||
| private static final Logger logger = LoggerFactory.getLogger(RewriteMsgCommand.class); | ||
|
Zabuzard marked this conversation as resolved.
Outdated
|
||
| public static final String COMMAND_NAME = "rewrite"; | ||
| private static final String MESSAGE_OPTION = "message"; | ||
| private static final String TONE_OPTION = "tone"; | ||
| private static final int MAX_MESSAGE_LENGTH = 500; | ||
| private static final int MIN_MESSAGE_LENGTH = 3; | ||
|
|
||
| private final RewriteMsgService rewriteMsgService; | ||
|
|
||
|
|
||
|
Zabuzard marked this conversation as resolved.
Outdated
|
||
| public RewriteMsgCommand(RewriteMsgService rewriteMsgService) { | ||
| super(COMMAND_NAME, "Rewrite your message in a clearer, more professional form", | ||
|
Zabuzard marked this conversation as resolved.
Outdated
|
||
| CommandVisibility.GUILD); | ||
|
|
||
| this.rewriteMsgService = rewriteMsgService; | ||
|
|
||
| logger.debug("Initializing RewriteMsgCommand with ChatGptService and HelpSystemHelper"); | ||
|
Zabuzard marked this conversation as resolved.
Outdated
|
||
|
|
||
| final OptionData toneOption = new OptionData(OptionType.STRING, TONE_OPTION, | ||
| "The tone/style for the rewritten message (default: " | ||
| + RewriteMsgTone.CLEAR.getDisplayName() + ")", | ||
| false); | ||
|
|
||
| logger.debug("Adding tone choices to command options"); | ||
|
Zabuzard marked this conversation as resolved.
Outdated
|
||
| Arrays.stream(RewriteMsgTone.values()).forEach(tone -> { | ||
| toneOption.addChoice(tone.getDisplayName(), tone.name()); | ||
| logger.debug("Added tone choice: {} ({})", tone.getDisplayName(), tone.name()); | ||
|
Zabuzard marked this conversation as resolved.
Outdated
|
||
| }); | ||
|
|
||
| final OptionData messageOption = | ||
| new OptionData(OptionType.STRING, MESSAGE_OPTION, "The message you want to rewrite", | ||
| true) | ||
| .setMinLength(MIN_MESSAGE_LENGTH) | ||
| .setMaxLength(MAX_MESSAGE_LENGTH); | ||
|
|
||
| logger.debug("Configured message option: min={}, max={}", MIN_MESSAGE_LENGTH, | ||
| MAX_MESSAGE_LENGTH); | ||
|
Zabuzard marked this conversation as resolved.
Outdated
|
||
|
|
||
| super.getData().addOptions(messageOption, toneOption); | ||
|
Zabuzard marked this conversation as resolved.
Outdated
|
||
| logger.debug("RewriteMsgCommand initialization complete"); | ||
| } | ||
|
|
||
| @Override | ||
| public void onSlashCommand(SlashCommandInteractionEvent event) { | ||
| logger.debug("onSlashCommand method invoked"); | ||
|
Zabuzard marked this conversation as resolved.
Outdated
|
||
| event.deferReply(true).queue(); | ||
| logger.debug("Reply deferred as ephemeral"); | ||
|
|
||
| final String userId = event.getUser().getId(); | ||
|
|
||
| logger.info("Rewrite command triggered by user: {}", userId); | ||
|
Zabuzard marked this conversation as resolved.
Outdated
|
||
|
|
||
| final String userMessage = | ||
| this.rewriteMsgService.validateMsg(event.getOption(MESSAGE_OPTION), userId); | ||
|
|
||
| final RewriteMsgTone tone = | ||
| this.rewriteMsgService.parseTone(event.getOption(TONE_OPTION), userId); | ||
|
|
||
| final Optional<String> rewrittenMessage = | ||
| this.rewriteMsgService.rewrite(userMessage, tone, userId); | ||
|
|
||
| final Optional<MessageEmbed> responseEmbed = | ||
|
Zabuzard marked this conversation as resolved.
Outdated
|
||
| this.rewriteMsgService.buildResponse(userMessage, rewrittenMessage.orElse(null), | ||
| tone, userId, event.getJDA().getSelfUser()); | ||
|
|
||
| logger.debug("Sending embed response to user: {}", userId); | ||
|
Zabuzard marked this conversation as resolved.
Outdated
|
||
|
|
||
| if (responseEmbed.isPresent()) { | ||
| event.getHook() | ||
| .sendMessageEmbeds(responseEmbed.get()) | ||
|
Zabuzard marked this conversation as resolved.
Outdated
|
||
| .queue(_ -> logger.info("Rewrite response sent successfully to user: {}", userId), | ||
|
Zabuzard marked this conversation as resolved.
Outdated
|
||
| error -> logger.error("Failed to send rewrite response to user: {}", userId, | ||
| error)); | ||
|
Zabuzard marked this conversation as resolved.
Outdated
|
||
| } else { | ||
| logger.error("Failed to build response embed for user: {}", userId); | ||
|
Zabuzard marked this conversation as resolved.
Outdated
|
||
| event.getHook() | ||
| .sendMessage( | ||
| "An error occurred while processing your request. Please try again later.") | ||
|
Zabuzard marked this conversation as resolved.
Outdated
|
||
| .queue(); | ||
| } | ||
|
Zabuzard marked this conversation as resolved.
Outdated
|
||
| } | ||
| } | ||
139 changes: 139 additions & 0 deletions
139
application/src/main/java/org/togetherjava/tjbot/features/messages/RewriteMsgService.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,139 @@ | ||
| package org.togetherjava.tjbot.features.messages; | ||
|
|
||
| import net.dv8tion.jda.api.entities.MessageEmbed; | ||
| import net.dv8tion.jda.api.entities.SelfUser; | ||
| import net.dv8tion.jda.api.interactions.commands.OptionMapping; | ||
| import org.jetbrains.annotations.Nullable; | ||
| import org.slf4j.Logger; | ||
| import org.slf4j.LoggerFactory; | ||
|
|
||
| import org.togetherjava.tjbot.features.chatgpt.ChatGptModel; | ||
| import org.togetherjava.tjbot.features.chatgpt.ChatGptService; | ||
| import org.togetherjava.tjbot.features.help.HelpSystemHelper; | ||
|
|
||
| import java.util.Optional; | ||
|
|
||
| /** | ||
| * Service for handling rewrite command business logic and ChatGPT integration. | ||
| */ | ||
| public class RewriteMsgService { | ||
|
Zabuzard marked this conversation as resolved.
Outdated
|
||
| private static final Logger logger = LoggerFactory.getLogger(RewriteMsgService.class); | ||
| private static final ChatGptModel CHAT_GPT_MODEL = ChatGptModel.HIGH_QUALITY; | ||
|
|
||
| private final ChatGptService chatGptService; | ||
| private final HelpSystemHelper helper; | ||
|
Zabuzard marked this conversation as resolved.
Outdated
|
||
|
|
||
| /** | ||
| * Creates a new RewriteMsgService. | ||
| * | ||
| * @param chatGptService the ChatGPT service | ||
| * @param helper the help system helper for embed formatting | ||
| */ | ||
| public RewriteMsgService(ChatGptService chatGptService, HelpSystemHelper helper) { | ||
| this.chatGptService = chatGptService; | ||
| this.helper = helper; | ||
| } | ||
|
|
||
| public String validateMsg(@Nullable OptionMapping messageOption, String userId) { | ||
| logger.debug("Extracting message option for user: {}", userId); | ||
| logger.debug("Retrieved message option: {}", messageOption != null ? "present" : "null"); | ||
|
Zabuzard marked this conversation as resolved.
Outdated
|
||
|
|
||
| final String userMessage = messageOption != null ? messageOption.getAsString() : ""; | ||
|
|
||
| if (userMessage.isEmpty()) { | ||
| logger.warn("User {} provided an empty message", userId); | ||
|
Zabuzard marked this conversation as resolved.
Outdated
|
||
| } else { | ||
| logger.debug("User {} provided message of length: {}", userId, userMessage.length()); | ||
| logMessagePreview(userMessage); | ||
| } | ||
|
|
||
| return userMessage; | ||
| } | ||
|
|
||
| public RewriteMsgTone parseTone(@Nullable OptionMapping toneOption, String userId) { | ||
| logger.debug("Extracting tone option for user: {}", userId); | ||
| logger.debug("Retrieved tone option: {}", toneOption != null ? "present" : "null"); | ||
|
Zabuzard marked this conversation as resolved.
Outdated
|
||
|
|
||
| if (toneOption == null) { | ||
| logger.debug("Tone option not provided, using default: {}", | ||
| RewriteMsgTone.CLEAR.getDisplayName()); | ||
| return RewriteMsgTone.CLEAR; | ||
| } | ||
|
|
||
| final String toneValue = toneOption.getAsString(); | ||
| try { | ||
| final RewriteMsgTone tone = RewriteMsgTone.valueOf(toneValue); | ||
| logger.debug("Parsed tone value from option: {}", toneValue); | ||
| return tone; | ||
| } catch (IllegalArgumentException e) { | ||
| logger.error("Invalid tone value provided: {}, using default CLEAR", toneValue, e); | ||
| return RewriteMsgTone.CLEAR; | ||
| } | ||
|
Zabuzard marked this conversation as resolved.
Outdated
|
||
| } | ||
|
|
||
| public Optional<String> rewrite(String userMessage, RewriteMsgTone tone, String userId) { | ||
| logger.debug("Rewriting message for user {} with tone: {}", userId, tone.getDisplayName()); | ||
|
|
||
| final String rewritePrompt = buildChatGptPrompt(userMessage, tone); | ||
| logger.debug("ChatGPT prompt prepared: {} characters", rewritePrompt.length()); | ||
|
Zabuzard marked this conversation as resolved.
Outdated
|
||
|
|
||
| try { | ||
| final Optional<String> rewrittenMessage = chatGptService.ask(rewritePrompt, | ||
| "Professional writing improvement", CHAT_GPT_MODEL); | ||
|
|
||
| if (rewrittenMessage.isPresent()) { | ||
| logger.info("Successfully rewrote message for user: {} with tone: {}", userId, | ||
| tone.getDisplayName()); | ||
|
Zabuzard marked this conversation as resolved.
Outdated
|
||
| logMessagePreview(rewrittenMessage.get()); | ||
|
Zabuzard marked this conversation as resolved.
Outdated
|
||
| } else { | ||
| logger.warn("ChatGPT returned empty response for user: {}", userId); | ||
|
Zabuzard marked this conversation as resolved.
Outdated
|
||
| } | ||
|
|
||
| return rewrittenMessage; | ||
| } catch (Exception e) { | ||
| logger.error("Failed to rewrite message for user: {}", userId, e); | ||
| return Optional.empty(); | ||
| } | ||
|
Zabuzard marked this conversation as resolved.
Outdated
|
||
| } | ||
|
|
||
| public Optional<MessageEmbed> buildResponse(String userMessage, | ||
| @Nullable String rewrittenMessage, RewriteMsgTone tone, String userId, | ||
| SelfUser selfUser) { | ||
| logger.debug("Building response embed for user: {}", userId); | ||
|
|
||
| final String responseContent = rewrittenMessage != null ? rewrittenMessage | ||
| : "Sorry, I couldn't rewrite your message at this time. Please try again later."; | ||
| final String embedTitle = "Rewritten message (" + tone.getDisplayName() + ")"; | ||
| logger.debug("Prepared embed title: {}", embedTitle); | ||
|
|
||
| try { | ||
| final MessageEmbed responseEmbed = helper.generateGptResponseEmbed( | ||
| "**Original:**\n" + userMessage + "\n\n**Rewritten:**\n" + responseContent, | ||
| selfUser, embedTitle, CHAT_GPT_MODEL); | ||
|
Zabuzard marked this conversation as resolved.
Outdated
|
||
| logger.debug("Message embed created successfully for user: {}", userId); | ||
| return Optional.of(responseEmbed); | ||
| } catch (Exception e) { | ||
|
Zabuzard marked this conversation as resolved.
Outdated
|
||
| logger.error("Failed to create message embed for user: {}", userId, e); | ||
|
Zabuzard marked this conversation as resolved.
Outdated
|
||
| return Optional.empty(); | ||
| } | ||
| } | ||
|
|
||
| private String buildChatGptPrompt(String userMessage, RewriteMsgTone tone) { | ||
| return """ | ||
| Please rewrite the following message to make it clearer, more professional, \ | ||
| and better structured. Maintain the original meaning while improving the quality \ | ||
| of the writing. Do NOT use em-dashes (—). %s | ||
|
|
||
| If the message is already well-written, provide minor improvements. | ||
|
|
||
| Original message: | ||
| %s""".formatted(tone.getPromptInstruction(), userMessage); | ||
| } | ||
|
|
||
| private void logMessagePreview(String message) { | ||
| final int previewLength = Math.min(50, message.length()); | ||
| final String preview = message.substring(0, previewLength); | ||
|
|
||
| logger.debug("Message content preview: {}", preview); | ||
|
Zabuzard marked this conversation as resolved.
Outdated
|
||
| } | ||
| } | ||
42 changes: 42 additions & 0 deletions
42
application/src/main/java/org/togetherjava/tjbot/features/messages/RewriteMsgTone.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| package org.togetherjava.tjbot.features.messages; | ||
|
|
||
| /** | ||
| * Enum representing the available tone/style options for message rewriting. | ||
| * <p> | ||
| * Each tone provides a specific instruction to ChatGPT for how to approach the rewrite. | ||
| */ | ||
| public enum RewriteMsgTone { | ||
|
Zabuzard marked this conversation as resolved.
Outdated
|
||
| CLEAR("Clear"), | ||
| PRO("Pro"), | ||
| DETAILED("Detailed"), | ||
| TECHNICAL("Technical"); | ||
|
|
||
| private final String displayName; | ||
|
|
||
| RewriteMsgTone(String displayName) { | ||
| this.displayName = displayName; | ||
| } | ||
|
|
||
| /** | ||
| * Gets the display name of this tone. | ||
| * | ||
| * @return the display name | ||
| */ | ||
| public String getDisplayName() { | ||
| return displayName; | ||
| } | ||
|
|
||
| /** | ||
| * Gets the prompt instruction for this tone. | ||
| * | ||
| * @return the prompt instruction to include in ChatGPT prompt | ||
| */ | ||
| public String getPromptInstruction() { | ||
|
Zabuzard marked this conversation as resolved.
Outdated
|
||
| return switch (this) { | ||
| case CLEAR -> "Make it clear and easy to understand."; | ||
| case PRO -> "Use a professional and polished tone."; | ||
| case DETAILED -> "Expand with more detail and explanation."; | ||
| case TECHNICAL -> "Use technical and specialized language where appropriate."; | ||
| }; | ||
| } | ||
|
Zabuzard marked this conversation as resolved.
Outdated
|
||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.