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

AI response should be in embed #1046

Merged
merged 4 commits into from
Mar 12, 2024
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 @@ -162,7 +162,7 @@ public static Collection<Feature> createFeatures(JDA jda, Database database, Con
features.add(new HelpThreadCommand(config, helpSystemHelper));
features.add(new ReportCommand(config));
features.add(new BookmarksCommand(bookmarksSystem));
features.add(new ChatGptCommand(chatGptService));
features.add(new ChatGptCommand(chatGptService, helpSystemHelper));
features.add(new JShellCommand(jshellEval));

FeatureBlacklist<Class<?>> blacklist = blacklistConfig.normal();
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import net.dv8tion.jda.api.entities.MessageEmbed;
import net.dv8tion.jda.api.entities.SelfUser;
import net.dv8tion.jda.api.events.interaction.ModalInteractionEvent;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.interactions.components.Modal;
Expand All @@ -10,6 +12,7 @@

import org.togetherjava.tjbot.features.CommandVisibility;
import org.togetherjava.tjbot.features.SlashCommandAdapter;
import org.togetherjava.tjbot.features.help.HelpSystemHelper;

import java.time.Duration;
import java.time.Instant;
Expand All @@ -28,6 +31,7 @@ public final class ChatGptCommand extends SlashCommandAdapter {
private static final int MIN_MESSAGE_INPUT_LENGTH = 4;
private static final Duration COMMAND_COOLDOWN = Duration.of(10, ChronoUnit.SECONDS);
private final ChatGptService chatGptService;
private final HelpSystemHelper helper;

private final Cache<String, Instant> userIdToAskedAtCache =
Caffeine.newBuilder().maximumSize(1_000).expireAfterWrite(COMMAND_COOLDOWN).build();
Expand All @@ -36,11 +40,13 @@ public final class ChatGptCommand extends SlashCommandAdapter {
* Creates an instance of the chatgpt command.
*
* @param chatGptService ChatGptService - Needed to make calls to ChatGPT API
* @param helper HelpSystemHelper - Needed to generate response embed for prompt
*/
public ChatGptCommand(ChatGptService chatGptService) {
public ChatGptCommand(ChatGptService chatGptService, HelpSystemHelper helper) {
super(COMMAND_NAME, "Ask the ChatGPT AI a question!", CommandVisibility.GUILD);

this.chatGptService = chatGptService;
this.helper = helper;
}

@Override
Expand Down Expand Up @@ -75,20 +81,23 @@ public void onModalSubmitted(ModalInteractionEvent event, List<String> args) {
event.deferReply().queue();

String context = "";
Optional<String[]> optional =
chatGptService.ask(event.getValue(QUESTION_INPUT).getAsString(), context);
String question = event.getValue(QUESTION_INPUT).getAsString();

Optional<String> optional = chatGptService.ask(question, context);
if (optional.isPresent()) {
userIdToAskedAtCache.put(event.getMember().getId(), Instant.now());
}

String[] errorResponse = {"""
String errorResponse = """
An error has occurred while trying to communicate with ChatGPT.
Please try again later.
"""};
""";

String[] response = optional.orElse(errorResponse);
for (String message : response) {
event.getHook().sendMessage(message).queue();
}
String response = optional.orElse(errorResponse);
SelfUser selfUser = event.getJDA().getSelfUser();

MessageEmbed responseEmbed = helper.generateGptResponseEmbed(response, selfUser, question);

event.getHook().sendMessageEmbeds(responseEmbed).queue();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,11 @@ public ChatGptService(Config config) {
* @param question The question being asked of ChatGPT. Max is {@value MAX_TOKENS} tokens.
* @param context The category of asked question, to set the context(eg. Java, Database, Other
* etc).
* @return partitioned response from ChatGPT as a String array.
* @return response from ChatGPT as a String.
* @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, String context) {
if (isDisabled) {
return Optional.empty();
}
Expand Down Expand Up @@ -121,7 +121,7 @@ public Optional<String[]> ask(String question, String context) {
return Optional.empty();
}

return Optional.of(AIResponseParser.parse(response));
return Optional.of(response);
} catch (OpenAiHttpException openAiHttpException) {
logger.warn(
"There was an error using the OpenAI API: {} Code: {} Type: {} Status Code: {}",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.togetherjava.tjbot.features.help;

import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.entities.*;
import net.dv8tion.jda.api.entities.channel.attribute.IThreadContainer;
import net.dv8tion.jda.api.entities.channel.concrete.ForumChannel;
Expand All @@ -9,7 +10,6 @@
import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel;
import net.dv8tion.jda.api.interactions.components.buttons.Button;
import net.dv8tion.jda.api.requests.RestAction;
import net.dv8tion.jda.api.requests.restaction.MessageCreateAction;
import net.dv8tion.jda.internal.requests.CompletedRestAction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -33,7 +33,6 @@
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
Expand Down Expand Up @@ -117,7 +116,7 @@ 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);
Expand All @@ -130,11 +129,12 @@ RestAction<Message> constructChatGptAttempt(ThreadChannel threadChannel,

String context = matchingTag.getName();
chatGPTAnswer = chatGptService.ask(question, context);

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

List<String> ids = new CopyOnWriteArrayList<>();
StringBuilder idForDismissButton = new StringBuilder();
RestAction<Message> message =
mentionGuildSlashCommand(threadChannel.getGuild(), ChatGptCommand.COMMAND_NAME)
.map("""
Expand All @@ -143,27 +143,43 @@ RestAction<Message> constructChatGptAttempt(ThreadChannel threadChannel,
%s.
"""::formatted)
.flatMap(threadChannel::sendMessage)
.onSuccess(m -> ids.add(m.getId()));
String[] answers = chatGPTAnswer.orElseThrow();

for (int i = 0; i < answers.length; i++) {
MessageCreateAction answer = threadChannel.sendMessage(answers[i]);
.onSuccess(m -> idForDismissButton.append(m.getId()));

if (i == answers.length - 1) {
message = message.flatMap(any -> answer
.addActionRow(generateDismissButton(componentIdInteractor, ids)));
continue;
}
String answer = chatGPTAnswer.orElseThrow();
SelfUser selfUser = threadChannel.getJDA().getSelfUser();

message = message.flatMap(ignored -> answer.onSuccess(m -> ids.add(m.getId())));
int responseCharLimit = MessageEmbed.DESCRIPTION_MAX_LENGTH;
if (answer.length() > responseCharLimit) {
answer = answer.substring(0, responseCharLimit);
}

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

public MessageEmbed generateGptResponseEmbed(String answer, SelfUser selfUser, String title) {
String responseByGptFooter = "- AI generated response";

int embedTitleLimit = MessageEmbed.TITLE_MAX_LENGTH;
String capitalizedTitle = Character.toUpperCase(title.charAt(0)) + title.substring(1);

String titleForEmbed = capitalizedTitle.length() > embedTitleLimit
? capitalizedTitle.substring(0, embedTitleLimit)
: capitalizedTitle;

return new EmbedBuilder()
.setAuthor(selfUser.getName(), null, selfUser.getEffectiveAvatarUrl())
.setTitle(titleForEmbed)
.setDescription(answer)
.setColor(Color.pink)
.setFooter(responseByGptFooter)
.build();
}

private Button generateDismissButton(ComponentIdInteractor componentIdInteractor,
List<String> ids) {
String buttonId = componentIdInteractor.generateComponentId(ids.toArray(String[]::new));
private Button generateDismissButton(ComponentIdInteractor componentIdInteractor, String id) {
String buttonId = componentIdInteractor.generateComponentId(id);
return Button.danger(buttonId, "Dismiss");
}

Expand Down

This file was deleted.

Loading