Skip to content
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

Feature: ChatGPT - Code formatter #1052

Draft
wants to merge 11 commits into
base: develop
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,9 @@ public static Collection<Feature> createFeatures(JDA jda, Database database, Con
ModAuditLogWriter modAuditLogWriter = new ModAuditLogWriter(config);
ScamHistoryStore scamHistoryStore = new ScamHistoryStore(database);
GitHubReference githubReference = new GitHubReference(config);
CodeMessageHandler codeMessageHandler =
new CodeMessageHandler(blacklistConfig.special(), jshellEval);
ChatGptService chatGptService = new ChatGptService(config);
CodeMessageHandler codeMessageHandler =
new CodeMessageHandler(blacklistConfig.special(), jshellEval, chatGptService);
HelpSystemHelper helpSystemHelper = new HelpSystemHelper(config, database, chatGptService);

// NOTE The system can add special system relevant commands also by itself,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public class ChatGptService {
* a separate iteration based on the input.
*/
private static final int MAX_NUMBER_OF_RESPONSES = 1;
private static final int MAX_CODE_LENGTH = 2000;
private static final String AI_MODEL = "gpt-3.5-turbo";

private boolean isDisabled = false;
Expand Down Expand Up @@ -96,12 +97,51 @@ public Optional<String> ask(String question, String context) {
return Optional.empty();
}

String instructions = "KEEP IT CONCISE, NOT MORE THAN 280 WORDS";
String questionWithContext = "context: Category %s on a Java Q&A discord server. %s %s"
.formatted(context, instructions, question);

return getMessageResponse(questionWithContext);
}

/**
* Provide ChatGPT with code to format.
*
* @param code the code to be formatted by ChatGPT. If code exceeds {@value MAX_CODE_LENGTH}
* characters then this method returns an empty {@link Optional}
* @return an optional response from ChatGPT as a String
*/
public Optional<String> formatCode(CharSequence code) {
if (isDisabled || code.length() > MAX_CODE_LENGTH) {
return Optional.empty();
}

String payload = String.format(
"""
If you happen to find any code in the container below, FORMAT \
IT regardless of the programming language you find. MAKE IT HUMANLY READABLE. \
Output with no introduction, no explanation, no ``` stuff, only code. Double \
check that your response is correct. The code provided might not be readable.

--- BEGIN CODE ---
%s
--- END CODE ---
""",
code);

return getMessageResponse(payload);
}

/**
* Prompt ChatGPT with a message and get its response.
*
* @param message the message to send to ChatGPT
* @return an optional response from ChatGPT as a String
*/
private Optional<String> getMessageResponse(String message) {
try {
String instructions = "KEEP IT CONCISE, NOT MORE THAN 280 WORDS";
String questionWithContext = "context: Category %s on a Java Q&A discord server. %s %s"
.formatted(context, instructions, question);
ChatMessage chatMessage = new ChatMessage(ChatMessageRole.USER.value(),
Objects.requireNonNull(questionWithContext));
ChatMessage chatMessage =
new ChatMessage(ChatMessageRole.USER.value(), Objects.requireNonNull(message));
Taz03 marked this conversation as resolved.
Show resolved Hide resolved
ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest.builder()
.model(AI_MODEL)
.messages(List.of(chatMessage))
Expand Down Expand Up @@ -131,6 +171,7 @@ public Optional<String> ask(String question, String context) {
logger.warn("There was an error using the OpenAI API: {}",
runtimeException.getMessage());
}

return Optional.empty();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package org.togetherjava.tjbot.features.code;

import org.togetherjava.tjbot.features.chatgpt.ChatGptService;

import java.util.Optional;

/**
* A utility class for formatting code using ChatGPT.
*/
public final class ChatGPTFormatter {
private final ChatGptService chatGptService;

/**
* Constructs a new {@link ChatGPTFormatter} with the provided {@link ChatGptService}.
*
* @param chatGptService the {@link ChatGptService} used for formatting code
*/
public ChatGPTFormatter(ChatGptService chatGptService) {
this.chatGptService = chatGptService;
}

/**
* Formats the provided code using ChatGPT.
*
* @param code the code to be formatted
* @return an Optional containing the formatted code if successful, empty otherwise
*/
public Optional<String> format(CharSequence code) {
return chatGptService.formatCode(code);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import org.togetherjava.tjbot.features.MessageReceiverAdapter;
import org.togetherjava.tjbot.features.UserInteractionType;
import org.togetherjava.tjbot.features.UserInteractor;
import org.togetherjava.tjbot.features.chatgpt.ChatGptService;
import org.togetherjava.tjbot.features.componentids.ComponentIdGenerator;
import org.togetherjava.tjbot.features.componentids.ComponentIdInteractor;
import org.togetherjava.tjbot.features.jshell.JShellEval;
Expand Down Expand Up @@ -68,11 +69,14 @@ public final class CodeMessageHandler extends MessageReceiverAdapter implements
* disabled
* @param jshellEval used to execute java code and build visual result
*/
public CodeMessageHandler(FeatureBlacklist<String> blacklist, JShellEval jshellEval) {
public CodeMessageHandler(FeatureBlacklist<String> blacklist, JShellEval jshellEval,
ChatGptService chatGptService) {
componentIdInteractor = new ComponentIdInteractor(getInteractionType(), getName());

List<CodeAction> codeActions = blacklist
.filterStream(Stream.of(new FormatCodeCommand(), new EvalCodeCommand(jshellEval)),
.filterStream(
Stream.of(new FormatCodeCommand(chatGptService),
new EvalCodeCommand(jshellEval)),
codeAction -> codeAction.getClass().getName())
.toList();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.entities.MessageEmbed;

import org.togetherjava.tjbot.features.chatgpt.ChatGptService;
import org.togetherjava.tjbot.features.utils.CodeFence;
import org.togetherjava.tjbot.formatter.Formatter;

Expand All @@ -13,6 +14,16 @@
*/
final class FormatCodeCommand implements CodeAction {
private final Formatter formatter = new Formatter();
private final ChatGPTFormatter chatGPTFormatter;

/**
* Initializes a {@link FormatCodeCommand} which formats code.
*
* @param service the {@link ChatGptService} instance to be used for code formatting
*/
public FormatCodeCommand(ChatGptService service) {
this.chatGPTFormatter = new ChatGPTFormatter(service);
}
christolis marked this conversation as resolved.
Show resolved Hide resolved

@Override
public String getLabel() {
Expand All @@ -33,7 +44,13 @@ public MessageEmbed apply(CodeFence codeFence) {
.build();
}

/**
* Formats the provided code using either the ChatGPT formatter or the generic formatter.
*
* @param code the code to be formatted
* @return the formatted code
*/
private String formatCode(CharSequence code) {
return formatter.format(code);
return chatGPTFormatter.format(code).orElse(formatter.format(code));
}
}
Loading