diff --git a/apps/help.js b/apps/help.js index 65ee33f..50850e6 100644 --- a/apps/help.js +++ b/apps/help.js @@ -50,6 +50,11 @@ let helpData = [ icon: 'destroy-other', title: '#结束对话 @某人', desc: '结束该用户当前对话,下次开启对话机器人将遗忘掉本次对话内容。' + }, + { + icon: 'confirm', + title: '#chatgpt(导出)聊天记录', + desc: '图片形式导出聊天记录,目前仅支持Bing下的Sydney和自定义' } ] }, diff --git a/apps/history.js b/apps/history.js new file mode 100644 index 0000000..bbc0bec --- /dev/null +++ b/apps/history.js @@ -0,0 +1,116 @@ +import plugin from '../../../lib/plugins/plugin.js' +import { render } from '../utils/common.js' +import { Config } from '../utils/config.js' +import { KeyvFile } from 'keyv-file' + +async function getKeyv () { + let Keyv + try { + Keyv = (await import('keyv')).default + } catch (error) { + throw new Error('keyv依赖未安装,请使用pnpm install keyv安装') + } + return Keyv +} +export class history extends plugin { + constructor (e) { + super({ + name: 'ChatGPT-Plugin聊天记录', + dsc: 'ChatGPT-Plugin聊天记录提取', + event: 'message', + priority: 500, + rule: [ + { + reg: '^#(chatgpt|ChatGPT)(导出)?聊天记录', + fnc: 'history' + } + ] + }) + } + + async history (e) { + let use = await redis.get('CHATGPT:USE') || 'api' + let chat = [] + let filtered = e.message.filter(m => m.type === 'at').filter(m => m.qq !== Bot.uin) + let queryUser = e.sender.user_id + if (filtered.length > 0) { + queryUser = filtered[0].qq + } + switch (use) { + case 'api': { + await e.reply('还不支持API模式呢') + return true + } + case 'api3': { + await e.reply('还不支持API3模式呢') + return true + } + case 'bing': { + if (Config.toneStyle === 'Sydney' || Config.toneStyle === 'Custom') { + const cacheOptions = { + namespace: Config.toneStyle, + store: new KeyvFile({ filename: 'cache.json' }) + } + let Keyv = await getKeyv() + let conversationsCache = new Keyv(cacheOptions) + const conversation = (await conversationsCache.get(`SydneyUser_${queryUser}`)) || { + messages: [], + createdAt: Date.now() + } + let key = `CHATGPT:CONVERSATIONS_BING:${e.sender.user_id}` + let previousConversation = await redis.get(key) || JSON.stringify({}) + previousConversation = JSON.parse(previousConversation) + let parentMessageId = previousConversation.parentMessageId + let tmp = {} + const previousCachedMessages = getMessagesForConversation(conversation.messages, parentMessageId) + .map((message) => { + return { + text: message.message, + author: message.role === 'User' ? 'user' : 'bot' + } + }) + previousCachedMessages.forEach(m => { + if (m.author === 'user') { + tmp.prompt = m.text + } else { + tmp.response = m.text + chat.push(tmp) + tmp = {} + } + }) + } else { + await e.reply('还不支持BING模式呢') + return true + } + break + } + } + await e.reply(await render(e, 'chatgpt-plugin', 'content/History/index', { + version: Config.version, + user: { + qq: e.sender.user_id, + name: e.sender.card || e.sender.nickname || e.sender.user_id + }, + bot: { + qq: Bot.uin, + name: Bot.nickname + }, + chat + }, {})) + } +} + +function getMessagesForConversation (messages, parentMessageId) { + const orderedMessages = [] + let currentMessageId = parentMessageId + while (currentMessageId) { + const message = messages.find((m) => m.id === currentMessageId) + if (!message) { + break + } + orderedMessages.unshift(message) + currentMessageId = message.parentMessageId + } + + return orderedMessages +} diff --git a/resources/content/History/index.html b/resources/content/History/index.html new file mode 100644 index 0000000..c8080c2 --- /dev/null +++ b/resources/content/History/index.html @@ -0,0 +1,99 @@ + + + + + 聊天记录 + + +
+
+ 聊天记录 {{user.name}}【User】 & {{bot.name}}【Bot】 +
+ {{each chat val}} +
+
+ +
+
+ {{val.prompt}} +
+
+
+
+ {{val.response}} +
+
+ +
+
+ {{/each}} + +
+ + + \ No newline at end of file diff --git a/utils/SydneyAIClient.js b/utils/SydneyAIClient.js index a624f3b..5ed1897 100644 --- a/utils/SydneyAIClient.js +++ b/utils/SydneyAIClient.js @@ -690,7 +690,7 @@ export default class SydneyAIClient { conversation.messages.push(userMessage) conversation.messages.push(replyMessage) } - + await this.conversationsCache.set(conversationKey, conversation) return { conversationSignature, conversationId,