mirror of
https://github.com/ikechan8370/chatgpt-plugin.git
synced 2025-12-16 13:27:08 +00:00
独立render功能,图片模式添加引用回复 (#204)
* 修复引用转发,默认bing模式并发 * 开启stream增加稳定性 * fix: remove queue element only in non-bing mode * 使用chatgpt-api自带的超时逻辑,文字过多时启动切换到图片输出防止被吞 * Update chat.js * 添加Bing专用的图片输出样式 * 添加chatgpt的新图片模式,临时处理切换api导致的对话异常 * 修改bing样式表 * 为图片添加外部页面缓存 * 为图片模式添加MathJax * feat: add switch for qrcode * 防止script攻击 * 修复网页模板错误 * 修复bing页面引用错误 * 缓存服务器异常时处理 * 添加默认配置加载 * 修复配置文件路径错误 * 删除重复的模板文件,修复二维码地址错误 * 修正图片渲染错误 * 修复引用渲染错误 * 二维码网址统一改为使用本地配置 * 添加关闭思考提示的配置项 * 修复在Windows上无法载入配置文件的问题 * 修复关闭qr的情况下渲染错误 * 改为使用base64传递返回数据 * 当异常过多时使用图片输出 * 添加锅巴面板配置支持 * 补充遗漏的默认配置 * 修复qr模式下引用未被传递的问题 * 修复未将引用数据传输给缓存服务器的问题 * 删除无用的bingTimeoutMs配置项 * 添加消息队列超时弹出 * 优化图片模式处理,解决对话队列卡住的问题 * 添加对图片ocr的支持 * 添加图片识别配置项 * 添加黑名单配置项 * 修复一些bug * 修改锅巴配置格式和描述 * 传入数据也使用markdown * 图片识别换行改为marked兼容 * 添加绘图CD配置项 * 独立render模块,添加图片回复引用 --------- Co-authored-by: ikechan8370 <geyinchibuaa@gmail.com>
This commit is contained in:
parent
eb25ba1bfa
commit
7b58f20578
6 changed files with 95 additions and 6 deletions
|
|
@ -5,7 +5,7 @@ import { v4 as uuid } from 'uuid'
|
||||||
import delay from 'delay'
|
import delay from 'delay'
|
||||||
import { ChatGPTAPI } from 'chatgpt'
|
import { ChatGPTAPI } from 'chatgpt'
|
||||||
import { ChatGPTClient, BingAIClient } from '@waylaidwanderer/chatgpt-api'
|
import { ChatGPTClient, BingAIClient } from '@waylaidwanderer/chatgpt-api'
|
||||||
import { escapeHtml, getMessageById, makeForwardMsg, tryTimes, upsertMessage, randomString } from '../utils/common.js'
|
import { render, getMessageById, makeForwardMsg, tryTimes, upsertMessage, randomString } from '../utils/common.js'
|
||||||
import { ChatGPTPuppeteer } from '../utils/browser.js'
|
import { ChatGPTPuppeteer } from '../utils/browser.js'
|
||||||
import { KeyvFile } from 'keyv-file'
|
import { KeyvFile } from 'keyv-file'
|
||||||
import { OfficialChatGPTClient } from '../utils/message.js'
|
import { OfficialChatGPTClient } from '../utils/message.js'
|
||||||
|
|
@ -527,7 +527,7 @@ export class chatgpt extends plugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await e.runtime.render('chatgpt-plugin', template, {
|
await e.reply(await render(e, 'chatgpt-plugin', template, {
|
||||||
content: new Buffer.from(content).toString('base64'),
|
content: new Buffer.from(content).toString('base64'),
|
||||||
prompt: new Buffer.from(prompt).toString('base64'),
|
prompt: new Buffer.from(prompt).toString('base64'),
|
||||||
senderName: e.sender.nickname,
|
senderName: e.sender.nickname,
|
||||||
|
|
@ -535,7 +535,7 @@ export class chatgpt extends plugin {
|
||||||
quotes: quote,
|
quotes: quote,
|
||||||
cache: cacheData,
|
cache: cacheData,
|
||||||
version
|
version
|
||||||
})
|
},{retType: Config.quoteReply ? 'base64' : ''}), e.isGroup && Config.quoteReply)
|
||||||
}
|
}
|
||||||
|
|
||||||
async sendMessage (prompt, conversation = {}, use, e) {
|
async sendMessage (prompt, conversation = {}, use, e) {
|
||||||
|
|
@ -717,7 +717,7 @@ export class chatgpt extends plugin {
|
||||||
logger.mark('all conversations: ', conversations)
|
logger.mark('all conversations: ', conversations)
|
||||||
}
|
}
|
||||||
// let conversationsFirst10 = conversations.slice(0, 10)
|
// let conversationsFirst10 = conversations.slice(0, 10)
|
||||||
await e.runtime.render('chatgpt-plugin', 'conversation/chatgpt', { conversations, version })
|
await render(e, 'chatgpt-plugin', 'conversation/chatgpt', { conversations, version })
|
||||||
let text = '对话列表\n'
|
let text = '对话列表\n'
|
||||||
text += '对话id | 对话发起者 \n'
|
text += '对话id | 对话发起者 \n'
|
||||||
conversations.forEach(c => {
|
conversations.forEach(c => {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import plugin from '../../../lib/plugins/plugin.js'
|
import plugin from '../../../lib/plugins/plugin.js'
|
||||||
import { Config } from '../utils/config.js'
|
import { Config } from '../utils/config.js'
|
||||||
|
import { render } from '../utils/common.js'
|
||||||
let version = Config.version
|
let version = Config.version
|
||||||
let helpData = [
|
let helpData = [
|
||||||
{
|
{
|
||||||
|
|
@ -131,6 +132,6 @@ export class help extends plugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
async help (e) {
|
async help (e) {
|
||||||
await e.runtime.render('chatgpt-plugin', 'help/index', { helpData, version })
|
await render(e, 'chatgpt-plugin', 'help/index', { helpData, version })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,8 @@ export default {
|
||||||
// conversationPreserveTime: 0,
|
// conversationPreserveTime: 0,
|
||||||
// 触发方式 可选值:at 或 prefix 。at模式下只有at机器人才会回复。prefix模式下不需要at,但需要添加前缀#chat
|
// 触发方式 可选值:at 或 prefix 。at模式下只有at机器人才会回复。prefix模式下不需要at,但需要添加前缀#chat
|
||||||
// toggleMode: 'at',
|
// toggleMode: 'at',
|
||||||
|
// 是否在回复图片时引用原始消息
|
||||||
|
// quoteReply: true,
|
||||||
// 是否在图片模式中启用二维码。该对话内容将被发送至第三方服务器以进行渲染展示。改为false关闭该功能
|
// 是否在图片模式中启用二维码。该对话内容将被发送至第三方服务器以进行渲染展示。改为false关闭该功能
|
||||||
// showQRCode: true,
|
// showQRCode: true,
|
||||||
// 图片内容渲染服务器API地址
|
// 图片内容渲染服务器API地址
|
||||||
|
|
|
||||||
|
|
@ -87,6 +87,12 @@ export function supportGuoba() {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
field: 'quoteReply',
|
||||||
|
label: '图片引用消息',
|
||||||
|
bottomHelpMessage: '在回复图片时引用原始消息',
|
||||||
|
component: 'Switch',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
field: 'showQRCode',
|
field: 'showQRCode',
|
||||||
label: '启用二维码',
|
label: '启用二维码',
|
||||||
|
|
@ -105,6 +111,16 @@ export function supportGuoba() {
|
||||||
bottomHelpMessage: '图片内容渲染服务器开启预制访问代码,当渲染服务器访问较慢时可以开启,但无法保证访问代码可以正常访问页面。',
|
bottomHelpMessage: '图片内容渲染服务器开启预制访问代码,当渲染服务器访问较慢时可以开启,但无法保证访问代码可以正常访问页面。',
|
||||||
component: 'Switch',
|
component: 'Switch',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
field: 'drawCD',
|
||||||
|
label: '绘图CD',
|
||||||
|
helpMessage: '单位:秒',
|
||||||
|
bottomHelpMessage: '绘图指令的CD时间,主人不受限制',
|
||||||
|
component: 'InputNumber',
|
||||||
|
componentProps: {
|
||||||
|
min: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
field: 'proxy',
|
field: 'proxy',
|
||||||
label: '代理服务器地址',
|
label: '代理服务器地址',
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import { exec } from 'child_process'
|
||||||
import lodash from 'lodash'
|
import lodash from 'lodash'
|
||||||
import fs from 'node:fs'
|
import fs from 'node:fs'
|
||||||
import path from 'node:path'
|
import path from 'node:path'
|
||||||
|
import puppeteer from '../../../lib/puppeteer/puppeteer.js'
|
||||||
// export function markdownToText (markdown) {
|
// export function markdownToText (markdown) {
|
||||||
// return remark()
|
// return remark()
|
||||||
// .use(stripMarkdown)
|
// .use(stripMarkdown)
|
||||||
|
|
@ -217,4 +218,72 @@ export function mkdirs (dirname) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param pluginKey plugin key
|
||||||
|
* @param htmlPath html文件路径,相对于plugin resources目录
|
||||||
|
* @param data 渲染数据
|
||||||
|
* @param renderCfg 渲染配置
|
||||||
|
* @param renderCfg.retType 返回值类型
|
||||||
|
* * default/空:自动发送图片,返回true
|
||||||
|
* * msgId:自动发送图片,返回msg id
|
||||||
|
* * base64: 不自动发送图像,返回图像base64数据
|
||||||
|
* @param renderCfg.beforeRender({data}) 可改写渲染的data数据
|
||||||
|
* @returns {Promise<boolean>}
|
||||||
|
*/
|
||||||
|
export async function render (e, pluginKey, htmlPath, data = {}, renderCfg = {}) {
|
||||||
|
// 处理传入的path
|
||||||
|
htmlPath = htmlPath.replace(/.html$/, '')
|
||||||
|
let paths = lodash.filter(htmlPath.split('/'), (p) => !!p)
|
||||||
|
htmlPath = paths.join('/')
|
||||||
|
// 创建目录
|
||||||
|
const mkdir = (check) => {
|
||||||
|
let currDir = `${process.cwd()}/data`
|
||||||
|
for (let p of check.split('/')) {
|
||||||
|
currDir = `${currDir}/${p}`
|
||||||
|
if (!fs.existsSync(currDir)) {
|
||||||
|
fs.mkdirSync(currDir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return currDir
|
||||||
|
}
|
||||||
|
mkdir(`html/${pluginKey}/${htmlPath}`)
|
||||||
|
// 自动计算pluResPath
|
||||||
|
let pluResPath = `../../../${lodash.repeat('../', paths.length)}plugins/${pluginKey}/resources/`
|
||||||
|
// 渲染data
|
||||||
|
data = {
|
||||||
|
...data,
|
||||||
|
_plugin: pluginKey,
|
||||||
|
_htmlPath: htmlPath,
|
||||||
|
pluResPath,
|
||||||
|
tplFile: `./plugins/${pluginKey}/resources/${htmlPath}.html`,
|
||||||
|
saveId: data.saveId || data.save_id || paths[paths.length - 1],
|
||||||
|
pageGotoParams: {
|
||||||
|
waitUntil: 'networkidle0'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 处理beforeRender
|
||||||
|
if (renderCfg.beforeRender) {
|
||||||
|
data = renderCfg.beforeRender({ data }) || data
|
||||||
|
}
|
||||||
|
// 保存模板数据
|
||||||
|
if (process.argv.includes('web-debug')) {
|
||||||
|
// debug下保存当前页面的渲染数据,方便模板编写与调试
|
||||||
|
// 由于只用于调试,开发者只关注自己当时开发的文件即可,暂不考虑app及plugin的命名冲突
|
||||||
|
let saveDir = mkdir(`ViewData/${pluginKey}`)
|
||||||
|
let file = `${saveDir}/${data._htmlPath.split('/').join('_')}.json`
|
||||||
|
fs.writeFileSync(file, JSON.stringify(data))
|
||||||
|
}
|
||||||
|
// 截图
|
||||||
|
let base64 = await puppeteer.screenshot(`${pluginKey}/${htmlPath}`, data)
|
||||||
|
if (renderCfg.retType === 'base64') {
|
||||||
|
return base64
|
||||||
|
}
|
||||||
|
let ret = true
|
||||||
|
if (base64) {
|
||||||
|
ret = await e.reply(base64)
|
||||||
|
}
|
||||||
|
return renderCfg.retType === 'msgId' ? ret : true
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ const defaultConfig = {
|
||||||
autoUsePictureThreshold: 1200,
|
autoUsePictureThreshold: 1200,
|
||||||
conversationPreserveTime: 0,
|
conversationPreserveTime: 0,
|
||||||
toggleMode: 'at',
|
toggleMode: 'at',
|
||||||
|
quoteReply: true,
|
||||||
showQRCode: true,
|
showQRCode: true,
|
||||||
cacheUrl: 'https://content.alcedogroup.com',
|
cacheUrl: 'https://content.alcedogroup.com',
|
||||||
cacheEntry: false,
|
cacheEntry: false,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue