Skip to content

Commit 8909338

Browse files
committed
Reverted a lot of the discordbot parallelism and emoji reaction pre-prompts after hitting rate limits.
Removed some unused code.
1 parent d8f4088 commit 8909338

File tree

3 files changed

+74
-158
lines changed

3 files changed

+74
-158
lines changed

Chat/Discord/DiscordBot.cs

Lines changed: 60 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
using Microsoft.Extensions.Hosting;
1010
using OpenAI.GPT3.ObjectModels;
1111
using OpenAI.GPT3.ObjectModels.RequestModels;
12-
using Org.BouncyCastle.Asn1.X509;
1312

1413
namespace GPT.CLI.Chat.Discord;
1514

@@ -34,12 +33,14 @@ public record ChannelOptions
3433
}
3534

3635

36+
3737
private readonly DiscordSocketClient _client;
3838
private readonly IConfiguration _configuration;
3939
private readonly OpenAILogic _openAILogic;
4040
private readonly GPTParameters _defaultParameters;
4141
private readonly ConcurrentDictionary<ulong, ChannelState> _channelBots = new();
4242

43+
4344
public DiscordBot(DiscordSocketClient client, IConfiguration configuration, OpenAILogic openAILogic, GPTParameters defaultParameters)
4445
{
4546
_client = client;
@@ -63,6 +64,7 @@ public async Task StartAsync(CancellationToken cancellationToken)
6364
// Load state from discordState.json
6465
await LoadState();
6566

67+
// Login and start
6668
await _client.LoginAsync(TokenType.Bot, token);
6769
await _client.StartAsync();
6870

@@ -73,15 +75,7 @@ public async Task StartAsync(CancellationToken cancellationToken)
7375

7476

7577
// Message receiver is going to run in parallel
76-
_client.MessageReceived += message =>
77-
{
78-
#pragma warning disable CS4014
79-
return Task.Run(async () =>
80-
#pragma warning restore CS4014
81-
{
82-
await HandleMessageReceivedAsync(message);
83-
}, cancellationToken);
84-
};
78+
_client.MessageReceived += HandleMessageReceivedAsync;
8579

8680
_client.MessageUpdated += async (oldMessage, newMessage, channel) =>
8781
{
@@ -96,25 +90,17 @@ public async Task StartAsync(CancellationToken cancellationToken)
9690

9791

9892

99-
_client.Ready += () =>
93+
_client.Ready += async () =>
10094
{
101-
Console.WriteLine("Client is ready!");
102-
return Task.CompletedTask;
95+
await Console.Out.WriteLineAsync("Client is ready!");
10396
};
10497

105-
_client.MessageCommandExecuted += (command) =>
98+
_client.MessageCommandExecuted += async (command) =>
10699
{
107-
Console.WriteLine($"Command {command.CommandName} executed with result {command.Data.Message.Content}");
108-
return Task.CompletedTask;
100+
await Console.Out.WriteLineAsync($"Command {command.CommandName} executed with result {command.Data.Message.Content}");
109101
};
110102
}
111103

112-
private async Task AddStandardReactions(IMessage message)
113-
{
114-
await message.AddReactionAsync(new Emoji("📌"));
115-
await message.AddReactionAsync(new Emoji("🔄"));
116-
}
117-
118104
private async Task HandleReactionAsync(Cacheable<IUserMessage, ulong> userMessage, Cacheable<IMessageChannel, ulong> messageChannel, SocketReaction reaction)
119105
{
120106
if (reaction.UserId == _client.CurrentUser.Id)
@@ -125,6 +111,7 @@ private async Task HandleReactionAsync(Cacheable<IUserMessage, ulong> userMessag
125111
var message = await userMessage.GetOrDownloadAsync();
126112
var channel = await messageChannel.GetOrDownloadAsync();
127113

114+
128115
switch (reaction.Emote.Name)
129116
{
130117
case "📌":
@@ -135,28 +122,30 @@ private async Task HandleReactionAsync(Cacheable<IUserMessage, ulong> userMessag
135122
var chatBot = channelState.Chat;
136123
chatBot.AddInstruction(new ChatMessage(StaticValues.ChatMessageRoles.User, message.Content));
137124

125+
138126
using var typingState = channel.EnterTypingState();
139127
await message.RemoveReactionAsync(reaction.Emote, reaction.UserId);
140128
await message.ReplyAsync("Instruction added.");
141-
142-
Console.WriteLine(
143-
$"{reaction.User.Value.Username} reacted with an arrow up. Message promoted to instruction: {message.Content}");
144129
}
130+
145131
break;
146132
}
147133
case "🔄":
148134
{
149-
// remove the emoji
150-
await message.RemoveReactionAsync(reaction.Emote, reaction.UserId);
135+
// If the message is from the bot, ignore it. These aren't prompts.
136+
if (message.Author.Id == _client.CurrentUser.Id)
137+
{
138+
return;
139+
}
151140

152-
await message.ReplyAsync("Using as a prompt.");
141+
// remove the emoji
142+
await message.RemoveReactionAsync(reaction.Emote, reaction.User.Value);
153143

154144
// Replay the message as a new message
155-
#pragma warning disable CS4014
156-
Task.Run(async () => await HandleMessageReceivedAsync(message, reaction.Emote));
157-
#pragma warning restore CS4014
145+
await HandleMessageReceivedAsync(message as SocketMessage);
158146
break;
159147
}
148+
160149
}
161150
}
162151

@@ -222,7 +211,6 @@ private async Task<ChannelState> ReadAsync(ulong channelId, Stream stream)
222211
try
223212
{
224213
var str = await new StreamReader(stream).ReadToEndAsync();
225-
await Console.Out.WriteLineAsync($"State read for {channelId}: {str}");
226214
// Deserialize channelState from stream
227215
var channelState = JsonSerializer.Deserialize<ChannelState>(str);
228216

@@ -252,18 +240,16 @@ private async Task LogAsync(LogMessage log)
252240
await Console.Out.WriteLineAsync(log.ToString());
253241
}
254242

255-
private async Task HandleMessageReceivedAsync(IMessage message, IEmote emote = null)
243+
private async Task HandleMessageReceivedAsync(SocketMessage message)
256244
{
257-
if (message.Author.Id == _client.CurrentUser.Id && emote == null)
245+
if (message == null || message.Author.Id == _client.CurrentUser.Id)
258246
return;
259247

260248
// Handle the received message here
261249
// ...
262-
if (!_channelBots.TryGetValue(message.Channel.Id, out var channel))
263-
{
264-
channel = InitializeChannel(message.Channel.Id);
265-
}
266-
else if (channel.Chat.State.PrimeDirectives.Count != _defaultPrimeDirective.Count || channel.Chat.State.PrimeDirectives[0].Content != _defaultPrimeDirective[0].Content)
250+
var channel = _channelBots.GetOrAdd(message.Channel.Id, InitializeChannel);
251+
252+
if (channel.Chat.State.PrimeDirectives.Count != _defaultPrimeDirective.Count || channel.Chat.State.PrimeDirectives[0].Content != _defaultPrimeDirective[0].Content)
267253
{
268254
channel.Chat.State.PrimeDirectives = PrimeDirective.ToList();
269255
}
@@ -274,74 +260,58 @@ private async Task HandleMessageReceivedAsync(IMessage message, IEmote emote = n
274260
if (message.Content.StartsWith("!ignore"))
275261
return;
276262

277-
await message.AddReactionAsync(new Emoji("🤔"));
278-
279-
await AddStandardReactions(message);
280263

281264
// Add this message as a chat log
282265
await channel.Chat.AddMessage(new ChatMessage(StaticValues.ChatMessageRoles.User, $"<{message.Author.Username}> {message.Content}"));
283266

284267
if (!channel.Options.Muted)
285268
{
286-
try
269+
using var typingState = message.Channel.EnterTypingState();
270+
// Get the response from the bot
271+
var responses = channel.Chat.GetResponseAsync();
272+
// Add the response as a chat
273+
274+
var sb = new StringBuilder();
275+
// Send the response to the channel
276+
await foreach (var response in responses)
287277
{
288-
289-
// Get the response from the bot
290-
var responses = channel.Chat.GetResponseAsync();
291-
// Add the response as a chat
292-
293-
using var typingState = message.Channel.EnterTypingState();
294-
295-
var sb = new StringBuilder();
296-
// Send the response to the channel
297-
await foreach (var response in responses)
278+
if (response.Successful)
298279
{
299-
if (response.Successful)
280+
var content = response.Choices.FirstOrDefault()?.Message.Content;
281+
if (content is not null)
300282
{
301-
var content = response?.Choices?.FirstOrDefault()?.Message.Content;
302-
if (content is not null)
303-
{
304-
sb.Append(content);
305-
}
306-
}
307-
else
308-
{
309-
await Console.Out.WriteLineAsync(
310-
$"Error code {response.Error?.Code}: {response.Error?.Message}");
283+
sb.Append(content);
311284
}
312285
}
313-
314-
int chunkSize = 2000;
315-
int currentPosition = 0;
316-
317-
while (currentPosition < sb.Length)
286+
else
318287
{
319-
var size = Math.Min(chunkSize, sb.Length - currentPosition);
320-
var chunk = sb.ToString(currentPosition, size);
321-
currentPosition += size;
288+
await Console.Out.WriteLineAsync(
289+
$"Error code {response.Error?.Code}: {response.Error?.Message}");
290+
}
291+
}
322292

323-
var responseMessage = new ChatMessage(StaticValues.ChatMessageRoles.Assistant, chunk);
293+
int chunkSize = 2000;
294+
int currentPosition = 0;
324295

325-
await channel.Chat.AddMessage(responseMessage);
326-
// Convert message to SocketMessage
327-
IMessage newMessage;
296+
while (currentPosition < sb.Length)
297+
{
298+
var size = Math.Min(chunkSize, sb.Length - currentPosition);
299+
var chunk = sb.ToString(currentPosition, size);
300+
currentPosition += size;
328301

329-
if (message is IUserMessage userMessage)
330-
{
331-
newMessage = await userMessage.ReplyAsync(responseMessage.Content);
332-
}
333-
else
334-
{
302+
var responseMessage = new ChatMessage(StaticValues.ChatMessageRoles.Assistant, chunk);
335303

336-
newMessage = await message.Channel.SendMessageAsync(responseMessage.Content);
337-
}
304+
await channel.Chat.AddMessage(responseMessage);
305+
// Convert message to SocketMessage
338306

339-
await AddStandardReactions(newMessage);
307+
if (message is IUserMessage userMessage)
308+
{
309+
_ = await userMessage.ReplyAsync(responseMessage.Content);
310+
}
311+
else
312+
{
313+
_ = await message.Channel.SendMessageAsync(responseMessage.Content);
340314
}
341-
}
342-
finally
343-
{
344-
await message.RemoveReactionAsync(new Emoji("🤔"), _client.CurrentUser);
345315
}
346316
}
347317

@@ -354,7 +324,7 @@ await Console.Out.WriteLineAsync(
354324
(StaticValues.ChatMessageRoles.System,
355325
"This is the Prime Directive: This is a chat bot running in [GPT-CLI](https://github.com/kainazzzo/GPT-CLI). Answer questions and" +
356326
" provide responses in Discord message formatting. Encourage users to add instructions with /gptcli or by using the :up_arrow:" +
357-
" emoji reaction on any message. Instructions are like 'sticky' chat messages that provide upfront context to the bot.")
327+
" emoji reaction on any message. Instructions are like 'sticky' chat messages that provide upfront context to the bot. The the 📌 emoji reaction is for pinning a message to instructions. The 🔄 emoji reaction is for replaying a message as a new prompt.")
358328
};
359329

360330
private IEnumerable<ChatMessage> PrimeDirective => _defaultPrimeDirective;

Program.cs

Lines changed: 13 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.CommandLine;
1+
using System.Collections.Concurrent;
2+
using System.CommandLine;
23
using System.CommandLine.Builder;
34
using System.CommandLine.Parsing;
45
using System.Text;
@@ -144,6 +145,7 @@ static async Task Main(string[] args)
144145
ConfigureServices(services, binder, mode);
145146

146147
await using var serviceProvider = services.BuildServiceProvider();
148+
147149

148150
// get a OpenAILogic instance
149151
var openAILogic = serviceProvider.GetService<OpenAILogic>();
@@ -387,18 +389,18 @@ private static void ConfigureServices(IServiceCollection services, GPTParameters
387389
settings.BaseDomain = gptParameters.BaseDomain;
388390
});
389391
services.AddSingleton<OpenAILogic>();
390-
services.AddSingleton(_ =>
391-
{
392-
var config = new DiscordSocketConfig
393-
{
394-
GatewayIntents = GatewayIntents.Guilds | GatewayIntents.GuildMessages | GatewayIntents.GuildMembers |
395-
GatewayIntents.MessageContent | GatewayIntents.DirectMessages | GatewayIntents.DirectMessageReactions |
396-
GatewayIntents.GuildMessageReactions | GatewayIntents.GuildEmojis,
397-
MessageCacheSize = 100
398-
};
399392

400-
return new DiscordSocketClient(config);
393+
services.AddSingleton(_ => new DiscordSocketConfig
394+
{
395+
GatewayIntents = GatewayIntents.Guilds | GatewayIntents.GuildMessages | GatewayIntents.GuildMembers |
396+
GatewayIntents.MessageContent | GatewayIntents.DirectMessages |
397+
GatewayIntents.DirectMessageReactions |
398+
GatewayIntents.GuildMessageReactions | GatewayIntents.GuildEmojis,
399+
MessageCacheSize = 10
401400
});
401+
402+
services.AddScoped<DiscordSocketClient>();
403+
402404
services.AddSingleton<DiscordBot>();
403405
services.AddSingleton(_ => gptParameters);
404406

@@ -445,61 +447,4 @@ private static void ConfigureServices(IServiceCollection services, GPTParameters
445447
}
446448

447449
public static IConfigurationRoot Configuration { get; set; }
448-
449-
private static bool VerifySignature(string publicKey, string signature, string timestamp, string body)
450-
{
451-
byte[] publicKeyBytes = StringToByteArray(publicKey);
452-
byte[] signatureBytes = StringToByteArray(signature);
453-
byte[] timestampBytes = Encoding.UTF8.GetBytes(timestamp);
454-
byte[] bodyBytes = Encoding.UTF8.GetBytes(body);
455-
456-
var pubKeyParam = new Ed25519PublicKeyParameters(publicKeyBytes, 0);
457-
var verifier = SignerUtilities.GetSigner("Ed25519");
458-
459-
verifier.Init(false, pubKeyParam);
460-
461-
byte[] combinedBytes = new byte[timestampBytes.Length + bodyBytes.Length];
462-
Buffer.BlockCopy(timestampBytes, 0, combinedBytes, 0, timestampBytes.Length);
463-
Buffer.BlockCopy(bodyBytes, 0, combinedBytes, timestampBytes.Length, bodyBytes.Length);
464-
465-
verifier.BlockUpdate(combinedBytes, 0, combinedBytes.Length);
466-
467-
return verifier.VerifySignature(signatureBytes);
468-
469-
470-
}
471-
private static byte[] StringToByteArray(string hex)
472-
{
473-
int length = hex.Length;
474-
byte[] bytes = new byte[length / 2];
475-
for (int i = 0; i < length; i += 2)
476-
{
477-
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
478-
}
479-
return bytes;
480-
}
481-
482-
483-
public class InteractionPayload
484-
{
485-
public string ApplicationId { get; set; }
486-
public string Id { get; set; }
487-
public string Token { get; set; }
488-
public int Type { get; set; }
489-
public InteractionUser User { get; set; }
490-
public int Version { get; set; }
491-
}
492-
493-
public class InteractionUser
494-
{
495-
public string Avatar { get; set; }
496-
public object AvatarDecoration { get; set; }
497-
public string Discriminator { get; set; }
498-
public object DisplayName { get; set; }
499-
public object GlobalName { get; set; }
500-
public string Id { get; set; }
501-
public int PublicFlags { get; set; }
502-
public string Username { get; set; }
503-
}
504-
505450
}

test.bat

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
git log -1 --pretty=%B | xargs -I % dotnet publish gpt.csproj -c Release -r win-x64 -o c:\bin\ --self-contained true -p:PublishSingleFile=true -p:VersionSuffix=%

0 commit comments

Comments
 (0)