Skip to content

Commit 06de64a

Browse files
committed
Resolve merge conflicts
Let's merge this because I am getting tired of resolving conflicts for people to not review.
2 parents d60aa12 + 938c6c1 commit 06de64a

File tree

13 files changed

+758
-81
lines changed

13 files changed

+758
-81
lines changed

CLA.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,6 @@ IF THE DISCLAIMER AND DAMAGE WAIVER MENTIONED IN SECTION 5. AND SECTION 6. CANNO
115115

116116
### Us
117117

118-
Name: Daniel Tischner (aka Zabuzard, acting on behalf of Together Java)
119-
120118
Organization: https://github.com/Together-Java
121119

122120
Contact: https://discord.com/invite/XXFUXzK

application/build.gradle

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ dependencies {
5757

5858
implementation 'io.mikael:urlbuilder:2.0.9'
5959

60-
implementation 'org.jsoup:jsoup:1.21.1'
60+
implementation 'org.jsoup:jsoup:1.22.1'
6161

6262
implementation 'org.scilab.forge:jlatexmath:1.0.7'
6363
implementation 'org.scilab.forge:jlatexmath-font-greek:1.0.7'
@@ -86,8 +86,7 @@ dependencies {
8686
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
8787
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitVersion"
8888

89-
implementation "com.theokanning.openai-gpt3-java:api:$chatGPTVersion"
90-
implementation "com.theokanning.openai-gpt3-java:service:$chatGPTVersion"
89+
implementation "com.openai:openai-java:$chatGPTVersion"
9190
}
9291

9392
application {

application/src/main/java/org/togetherjava/tjbot/features/Features.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import org.togetherjava.tjbot.features.mathcommands.TeXCommand;
4040
import org.togetherjava.tjbot.features.mathcommands.wolframalpha.WolframAlphaCommand;
4141
import org.togetherjava.tjbot.features.mediaonly.MediaOnlyChannelListener;
42+
import org.togetherjava.tjbot.features.messages.MessageCommand;
4243
import org.togetherjava.tjbot.features.moderation.BanCommand;
4344
import org.togetherjava.tjbot.features.moderation.KickCommand;
4445
import org.togetherjava.tjbot.features.moderation.ModerationActionsStore;
@@ -204,6 +205,7 @@ public static Collection<Feature> createFeatures(JDA jda, Database database, Con
204205
features.add(new BookmarksCommand(bookmarksSystem));
205206
features.add(new ChatGptCommand(chatGptService, helpSystemHelper));
206207
features.add(new JShellCommand(jshellEval));
208+
features.add(new MessageCommand());
207209
features.add(new CreateRoleApplicationCommand(config));
208210

209211
FeatureBlacklist<Class<?>> blacklist = blacklistConfig.normal();
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package org.togetherjava.tjbot.features;
2+
3+
import net.dv8tion.jda.api.events.guild.voice.GuildVoiceDeafenEvent;
4+
import net.dv8tion.jda.api.events.guild.voice.GuildVoiceMuteEvent;
5+
import net.dv8tion.jda.api.events.guild.voice.GuildVoiceStreamEvent;
6+
import net.dv8tion.jda.api.events.guild.voice.GuildVoiceUpdateEvent;
7+
import net.dv8tion.jda.api.events.guild.voice.GuildVoiceVideoEvent;
8+
9+
import java.util.regex.Pattern;
10+
11+
/**
12+
* Receives incoming Discord guild events from voice channels matching a given pattern.
13+
* <p>
14+
* All voice receivers have to implement this interface. For convenience, there is a
15+
* {@link VoiceReceiverAdapter} available that implemented most methods already. A new receiver can
16+
* then be registered by adding it to {@link Features}.
17+
* <p>
18+
* <p>
19+
* After registration, the system will notify a receiver whenever a new event was sent or an
20+
* existing event was updated in any channel matching the {@link #getChannelNamePattern()} the bot
21+
* is added to.
22+
*/
23+
public interface VoiceReceiver extends Feature {
24+
/**
25+
* Retrieves the pattern matching the names of channels of which this receiver is interested in
26+
* receiving events from. Called by the core system once during the startup in order to register
27+
* the receiver accordingly.
28+
* <p>
29+
* Changes on the pattern returned by this method afterwards will not be picked up.
30+
*
31+
* @return the pattern matching the names of relevant channels
32+
*/
33+
Pattern getChannelNamePattern();
34+
35+
/**
36+
* Triggered by the core system whenever a member joined, left or moved voice channels.
37+
*
38+
* @param event the event that triggered this
39+
*/
40+
void onVoiceUpdate(GuildVoiceUpdateEvent event);
41+
42+
/**
43+
* Triggered by the core system whenever a member toggled their camera in a voice channel.
44+
*
45+
* @param event the event that triggered this
46+
*/
47+
void onVideoToggle(GuildVoiceVideoEvent event);
48+
49+
/**
50+
* Triggered by the core system whenever a member started or stopped a stream.
51+
*
52+
* @param event the event that triggered this
53+
*/
54+
void onStreamToggle(GuildVoiceStreamEvent event);
55+
56+
/**
57+
* Triggered by the core system whenever a member toggled their mute status.
58+
*
59+
* @param event the event that triggered this
60+
*/
61+
void onMuteToggle(GuildVoiceMuteEvent event);
62+
63+
/**
64+
* Triggered by the core system whenever a member toggled their deafened status.
65+
*
66+
* @param event the event that triggered this
67+
*/
68+
void onDeafenToggle(GuildVoiceDeafenEvent event);
69+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package org.togetherjava.tjbot.features;
2+
3+
import net.dv8tion.jda.api.events.guild.voice.GuildVoiceDeafenEvent;
4+
import net.dv8tion.jda.api.events.guild.voice.GuildVoiceMuteEvent;
5+
import net.dv8tion.jda.api.events.guild.voice.GuildVoiceStreamEvent;
6+
import net.dv8tion.jda.api.events.guild.voice.GuildVoiceUpdateEvent;
7+
import net.dv8tion.jda.api.events.guild.voice.GuildVoiceVideoEvent;
8+
9+
import java.util.regex.Pattern;
10+
11+
/**
12+
* Adapter implementation of a {@link VoiceReceiver}. A new receiver can then be registered by
13+
* adding it to {@link Features}.
14+
* <p>
15+
* {@link #onVoiceUpdate(GuildVoiceUpdateEvent)} like the other provided methods can be overridden
16+
* if desired. The default implementation is empty, the adapter will not react to such events.
17+
*/
18+
public class VoiceReceiverAdapter implements VoiceReceiver {
19+
20+
private final Pattern channelNamePattern;
21+
22+
protected VoiceReceiverAdapter() {
23+
this(Pattern.compile(".*"));
24+
}
25+
26+
protected VoiceReceiverAdapter(Pattern channelNamePattern) {
27+
this.channelNamePattern = channelNamePattern;
28+
}
29+
30+
@Override
31+
public Pattern getChannelNamePattern() {
32+
return channelNamePattern;
33+
}
34+
35+
@Override
36+
public void onVoiceUpdate(GuildVoiceUpdateEvent event) {
37+
// Adapter does not react by default, subclasses may change this behavior
38+
}
39+
40+
@Override
41+
public void onVideoToggle(GuildVoiceVideoEvent event) {
42+
// Adapter does not react by default, subclasses may change this behavior
43+
}
44+
45+
@Override
46+
public void onStreamToggle(GuildVoiceStreamEvent event) {
47+
// Adapter does not react by default, subclasses may change this behavior
48+
}
49+
50+
@Override
51+
public void onMuteToggle(GuildVoiceMuteEvent event) {
52+
// Adapter does not react by default, subclasses may change this behavior
53+
}
54+
55+
@Override
56+
public void onDeafenToggle(GuildVoiceDeafenEvent event) {
57+
// Adapter does not react by default, subclasses may change this behavior
58+
}
59+
}

application/src/main/java/org/togetherjava/tjbot/features/chatgpt/ChatGptService.java

Lines changed: 35 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
package org.togetherjava.tjbot.features.chatgpt;
22

3-
import com.theokanning.openai.OpenAiHttpException;
4-
import com.theokanning.openai.completion.chat.ChatCompletionRequest;
5-
import com.theokanning.openai.completion.chat.ChatMessage;
6-
import com.theokanning.openai.completion.chat.ChatMessageRole;
7-
import com.theokanning.openai.service.OpenAiService;
3+
import com.openai.client.OpenAIClient;
4+
import com.openai.client.okhttp.OpenAIOkHttpClient;
5+
import com.openai.models.ChatModel;
6+
import com.openai.models.responses.Response;
7+
import com.openai.models.responses.ResponseCreateParams;
8+
import com.openai.models.responses.ResponseOutputText;
89
import org.slf4j.Logger;
910
import org.slf4j.LoggerFactory;
1011

@@ -13,8 +14,8 @@
1314
import javax.annotation.Nullable;
1415

1516
import java.time.Duration;
16-
import java.util.List;
1717
import java.util.Optional;
18+
import java.util.stream.Collectors;
1819

1920
/**
2021
* Service used to communicate to OpenAI API to generate responses.
@@ -26,30 +27,8 @@ public class ChatGptService {
2627
/** The maximum number of tokens allowed for the generated answer. */
2728
private static final int MAX_TOKENS = 3_000;
2829

29-
/**
30-
* This parameter reduces the likelihood of the AI repeating itself. A higher frequency penalty
31-
* makes the model less likely to repeat the same lines verbatim. It helps in generating more
32-
* diverse and varied responses.
33-
*/
34-
private static final double FREQUENCY_PENALTY = 0.5;
35-
36-
/**
37-
* This parameter controls the randomness of the AI's responses. A higher temperature results in
38-
* more varied, unpredictable, and creative responses. Conversely, a lower temperature makes the
39-
* model's responses more deterministic and conservative.
40-
*/
41-
private static final double TEMPERATURE = 0.8;
42-
43-
/**
44-
* n: This parameter specifies the number of responses to generate for each prompt. If n is more
45-
* than 1, the AI will generate multiple different responses to the same prompt, each one being
46-
* a separate iteration based on the input.
47-
*/
48-
private static final int MAX_NUMBER_OF_RESPONSES = 1;
49-
private static final String AI_MODEL = "gpt-3.5-turbo";
50-
5130
private boolean isDisabled = false;
52-
private OpenAiService openAiService;
31+
private OpenAIClient openAIClient;
5332

5433
/**
5534
* Creates instance of ChatGPTService
@@ -63,23 +42,7 @@ public ChatGptService(Config config) {
6342
isDisabled = true;
6443
return;
6544
}
66-
67-
openAiService = new OpenAiService(apiKey, TIMEOUT);
68-
69-
ChatMessage setupMessage = new ChatMessage(ChatMessageRole.SYSTEM.value(), """
70-
For code supplied for review, refer to the old code supplied rather than
71-
rewriting the code. DON'T supply a corrected version of the code.\s""");
72-
ChatCompletionRequest systemSetupRequest = ChatCompletionRequest.builder()
73-
.model(AI_MODEL)
74-
.messages(List.of(setupMessage))
75-
.frequencyPenalty(FREQUENCY_PENALTY)
76-
.temperature(TEMPERATURE)
77-
.maxTokens(50)
78-
.n(MAX_NUMBER_OF_RESPONSES)
79-
.build();
80-
81-
// Sending the system setup message to ChatGPT.
82-
openAiService.createChatCompletion(systemSetupRequest);
45+
openAIClient = OpenAIOkHttpClient.builder().apiKey(apiKey).timeout(TIMEOUT).build();
8346
}
8447

8548
/**
@@ -98,32 +61,35 @@ public Optional<String> ask(String question, @Nullable String context) {
9861
}
9962

10063
String contextText = context == null ? "" : ", Context: %s.".formatted(context);
101-
String fullQuestion = "(KEEP IT CONCISE, NOT MORE THAN 280 WORDS%s) - %s"
102-
.formatted(contextText, question);
103-
104-
ChatMessage chatMessage = new ChatMessage(ChatMessageRole.USER.value(), fullQuestion);
105-
ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest.builder()
106-
.model(AI_MODEL)
107-
.messages(List.of(chatMessage))
108-
.frequencyPenalty(FREQUENCY_PENALTY)
109-
.temperature(TEMPERATURE)
110-
.maxTokens(MAX_TOKENS)
111-
.n(MAX_NUMBER_OF_RESPONSES)
112-
.build();
113-
logger.debug("ChatGpt Request: {}", fullQuestion);
64+
String inputPrompt = """
65+
For code supplied for review, refer to the old code supplied rather than
66+
rewriting the code. DON'T supply a corrected version of the code.
67+
68+
KEEP IT CONCISE, NOT MORE THAN 280 WORDS
69+
70+
%s
71+
Question: %s
72+
""".formatted(contextText, question);
73+
74+
logger.debug("ChatGpt request: {}", inputPrompt);
11475

11576
String response = null;
11677
try {
117-
response = openAiService.createChatCompletion(chatCompletionRequest)
118-
.getChoices()
119-
.getFirst()
120-
.getMessage()
121-
.getContent();
122-
} catch (OpenAiHttpException openAiHttpException) {
123-
logger.warn(
124-
"There was an error using the OpenAI API: {} Code: {} Type: {} Status Code: {}",
125-
openAiHttpException.getMessage(), openAiHttpException.code,
126-
openAiHttpException.type, openAiHttpException.statusCode);
78+
ResponseCreateParams params = ResponseCreateParams.builder()
79+
.model(ChatModel.GPT_5_NANO)
80+
.input(inputPrompt)
81+
.maxOutputTokens(MAX_TOKENS)
82+
.build();
83+
84+
Response chatGptResponse = openAIClient.responses().create(params);
85+
86+
response = chatGptResponse.output()
87+
.stream()
88+
.flatMap(item -> item.message().stream())
89+
.flatMap(message -> message.content().stream())
90+
.flatMap(content -> content.outputText().stream())
91+
.map(ResponseOutputText::text)
92+
.collect(Collectors.joining("\n"));
12793
} catch (RuntimeException runtimeException) {
12894
logger.warn("There was an error using the OpenAI API: {}",
12995
runtimeException.getMessage());

0 commit comments

Comments
 (0)