Skip to content

Improved ChatGpt requests and response handling #1262

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 3 commits into from
Jun 27, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,11 @@ public void onSlashCommand(SlashCommandInteractionEvent event) {
public void onModalSubmitted(ModalInteractionEvent event, List<String> args) {
event.deferReply().queue();

String context = "";
String question = event.getValue(QUESTION_INPUT).getAsString();

Optional<String> optional = chatGptService.ask(question, context);
if (optional.isPresent()) {
Optional<String> chatgptResponse =
chatGptService.ask(question, "You may use markdown syntax for the response");
if (chatgptResponse.isPresent()) {
userIdToAskedAtCache.put(event.getMember().getId(), Instant.now());
}

Expand All @@ -93,7 +93,7 @@ public void onModalSubmitted(ModalInteractionEvent event, List<String> args) {
Please try again later.
""";

String response = optional.orElse(errorResponse);
String response = chatgptResponse.orElse(errorResponse);
SelfUser selfUser = event.getJDA().getSelfUser();

MessageEmbed responseEmbed = helper.generateGptResponseEmbed(response, selfUser, question);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@

import org.togetherjava.tjbot.config.Config;

import javax.annotation.Nullable;

import java.time.Duration;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
Expand Down Expand Up @@ -91,37 +92,33 @@ public ChatGptService(Config config) {
* @see <a href="https://platform.openai.com/docs/guides/chat/managing-tokens">ChatGPT
* Tokens</a>.
*/
public Optional<String> ask(String question, String context) {
public Optional<String> ask(String question, @Nullable String context) {
if (isDisabled) {
return Optional.empty();
}

String contextText = context == null ? "" : ", Context: %s.".formatted(context);
String fullQuestion = "(KEEP IT CONCISE, NOT MORE THAN 280 WORDS%s) - %s"
.formatted(contextText, question);

ChatMessage chatMessage = new ChatMessage(ChatMessageRole.USER.value(), fullQuestion);
ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest.builder()
.model(AI_MODEL)
.messages(List.of(chatMessage))
.frequencyPenalty(FREQUENCY_PENALTY)
.temperature(TEMPERATURE)
.maxTokens(MAX_TOKENS)
.n(MAX_NUMBER_OF_RESPONSES)
.build();
logger.debug("ChatGpt Request: {}", fullQuestion);

String response = null;
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));
ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest.builder()
.model(AI_MODEL)
.messages(List.of(chatMessage))
.frequencyPenalty(FREQUENCY_PENALTY)
.temperature(TEMPERATURE)
.maxTokens(MAX_TOKENS)
.n(MAX_NUMBER_OF_RESPONSES)
.build();

String response = openAiService.createChatCompletion(chatCompletionRequest)
response = openAiService.createChatCompletion(chatCompletionRequest)
.getChoices()
.getFirst()
.getMessage()
.getContent();

if (response == null) {
return Optional.empty();
}

return Optional.of(response);
} catch (OpenAiHttpException openAiHttpException) {
logger.warn(
"There was an error using the OpenAI API: {} Code: {} Type: {} Status Code: {}",
Expand All @@ -131,6 +128,12 @@ public Optional<String> ask(String question, String context) {
logger.warn("There was an error using the OpenAI API: {}",
runtimeException.getMessage());
}
return Optional.empty();

logger.debug("ChatGpt Response: {}", response);
if (response == null) {
return Optional.empty();
}

return Optional.of(response);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.StringJoiner;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
Expand Down Expand Up @@ -127,36 +129,37 @@ public HelpSystemHelper(Config config, Database database, ChatGptService chatGpt
RestAction<Message> constructChatGptAttempt(ThreadChannel threadChannel,
String originalQuestion, ComponentIdInteractor componentIdInteractor) {
Optional<String> questionOptional = prepareChatGptQuestion(threadChannel, originalQuestion);
Optional<String> chatGPTAnswer;
Optional<String> chatGptAnswer;

if (questionOptional.isEmpty()) {
return useChatGptFallbackMessage(threadChannel);
}
String question = questionOptional.get();
logger.debug("The final question sent to chatGPT: {}", question);

ForumTag defaultTag = threadChannel.getAppliedTags().getFirst();
ForumTag matchingTag = getCategoryTagOfChannel(threadChannel).orElse(defaultTag);

String context = matchingTag.getName();
chatGPTAnswer = chatGptService.ask(question, context);
String context =
"Category %s on a Java Q&A discord server. You may use markdown syntax for the response"
.formatted(matchingTag.getName());
chatGptAnswer = chatGptService.ask(question, context);

if (chatGPTAnswer.isEmpty()) {
if (chatGptAnswer.isEmpty()) {
return useChatGptFallbackMessage(threadChannel);
}

StringBuilder idForDismissButton = new StringBuilder();
RestAction<Message> message =
AtomicReference<String> messageId = new AtomicReference<>("");
RestAction<Message> post =
mentionGuildSlashCommand(threadChannel.getGuild(), ChatGptCommand.COMMAND_NAME)
.map("""
Here is an AI assisted attempt to answer your question 🤖. Maybe it helps! \
In any case, a human is on the way 👍. To continue talking to the AI, you can use \
%s.
"""::formatted)
.flatMap(threadChannel::sendMessage)
.onSuccess(m -> idForDismissButton.append(m.getId()));
.onSuccess(message -> messageId.set(message.getId()));

String answer = chatGPTAnswer.orElseThrow();
String answer = chatGptAnswer.orElseThrow();
SelfUser selfUser = threadChannel.getJDA().getSelfUser();

int responseCharLimit = MessageEmbed.DESCRIPTION_MAX_LENGTH;
Expand All @@ -165,9 +168,8 @@ RestAction<Message> constructChatGptAttempt(ThreadChannel threadChannel,
}

MessageEmbed responseEmbed = generateGptResponseEmbed(answer, selfUser, originalQuestion);
return message.flatMap(any -> threadChannel.sendMessageEmbeds(responseEmbed)
.addActionRow(
generateDismissButton(componentIdInteractor, idForDismissButton.toString())));
return post.flatMap(any -> threadChannel.sendMessageEmbeds(responseEmbed)
.addActionRow(generateDismissButton(componentIdInteractor, messageId.get())));
}

/**
Expand Down Expand Up @@ -204,24 +206,21 @@ private Button generateDismissButton(ComponentIdInteractor componentIdInteractor

private Optional<String> prepareChatGptQuestion(ThreadChannel threadChannel,
String originalQuestion) {
StringJoiner question = new StringJoiner(" - ");

String questionTitle = threadChannel.getName();
StringBuilder questionBuilder = new StringBuilder(MAX_QUESTION_LENGTH);
question.add(questionTitle);
question.add(originalQuestion.substring(0,
Math.min(originalQuestion.length(), MAX_QUESTION_LENGTH)));

if (originalQuestion.length() < MIN_QUESTION_LENGTH
&& questionTitle.length() < MIN_QUESTION_LENGTH) {
// Not enough content for meaningful responses
if (question.length() < MIN_QUESTION_LENGTH) {
return Optional.empty();
}

questionBuilder.append(questionTitle).append(" ");
originalQuestion = originalQuestion.substring(0, Math
.min(MAX_QUESTION_LENGTH - questionBuilder.length(), originalQuestion.length()));

questionBuilder.append(originalQuestion);

questionBuilder.append(
". If possible, get, maximum, 5 top links from reliable websites as references in markdown syntax. Put this message on top of the links list \"Here are some links that may help :\".");

return Optional.of(questionBuilder.toString());
question.add(
"Additionally to answering the question, provide 3 useful links (as markdown list) from reliable websites on the topic. Write \"Useful links:\" as title for this list.");
return Optional.of(question.toString());
}

private RestAction<Message> useChatGptFallbackMessage(ThreadChannel threadChannel) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
import net.dv8tion.jda.api.exceptions.ErrorResponseException;
import net.dv8tion.jda.api.interactions.commands.build.Commands;
import net.dv8tion.jda.api.interactions.components.text.TextInput;
import net.dv8tion.jda.api.interactions.components.text.TextInput.Builder;
import net.dv8tion.jda.api.interactions.components.text.TextInputStyle;
import net.dv8tion.jda.api.interactions.modals.Modal;
import net.dv8tion.jda.api.requests.ErrorResponse;
Expand Down Expand Up @@ -86,7 +85,6 @@ public TransferQuestionCommand(Config config, ChatGptService chatGptService) {

@Override
public void onMessageContext(MessageContextInteractionEvent event) {

if (isInvalidForTransfer(event)) {
return;
}
Expand All @@ -96,11 +94,12 @@ public void onMessageContext(MessageContextInteractionEvent event) {
String originalChannelId = event.getTarget().getChannel().getId();
String authorId = event.getTarget().getAuthor().getId();
String mostCommonTag = tags.getFirst();
String chatGptPrompt =
"Summarize the following text into a concise title or heading not more than 4-5 words, remove quotations if any: %s"

String chatGptTitleRequest =
"Summarize the following question into a concise title or heading not more than 5 words, remove quotations if any: %s"
.formatted(originalMessage);
Optional<String> chatGptResponse = chatGptService.ask(chatGptPrompt, "");
String title = chatGptResponse.orElse(createTitle(originalMessage));
Optional<String> chatGptTitle = chatGptService.ask(chatGptTitleRequest, null);
String title = chatGptTitle.orElse(createTitle(originalMessage));
if (title.length() > TITLE_MAX_LENGTH) {
title = title.substring(0, TITLE_MAX_LENGTH);
}
Expand All @@ -112,7 +111,7 @@ public void onMessageContext(MessageContextInteractionEvent event) {
.setValue(title)
.build();

Builder modalInputBuilder =
TextInput.Builder modalInputBuilder =
TextInput.create(MODAL_INPUT_ID, "Question", TextInputStyle.PARAGRAPH)
.setRequiredRange(INPUT_MIN_LENGTH, INPUT_MAX_LENGTH)
.setPlaceholder("Contents of the question");
Expand Down
Loading