From 31af39f2575888f3ea6efd20b4be693d3644d1d1 Mon Sep 17 00:00:00 2001 From: ikechan8370 Date: Wed, 7 Dec 2022 18:29:44 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=B0=9D=E8=AF=95=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E8=BF=9E=E7=BB=AD=E5=AF=B9=E8=AF=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.js | 139 ++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 123 insertions(+), 16 deletions(-) diff --git a/index.js b/index.js index 50842fb..78adab2 100644 --- a/index.js +++ b/index.js @@ -3,7 +3,13 @@ import { ChatGPTAPI } from 'chatgpt' import _ from 'lodash' const SESSION_TOKEN='' -export class example extends plugin { +/** + * 每个对话保留的时长。单个对话内ai是保留上下文的。超时后销毁对话,再次对话创建新的对话。 + * 单位:秒 + * @type {number} + */ +const CONVERSATION_PRESERVE_TIME = 600 +export class chatgpt extends plugin { constructor () { super({ /** 功能名称 */ @@ -20,30 +26,131 @@ export class example extends plugin { reg: '^#chatgpt([\s\S]*)', /** 执行方法 */ fnc: 'chatgpt' + }, + { + reg: 'chatgpt对话列表', + fnc: 'getConversations' + }, + { + reg: '^#结束对话([\s\S]*)', + fnc: 'destroyConversations' + }, + { + reg: 'chatgpt帮助', + fnc: 'help' } ] }) - const api = new ChatGPTAPI({ sessionToken: SESSION_TOKEN, markdown: false }) - this.chatGPTApi = api + this.chatGPTApi = new ChatGPTAPI({ + sessionToken: SESSION_TOKEN, + markdown: true, + userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36' + }) } + /** - * 调用chatgpt接口 + * 获取chatgpt当前对话列表 + * @param e + * @returns {Promise} + */ + async getConversations (e) { + let keys = await redis.keys('CHATGPT:CONVERSATIONS:*') + if (!keys || keys.length === 0) { + await this.reply('当前没有人正在与机器人对话', true) + } else { + let response = '当前对话列表:(格式为【开始时间 qq昵称 对话长度 最后活跃时间】)\n' + await Promise.all(keys.map(async (key) => { + let conversation = await redis.get(key) + if (conversation) { + conversation = JSON.parse(conversation) + response += `${conversation.ctime} ${conversation.sender.nickname} ${conversation.num} ${conversation.utime} \n` + } + })) + await this.reply(`${response}`, true) + } + } + + /** + * 销毁指定人的对话 + * @param e + * @returns {Promise} + */ + async destroyConversations (e) { + let ats = e.message.filter(m => m.type === 'at') + if (ats.length === 0) { + let c = await redis.get(`CHATGPT:CONVERSATIONS:${e.sender.user_id}`) + if (!c) { + await this.reply('当前没有开启对话', true) + } else { + await redis.del(`CHATGPT:CONVERSATIONS:${e.sender.user_id}`) + await this.reply('已结束当前对话,请使用#chatgpt进行聊天以开启新的对话', true) + } + } else { + let at = ats[0] + let qq = at.qq + let atUser = _.trimStart(at.text, '@') + let c = await redis.get(`CHATGPT:CONVERSATIONS:${qq}`) + if (!c) { + await this.reply(`当前${atUser}没有开启对话`, true) + } else { + await redis.del(`CHATGPT:CONVERSATIONS:${qq}`) + await this.reply(`已结束${atUser}的对话,他仍可以使用#chatgpt进行聊天以开启新的对话`, true) + } + } + } + + async help (e) { + let response = 'chatgpt-plugin使用帮助文字版\n' + + '#chatgpt+聊天内容: 发起对话与AI进行聊天\n' + + 'chatgpt对话列表: 查看当前发起的对话\n' + + '#结束对话: 结束自己或@用户的对话' + await this.reply(response) + } + + /** + * #chatgpt * @param e oicq传递的事件参数e */ async chatgpt (e) { - logger.info(e.msg) - let question = _.trimStart(e.msg, "#chatgpt") + let question = _.trimStart(e.msg, '#chatgpt') question = question.trimStart() - logger.info(`chatgpt question: ${question}`) await this.chatGPTApi.ensureAuth() - // @todo conversation - // const response = await this.chatGPTApi.sendMessage(question, { conversationId: '0c382256-d267-4dd4-90e3-a01dd22c20a2', onProgress: this.onProgress }) - const response = await this.chatGPTApi.sendMessage(question) - /** 最后回复消息 */ - await this.reply(`${response}`, true) - } - - onProgress(partialResponse) { - console.log(partialResponse) + let c + logger.info(`chatgpt question: ${question}`) + let previousConversation = await redis.get(`CHATGPT:CONVERSATIONS:${e.sender.user_id}`) + if (!previousConversation) { + c = this.chatGPTApi.getConversation() + previousConversation = { + sender: e.sender, + conversation: c, + ctime: new Date(), + utime: new Date(), + num: 0 + } + await redis.set(`CHATGPT:CONVERSATIONS:${e.sender.user_id}`, JSON.stringify(previousConversation), { EX: CONVERSATION_PRESERVE_TIME }) + } else { + c = this.chatGPTApi.getConversation({ + conversationId: JSON.parse(previousConversation).conversation.conversationId, + parentMessageId: JSON.parse(previousConversation).conversation.parentMessageId + }) + } + try { + // console.log({ c }) + const response = await c.sendMessage(question) + logger.info(response) + // 更新redis中的conversation对象,因为send后c已经被自动更新了 + await redis.set(`CHATGPT:CONVERSATIONS:${e.sender.user_id}`, JSON.stringify({ + sender: e.sender, + conversation: c, + ctime: previousConversation.ctime, + utime: new Date(), + num: previousConversation.num + 1 + }), { EX: CONVERSATION_PRESERVE_TIME }) + /** 最后回复消息 */ + await this.reply(`${response}`, true) + } catch (e) { + logger.error(e) + await this.reply(`与OpenAI通信异常,请稍后重试:${e}`, true) + } } }