From c1599e4f34390bd979cdb422777f17f2067c8484 Mon Sep 17 00:00:00 2001 From: ikechan8370 Date: Sun, 16 Apr 2023 19:12:56 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81claude=E5=8D=95?= =?UTF-8?q?=E4=BA=BA=E5=AF=B9=E8=AF=9D=EF=BC=9B=E6=B3=A8=E6=84=8F=EF=BC=9A?= =?UTF-8?q?=E9=9C=80=E8=A6=81=E9=87=8D=E6=96=B0=E8=AE=BE=E7=BD=AEslack?= =?UTF-8?q?=E6=9D=83=E9=99=90=E5=92=8C=E9=85=8D=E7=BD=AE=E6=8F=92=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/chat.js | 7 +- guoba.support.js | 6 +- utils/config.js | 3 +- utils/slack/slackClient.js | 132 +++++++++++++++++++++++++++++-------- 4 files changed, 115 insertions(+), 33 deletions(-) diff --git a/apps/chat.js b/apps/chat.js index e873464..72c442b 100644 --- a/apps/chat.js +++ b/apps/chat.js @@ -216,7 +216,8 @@ export class chatgpt extends plugin { // slackChannelId: Config.slackChannelId // }) // await client.endConversation() - await e.reply('由于Slack官方限制,结束Claude对话请前往网站或客户端执行/reset。', true) + await redis.del(`CHATGPT:SLACK_CONVERSATION:${e.sender.user_id}`) + await e.reply('claude对话已结束') return } let ats = e.message.filter(m => m.type === 'at') @@ -353,7 +354,7 @@ export class chatgpt extends plugin { async endAllConversations (e) { let use = await redis.get('CHATGPT:USE') || 'api' if (use === 'claude') { - await e.reply('由于Slack官方限制,结束Claude对话请前往网站或客户端执行/reset。', true) + await e.reply('claude暂不支持结束全部对话!', true) return } let deleted = 0 @@ -1389,7 +1390,7 @@ export class chatgpt extends plugin { slackUserToken: Config.slackUserToken, slackChannelId: Config.slackChannelId }) - let text = await client.sendMessage(prompt) + let text = await client.sendMessage(prompt, e) return { text } diff --git a/guoba.support.js b/guoba.support.js index 87c47f1..92961d3 100644 --- a/guoba.support.js +++ b/guoba.support.js @@ -458,9 +458,9 @@ export function supportGuoba () { component: 'Input' }, { - field: 'slackChannelId', - label: 'Slack私聊频道号', - bottomHelpMessage: '在Slack中与Claude机器人私聊的频道号。如果页面URL为https://app.slack.com/client/TXXXXXXXX/DXXXXXXXXX/,则频道号就是DXXXXXXXXX', + field: 'slackClaudeUserId', + label: 'Slack成员id', + bottomHelpMessage: '在Slack中点击Claude头像查看详情,其中的成员ID复制过来', component: 'Input' }, { diff --git a/utils/config.js b/utils/config.js index b224bcf..e1d0f26 100644 --- a/utils/config.js +++ b/utils/config.js @@ -94,8 +94,9 @@ const defaultConfig = { ttsRegex: '/匹配规则/匹配模式', slackUserToken: '', slackBotUserToken: '', - slackChannelId: '', + // slackChannelId: '', slackSigningSecret: '', + slackClaudeUserId: '', version: 'v2.5.3' } const _path = process.cwd() diff --git a/utils/slack/slackClient.js b/utils/slack/slackClient.js index 291f42b..b94ced6 100644 --- a/utils/slack/slackClient.js +++ b/utils/slack/slackClient.js @@ -29,40 +29,120 @@ export class SlackClaudeClient { } } - async sendMessage (prompt) { - let sendResponse = await this.app.client.chat.postMessage({ - as_user: true, - text: `${prompt}`, + async sendMessage (prompt, e, t = 0) { + if (t > 10) { + return 'claude 未响应' + } + let qq = e.sender.user_id + let channels = await this.app.client.conversations.list({ token: this.config.slackUserToken, - channel: this.config.slackChannelId + types: 'public_channel,private_channel' }) - let ts = sendResponse.ts - let response = '_Typing…_' - let tryTimes = 0 - while (response.trim().endsWith('_Typing…_')) { - let replies = await this.app.client.conversations.history({ + let channel = channels.channels.filter(c => c.name === '' + qq) + if (!channel || channel.length === 0) { + let createChannelResponse = await this.app.client.conversations.create({ token: this.config.slackUserToken, - channel: this.config.slackChannelId, - limit: 1, - oldest: ts + name: qq + '', + is_private: true }) - if (replies.messages.length > 0 && replies.messages[0].bot_profile) { - response = replies.messages[0].text - if (Config.debug) { - let text = response.replace('_Typing…_', '') - if (text) { - logger.info(response.replace('_Typing…_', '')) + channel = createChannelResponse.channel + await this.app.client.conversations.invite({ + token: this.config.slackUserToken, + channel: channel.id, + users: 'U053NDP2YRF' + }) + await delay(1000) + } else { + channel = channel[0] + } + let conversationId = await redis.get(`CHATGPT:SLACK_CONVERSATION:${qq}`) + if (!conversationId) { + let sendResponse = await this.app.client.chat.postMessage({ + as_user: true, + text: `<@${Config.slackClaudeUserId}> ${prompt}`, + token: this.config.slackUserToken, + channel: channel.id + }) + let ts = sendResponse.ts + let response = '_Typing…_' + let tryTimes = 0 + while (response.trim().endsWith('_Typing…_')) { + let replies = await this.app.client.conversations.replies({ + token: this.config.slackUserToken, + channel: channel.id, + limit: 1000, + ts: ts + }) + await await redis.set(`CHATGPT:SLACK_CONVERSATION:${qq}`, `${ts}`) + if (replies.messages.length > 0) { + let formalMessages = replies.messages.filter(m => m.text.indexOf('Acceptable Use Policy') === -1) + if (!formalMessages[formalMessages.length - 1].bot_profile) { + // 问题的下一句不是bot回复的,这属于意料之外的问题,可能是多人同时问问题导致 再问一次吧 + return await this.sendMessage(prompt, e, t + 1) + } + let reply = formalMessages[formalMessages.length - 1] + if (reply.text !== `<@${Config.slackClaudeUserId}> ${prompt}`) { + response = reply.text + if (Config.debug) { + let text = response.replace('_Typing…_', '') + if (text) { + logger.info(response.replace('_Typing…_', '')) + } + } } } + await delay(500) + tryTimes++ + if (tryTimes > 10 && response === '_Typing…_') { + // 过了5秒还没任何回复,就重新发一下试试 + logger.warn('claude没有响应,重试中') + return await this.sendMessage(prompt, e, t + 1) + } } - await delay(500) - tryTimes++ - if (tryTimes > 10 && response === '_Typing…_') { - // 过了5秒还没任何回复,就重新发一下试试 - logger.warn('claude没有响应,重试中') - return await this.sendMessage(prompt) + return response + } else { + await this.app.client.chat.postMessage({ + as_user: true, + text: `<@${Config.slackClaudeUserId}> ${prompt}`, + token: this.config.slackUserToken, + channel: channel.id, + thread_ts: conversationId + }) + let response = '_Typing…_' + let tryTimes = 0 + while (response.trim().endsWith('_Typing…_')) { + let replies = await this.app.client.conversations.replies({ + token: this.config.slackUserToken, + channel: channel.id, + limit: 1000, + ts: conversationId + }) + if (replies.messages.length > 0) { + let formalMessages = replies.messages.filter(m => m.text.indexOf('Acceptable Use Policy') === -1) + if (!formalMessages[formalMessages.length - 1].bot_profile) { + // 问题的下一句不是bot回复的,这属于意料之外的问题,可能是多人同时问问题导致 再问一次吧 + return await this.sendMessage(prompt, e, t + 1) + } + let reply = formalMessages[formalMessages.length - 1] + if (reply.text !== `<@${Config.slackClaudeUserId}> ${prompt}`) { + response = reply.text + if (Config.debug) { + let text = response.replace('_Typing…_', '') + if (text) { + logger.info(response.replace('_Typing…_', '')) + } + } + } + } + await delay(500) + tryTimes++ + if (tryTimes > 10 && response === '_Typing…_') { + // 过了5秒还没任何回复,就重新发一下试试 + logger.warn('claude没有响应,重试中') + return await this.sendMessage(prompt, e, t + 1) + } } + return response } - return response } }