feat: 聊天记录

This commit is contained in:
ikechan8370 2023-03-29 23:50:49 +08:00
parent 0755b54486
commit fbfd105e0d
4 changed files with 221 additions and 1 deletions

View file

@ -50,6 +50,11 @@ let helpData = [
icon: 'destroy-other',
title: '#结束对话 @某人',
desc: '结束该用户当前对话,下次开启对话机器人将遗忘掉本次对话内容。'
},
{
icon: 'confirm',
title: '#chatgpt(导出)聊天记录',
desc: '图片形式导出聊天记录目前仅支持Bing下的Sydney和自定义'
}
]
},

116
apps/history.js Normal file
View file

@ -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
}

View file

@ -0,0 +1,99 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>聊天记录</title>
</head>
<body>
<div class="content">
<div class="title">
聊天记录 {{user.name}}【User】 & {{bot.name}}【Bot】
</div>
{{each chat val}}
<div class="chat-bot">
<div>
<img src="https://q1.qlogo.cn/g?b=qq&s=0&nk={{user.qq}}" style="height:40px;margin-top:10px;margin-bottom:10px;margin-left: 10px">
</div>
<div style="margin: 10px;" class="blob-user">
{{val.prompt}}
</div>
</div>
<div class="chat-user">
<div style="margin: 10px;" class="blob-bot">
{{val.response}}
</div>
<div>
<img src="https://q1.qlogo.cn/g?b=qq&s=0&nk={{bot.qq}}" style="height:40px;margin-top:10px;margin-bottom:10px;margin-left: 10px">
</div>
</div>
{{/each}}
<div class="site-logo">
Created By Yunzai-Bot and ChatGPT-Plugin {{version}}
</div>
</div>
</body>
</html>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
user-select: none;
}
body {
font-family: sans-serif;
font-size: 16px;
width: 600px;
color: #1e1f20;
transform: scale(1.5);
transform-origin: 0 0;
}
.content {
width: 600px;
border-radius: 5px;
background: #dbedee;
}
.title {
padding-top: 10px;
width: 90%;
margin: auto;
font-weight: bold;
height: 50px;
font-size: 20px;
text-align: center;
}
.chat-bot {
width: 540px;
padding-left: 30px;
padding-right: 30px;
margin-top: 5px;
margin-bottom: 5px;
display: flex;
}
.chat-user {
width: 540px;
margin-left: 30px;
margin-top: 5px;
margin-bottom: 5px;
display: flex;
}
.blob-bot {
/*border: #00c3ff solid 1px;*/
border-radius: 5px;
padding: 9px;
background: #abb8ff;
width: 480px;
}
.blob-user {
/*border: #00c3ff solid 1px;*/
border-radius: 5px;
padding: 9px;
background: #b2d797;
}
.site-logo {
text-align: center;
padding-bottom: 20px;
}
</style>

View file

@ -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,