From 9be84f78c7a2369a730c9f06a1b0e8e29c35b495 Mon Sep 17 00:00:00 2001 From: Perzeuss <11357019+perzeuss@users.noreply.github.com> Date: Sat, 9 Mar 2024 17:11:43 +0100 Subject: [PATCH] fix: chat history not working --- README.md | 2 ++ src/bot.ts | 48 +++++++++++++++++++++++++++++++++++------------- 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index ae94114..75f8778 100644 --- a/README.md +++ b/README.md @@ -83,6 +83,8 @@ Set it to `user` if you want the bot to enable an own chat history for every use ### History per channel Set it to `channel` if you want the bot to enable a history for channels. The assistant will remember every message in the channe regardless from which user it came. You should use the dify variable "username" to allow the bot recognize the author of messages, otherwise the assistant will think all messages come from the same user. +Hint: If you use this, the userId of messages will no longer be the user but the server id, since dify does store conversations per user - if you share conversations accross users, you cannot pass the userid since dify would still create a unique conversation per user. + ## Contributing 🤝 diff --git a/src/bot.ts b/src/bot.ts index c243673..a627a59 100644 --- a/src/bot.ts +++ b/src/bot.ts @@ -12,12 +12,12 @@ class DiscordBot { private client: Client; private difyClient: DifyChatClient; private readonly TOKEN: string; - private readonly CACHE_MODE: string; + private readonly HISTORY_MODE: string; private readonly MAX_MESSAGE_LENGTH: number; constructor() { this.TOKEN = process.env.DISCORD_BOT_TOKEN || ''; - this.CACHE_MODE = process.env.CACHE_MODE || ''; + this.HISTORY_MODE = process.env.HISTORY_MODE || ''; this.MAX_MESSAGE_LENGTH = Number(process.env.MAX_MESSAGE_LENGTH) || 2000; if (!this.TOKEN) { throw new Error('DISCORD_BOT_TOKEN must be provided in the .env file'); @@ -49,7 +49,7 @@ class DiscordBot { if (interaction.commandName === 'chat') { await this.handleChatCommand(interaction); } else if (interaction.commandName === 'new-conversation') { - const cacheId = this.CACHE_MODE && this.CACHE_MODE === 'user' ? interaction.user.id : interaction.channelId; + const cacheId = this.HISTORY_MODE && this.HISTORY_MODE === 'user' ? interaction.user.id : interaction.channelId; conversationCache.delete(cacheId); await interaction.reply('New conversation started!'); } @@ -100,13 +100,13 @@ class DiscordBot { await interaction.deferReply({ ephemeral: true }); const message = interaction.options.get('message', true); - const cacheId = this.CACHE_MODE && this.CACHE_MODE === 'user' ? interaction.user.id : interaction.channelId; + const cacheKey = this.getCacheKey(interaction.user.id, interaction.channel?.id); try { - const difyResponse = await this.difyClient.createChatMessage({ inputs: { username: interaction.user.globalName || interaction.user.username }, query: message.value! as string, response_mode: 'blocking', conversation_id: cacheId && conversationCache.get(cacheId) || '', user: interaction.user.id }); + const difyResponse = await this.difyClient.createChatMessage({ inputs: { username: interaction.user.globalName || interaction.user.username }, query: message.value! as string, response_mode: 'blocking', conversation_id: cacheKey && conversationCache.get(cacheKey) || '', user: this.getUserId(interaction.user.id, interaction.guild?.id) }); - if (cacheId) { - conversationCache.set(cacheId, difyResponse.conversation_id); + if (cacheKey) { + conversationCache.set(cacheKey, difyResponse.conversation_id); } const messages = this.splitMessage(difyResponse.answer, { maxLength: this.MAX_MESSAGE_LENGTH }); @@ -114,7 +114,7 @@ class DiscordBot { if (index === 0) { await interaction.editReply({ content: m }); } else { - await interaction.followUp({ content: m, ephemeral: true}); + await interaction.followUp({ content: m, ephemeral: true }); } } } catch (error) { @@ -124,26 +124,48 @@ class DiscordBot { } private async handleChatMessage(message: Message) { - const cacheId = this.CACHE_MODE && this.CACHE_MODE === 'user' ? message.author.id : message.channelId; + const cacheKey = this.getCacheKey(message.author.id, message.channelId); try { message.channel.sendTyping().catch(console.error); - const difyResponse = await this.difyClient.createChatMessage({ inputs: { username: message.author.globalName || message.author.username }, query: message.content.replace(`<@${this.client.user?.id}>`, ''), response_mode: 'blocking', conversation_id: cacheId && conversationCache.get(cacheId) || '', user: message.author.id }); + const difyResponse = await this.difyClient.createChatMessage({ inputs: { username: message.author.globalName || message.author.username }, query: message.content.replace(`<@${this.client.user?.id}>`, ''), response_mode: 'blocking', conversation_id: cacheKey && conversationCache.get(cacheKey) || '', user: this.getUserId(message.author.id, message.guild?.id) }); - if (cacheId) { - conversationCache.set(cacheId, difyResponse.conversation_id); + if (cacheKey) { + conversationCache.set(cacheKey, difyResponse.conversation_id); } const messages = this.splitMessage(difyResponse.answer, { maxLength: this.MAX_MESSAGE_LENGTH }); for (const m of messages) { await message.reply(m); } - } catch (error) { + } catch (error: any) { console.error('Error sending message to Dify:', error); await message.reply('Sorry, something went wrong while generating the answer.'); } } + private getCacheKey(userId: string | undefined, channelId: string | undefined) { + switch (this.HISTORY_MODE) { + case 'user': + return userId || '' + case 'channel': + return channelId || '' + default: + return '' + } + } + + private getUserId(userId: string | undefined, serverId: string | undefined) { + switch (this.HISTORY_MODE) { + case 'user': + return userId || '' + case 'channel': + return serverId || '' + default: + return '' + } + } + splitMessage(message: string, options: { maxLength?: number, char?: string, prepend?: string, append?: string } = {}): string[] { const { maxLength = 2000, char = '\n', prepend = '', append = '' } = options; if (message.length <= maxLength) return [message];