-
-
Notifications
You must be signed in to change notification settings - Fork 105
Feature: Implement /rewrite command for message improvement using Cha… #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
Open
firasrg
wants to merge
7
commits into
develop
Choose a base branch
from
firasrg/feature-slash-command-rewrite-msg
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+238
−17
Open
Changes from all commits
Commits
Show all changes
7 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 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
Some comments aren't visible on the classic Files Changed page.
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
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
184 changes: 184 additions & 0 deletions
184
application/src/main/java/org/togetherjava/tjbot/features/messages/RewriteCommand.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,184 @@ | ||
| package org.togetherjava.tjbot.features.messages; | ||
|
|
||
| import net.dv8tion.jda.api.entities.Message; | ||
| import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; | ||
| import net.dv8tion.jda.api.interactions.commands.OptionMapping; | ||
| import net.dv8tion.jda.api.interactions.commands.OptionType; | ||
| import net.dv8tion.jda.api.interactions.commands.build.OptionData; | ||
| import org.jetbrains.annotations.Nullable; | ||
| import org.slf4j.Logger; | ||
| import org.slf4j.LoggerFactory; | ||
|
|
||
| import org.togetherjava.tjbot.features.CommandVisibility; | ||
| import org.togetherjava.tjbot.features.SlashCommandAdapter; | ||
| import org.togetherjava.tjbot.features.chatgpt.ChatGptModel; | ||
| import org.togetherjava.tjbot.features.chatgpt.ChatGptService; | ||
|
|
||
| import java.util.Arrays; | ||
|
|
||
| /** | ||
| * The implemented command is {@code /rewrite}, which allows users to have their message rewritten | ||
| * in a clearer, more professional, or better structured form using AI. | ||
| * <p> | ||
| * The rewritten message is shown as an ephemeral message visible only to the user who triggered the | ||
| * command. | ||
| * <p> | ||
| * Users can optionally specify a tone/style for the rewrite. | ||
| */ | ||
| public final class RewriteCommand extends SlashCommandAdapter { | ||
| private static final Logger logger = LoggerFactory.getLogger(RewriteCommand.class); | ||
| private 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 = Message.MAX_CONTENT_LENGTH; | ||
| private static final int MIN_MESSAGE_LENGTH = 3; | ||
|
|
||
| private static final String AI_REWRITE_PROMPT_TEMPLATE = """ | ||
| You are rewriting a Discord text chat message for clarity and professionalism. | ||
| Keep it conversational and casual, not email or formal document format. | ||
|
|
||
| Tone: %s | ||
|
|
||
| Rewrite the message to: | ||
| - Improve clarity and structure | ||
| - Maintain the original meaning | ||
| - Avoid em-dashes (—) | ||
| - Stay under %d characters (strict limit) | ||
|
|
||
| If the message is already well-written, make only minor improvements. | ||
|
|
||
| Message to rewrite: | ||
| %s | ||
| """.stripIndent(); | ||
|
|
||
| private final ChatGptService chatGptService; | ||
|
|
||
| /** | ||
| * Creates the slash command definition and configures available options for rewriting messages. | ||
| * | ||
| * @param chatGptService service for interacting with ChatGPT | ||
| */ | ||
| public RewriteCommand(ChatGptService chatGptService) { | ||
| super(COMMAND_NAME, "Let AI rephrase and improve your message", CommandVisibility.GUILD); | ||
|
|
||
| this.chatGptService = chatGptService; | ||
|
|
||
| OptionData messageOption = | ||
| new OptionData(OptionType.STRING, MESSAGE_OPTION, "The message you want to rewrite", | ||
| true) | ||
| .setMinLength(MIN_MESSAGE_LENGTH) | ||
| .setMaxLength(MAX_MESSAGE_LENGTH); | ||
|
|
||
| OptionData toneOption = new OptionData(OptionType.STRING, TONE_OPTION, | ||
| "The tone/style for the rewritten message (default: " | ||
| + MessageTone.CLEAR.displayName + ")", | ||
| false); | ||
Taz03 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| Arrays.stream(MessageTone.values()) | ||
| .forEach(tone -> toneOption.addChoice(tone.displayName, tone.name())); | ||
|
|
||
| getData().addOptions(messageOption, toneOption); | ||
| } | ||
|
|
||
| @Override | ||
| public void onSlashCommand(SlashCommandInteractionEvent event) { | ||
tj-wazei marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| OptionMapping messageOption = event.getOption(MESSAGE_OPTION); | ||
|
|
||
| if (messageOption == null) { | ||
| throw new IllegalArgumentException( | ||
| "Required option '" + MESSAGE_OPTION + "' is missing"); | ||
| } | ||
|
|
||
| String userMessage = messageOption.getAsString(); | ||
|
|
||
| MessageTone tone = parseTone(event.getOption(TONE_OPTION)); | ||
|
|
||
| event.deferReply(true).queue(); | ||
|
|
||
| String rewrittenMessage = rewrite(userMessage, tone); | ||
|
|
||
| if (rewrittenMessage.isEmpty()) { | ||
| logger.debug("Failed to obtain a response for /{}, original message: '{}'", | ||
| COMMAND_NAME, userMessage); | ||
|
|
||
| event.getHook() | ||
| .editOriginal( | ||
tj-wazei marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| "An error occurred while processing your request. Please try again later.") | ||
| .queue(); | ||
|
|
||
| return; | ||
| } | ||
|
|
||
| logger.debug("Rewrite successful; rewritten message length: {}", rewrittenMessage.length()); | ||
|
|
||
| event.getHook().sendMessage(rewrittenMessage).setEphemeral(true).queue(); | ||
| } | ||
|
|
||
| private MessageTone parseTone(@Nullable OptionMapping toneOption) | ||
| throws IllegalArgumentException { | ||
|
|
||
| if (toneOption == null) { | ||
| logger.debug("Tone option not provided, using default '{}'", MessageTone.CLEAR.name()); | ||
| return MessageTone.CLEAR; | ||
| } | ||
|
|
||
| return MessageTone.valueOf(toneOption.getAsString()); | ||
| } | ||
|
|
||
| private String rewrite(String userMessage, MessageTone tone) { | ||
|
|
||
| String rewritePrompt = createAiPrompt(userMessage, tone); | ||
|
|
||
| ChatGptModel aiModel = tone.model; | ||
|
|
||
| String attempt = askAi(rewritePrompt, aiModel); | ||
|
|
||
| if (attempt.length() <= MAX_MESSAGE_LENGTH) { | ||
| return attempt; | ||
| } | ||
|
|
||
| logger.debug("Rewritten message exceeded {} characters; retrying with stricter constraint", | ||
tj-wazei marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| MAX_MESSAGE_LENGTH); | ||
|
|
||
| String shortenPrompt = | ||
| """ | ||
| %s | ||
|
|
||
| Constraint reminder: Your previous rewrite exceeded %d characters. | ||
| Provide a revised rewrite strictly under %d characters while preserving meaning and tone. | ||
| """ | ||
| .formatted(rewritePrompt, MAX_MESSAGE_LENGTH, MAX_MESSAGE_LENGTH); | ||
|
|
||
| return askAi(shortenPrompt, aiModel); | ||
| } | ||
|
|
||
| private String askAi(String shortenPrompt, ChatGptModel aiModel) { | ||
| return chatGptService.askRaw(shortenPrompt, aiModel).orElse(""); | ||
| } | ||
|
|
||
| private static String createAiPrompt(String userMessage, MessageTone tone) { | ||
| return AI_REWRITE_PROMPT_TEMPLATE.formatted(tone.description, MAX_MESSAGE_LENGTH, | ||
| userMessage); | ||
| } | ||
|
|
||
| private enum MessageTone { | ||
tj-wazei marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| CLEAR("Clear", "Make it clear and easy to understand.", ChatGptModel.FASTEST), | ||
| PROFESSIONAL("Professional", "Use a professional and polished tone.", ChatGptModel.FASTEST), | ||
| DETAILED("Detailed", "Expand with more detail and explanation.", ChatGptModel.HIGH_QUALITY), | ||
| TECHNICAL("Technical", "Use technical and specialized language where appropriate.", | ||
| ChatGptModel.HIGH_QUALITY); | ||
|
|
||
| private final String displayName; | ||
| private final String description; | ||
| private final ChatGptModel model; | ||
|
|
||
| MessageTone(String displayName, String description, ChatGptModel model) { | ||
| this.displayName = displayName; | ||
| this.description = description; | ||
| this.model = model; | ||
| } | ||
| } | ||
|
|
||
| } | ||
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.