mirror of
https://github.com/ikechan8370/chatgpt-plugin.git
synced 2025-12-18 06:17:06 +00:00
Merge branch 'ikechan8370:v2' into v2
This commit is contained in:
commit
d8454fe806
20 changed files with 657 additions and 320 deletions
22
apps/chat.js
22
apps/chat.js
|
|
@ -134,6 +134,7 @@ const newFetch = (url, options = {}) => {
|
|||
export class chatgpt extends plugin {
|
||||
constructor () {
|
||||
let toggleMode = Config.toggleMode
|
||||
let apiStream = Config.apiStream
|
||||
super({
|
||||
/** 功能名称 */
|
||||
name: 'ChatGpt 对话',
|
||||
|
|
@ -291,6 +292,7 @@ export class chatgpt extends plugin {
|
|||
]
|
||||
})
|
||||
this.toggleMode = toggleMode
|
||||
this.apiStream = apiStream
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -365,7 +367,7 @@ export class chatgpt extends plugin {
|
|||
if (use === 'api3') {
|
||||
await redis.del(`CHATGPT:QQ_CONVERSATION:${(e.isGroup && Config.groupMerge) ? e.group_id.toString() : e.sender.user_id}`)
|
||||
await this.reply('已退出当前对话,该对话仍然保留。请@我进行聊天以开启新的对话', true)
|
||||
} else if (use === 'bing' && (Config.toneStyle === 'Sydney' || Config.toneStyle === 'Custom')) {
|
||||
} else if (use === 'bing') {
|
||||
let c = await redis.get(`CHATGPT:CONVERSATIONS_BING:${(e.isGroup && Config.groupMerge) ? e.group_id.toString() : e.sender.user_id}`)
|
||||
if (!c) {
|
||||
await this.reply('当前没有开启对话', true)
|
||||
|
|
@ -458,7 +460,7 @@ export class chatgpt extends plugin {
|
|||
if (use === 'api3') {
|
||||
await redis.del(`CHATGPT:QQ_CONVERSATION:${qq}`)
|
||||
await this.reply(`${atUser}已退出TA当前的对话,TA仍可以@我进行聊天以开启新的对话`, true)
|
||||
} else if (use === 'bing' && (Config.toneStyle === 'Sydney' || Config.toneStyle === 'Custom')) {
|
||||
} else if (use === 'bing') {
|
||||
const conversation = {
|
||||
store: new KeyvFile({ filename: 'cache.json' }),
|
||||
namespace: Config.toneStyle
|
||||
|
|
@ -1214,11 +1216,7 @@ export class chatgpt extends plugin {
|
|||
previousConversation.invocationId = chatMessage.invocationId
|
||||
previousConversation.parentMessageId = chatMessage.parentMessageId
|
||||
previousConversation.conversationSignature = chatMessage.conversationSignature
|
||||
if (Config.toneStyle !== 'Sydney' && Config.toneStyle !== 'Custom') {
|
||||
previousConversation.bingToken = chatMessage.bingToken
|
||||
} else {
|
||||
previousConversation.bingToken = ''
|
||||
}
|
||||
previousConversation.bingToken = ''
|
||||
} else if (chatMessage.id) {
|
||||
previousConversation.parentMessageId = chatMessage.id
|
||||
} else if (chatMessage.message) {
|
||||
|
|
@ -1580,7 +1578,7 @@ export class chatgpt extends plugin {
|
|||
opt.toneStyle = Config.toneStyle
|
||||
// 如果当前没有开启对话或者当前是Sydney模式、Custom模式,则本次对话携带拓展资料
|
||||
let c = await redis.get(`CHATGPT:CONVERSATIONS_BING:${e.sender.user_id}`)
|
||||
if (!c || Config.toneStyle === 'Sydney' || Config.toneStyle === 'Custom') {
|
||||
if (!c) {
|
||||
opt.context = useCast?.bing_resource || Config.sydneyContext
|
||||
}
|
||||
// 重新拿存储的token,因为可能之前有过期的被删了
|
||||
|
|
@ -2265,7 +2263,7 @@ export class chatgpt extends plugin {
|
|||
let option = {
|
||||
timeoutMs: 600000,
|
||||
completionParams,
|
||||
stream: true,
|
||||
stream: this.apiStream,
|
||||
onProgress: (data) => {
|
||||
if (Config.debug) {
|
||||
logger.info(data?.text || data.functionCall || data)
|
||||
|
|
@ -2816,12 +2814,6 @@ async function getAvailableBingToken (conversation, throttled = []) {
|
|||
allThrottled
|
||||
}
|
||||
}
|
||||
if (Config.toneStyle != 'Sydney' && Config.toneStyle != 'Custom') {
|
||||
// bing 下,需要保证同一对话使用同一账号的token
|
||||
if (bingTokens.findIndex(element => element.Token === conversation.bingToken) > -1) {
|
||||
bingToken = conversation.bingToken
|
||||
}
|
||||
}
|
||||
// 记录使用情况
|
||||
const index = bingTokens.findIndex(element => element.Token === bingToken)
|
||||
bingTokens[index].Usage += 1
|
||||
|
|
|
|||
59
apps/draw.js
59
apps/draw.js
|
|
@ -4,6 +4,7 @@ import { makeForwardMsg } from '../utils/common.js'
|
|||
import _ from 'lodash'
|
||||
import { Config } from '../utils/config.js'
|
||||
import BingDrawClient from '../utils/BingDraw.js'
|
||||
import fetch from 'node-fetch'
|
||||
|
||||
export class dalle extends plugin {
|
||||
constructor (e) {
|
||||
|
|
@ -32,11 +33,67 @@ export class dalle extends plugin {
|
|||
{
|
||||
reg: '^#bing(画图|绘图)',
|
||||
fnc: 'bingDraw'
|
||||
},
|
||||
{
|
||||
reg: '^#dalle3(画图|绘图)',
|
||||
fnc: 'dalle3'
|
||||
}
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
// dalle3
|
||||
async dalle3 (e) {
|
||||
if (!Config.enableDraw) {
|
||||
this.reply('画图功能未开启')
|
||||
return false
|
||||
}
|
||||
let ttl = await redis.ttl(`CHATGPT:DALLE3:${e.sender.user_id}`)
|
||||
if (ttl > 0 && !e.isMaster) {
|
||||
this.reply(`冷却中,请${ttl}秒后再试`)
|
||||
return false
|
||||
}
|
||||
let prompt = e.msg.replace(/^#?dalle3(画图|绘图)/, '').trim()
|
||||
console.log('draw方法被调用,消息内容:', prompt)
|
||||
await redis.set(`CHATGPT:DALLE3:${e.sender.user_id}`, 'c', { EX: 30 })
|
||||
await this.reply('正在为您绘制大小为1024x1024的1张图片,预计消耗0.24美元余额,请稍候……')
|
||||
try {
|
||||
const response = await fetch(`${Config.openAiBaseUrl}/images/generations`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${Config.apiKey}`
|
||||
},
|
||||
body: JSON.stringify({
|
||||
model: 'dall-e-3',
|
||||
prompt,
|
||||
n: 1,
|
||||
size: '1024x1024',
|
||||
response_format: 'b64_json'
|
||||
})
|
||||
})
|
||||
// 如果需要,可以解析响应体
|
||||
const dataJson = await response.json()
|
||||
console.log(dataJson)
|
||||
if (dataJson.error) {
|
||||
e.reply(`画图失败:${dataJson.error?.code}:${dataJson.error?.message}`)
|
||||
await redis.del(`CHATGPT:DALLE3:${e.sender.user_id}`)
|
||||
return
|
||||
}
|
||||
if (dataJson.data[0].b64_json) {
|
||||
e.reply(`描述:${dataJson.data[0].revised_prompt}`)
|
||||
e.reply(segment.image(`base64://${dataJson.data[0].b64_json}`))
|
||||
} else if (dataJson.data[0].url) {
|
||||
e.reply(`哈哈哈,图来了~\n防止图💥,附上链接:\n${dataJson.data[0].url}`)
|
||||
e.reply(segment.image(dataJson.data[0].url))
|
||||
}
|
||||
} catch (err) {
|
||||
logger.error(err)
|
||||
this.reply(`画图失败: ${err}`, true)
|
||||
await redis.del(`CHATGPT:DALLE3:${e.sender.user_id}`)
|
||||
}
|
||||
}
|
||||
|
||||
async draw (e) {
|
||||
if (!Config.enableDraw) {
|
||||
this.reply('画图功能未开启')
|
||||
|
|
@ -215,7 +272,7 @@ export class dalle extends plugin {
|
|||
}
|
||||
try {
|
||||
let images = (await editImage(imgUrl, position.split(',').map(p => parseInt(p, 10)), prompt, num, size))
|
||||
.map(image => segment.image(`base64://${image}`))
|
||||
.map(image => segment.image(`base64://${image}`))
|
||||
if (images.length > 1) {
|
||||
this.reply(await makeForwardMsg(e, images, prompt))
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ let helpData = [
|
|||
},
|
||||
{
|
||||
icon: 'confirm',
|
||||
title: '#chatgpt必应切换(精准|均衡|创意|悉尼|自设定)',
|
||||
title: '#chatgpt必应切换(精准|创意)',
|
||||
desc: '切换Bing风格。'
|
||||
},
|
||||
{
|
||||
|
|
@ -337,6 +337,6 @@ export class help extends plugin {
|
|||
}
|
||||
|
||||
async help (e) {
|
||||
await render(e, 'chatgpt-plugin', 'help/index', { helpData, version })
|
||||
await render(e, 'chatgpt-plugin', 'help/index', { helpData, version })
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,42 +49,38 @@ export class history extends plugin {
|
|||
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:${queryUser}`
|
||||
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 = {}
|
||||
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:${queryUser}`
|
||||
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'
|
||||
}
|
||||
})
|
||||
} else {
|
||||
await e.reply('还不支持BING模式呢')
|
||||
return true
|
||||
}
|
||||
previousCachedMessages.forEach(m => {
|
||||
if (m.author === 'user') {
|
||||
tmp.prompt = m.text
|
||||
} else {
|
||||
tmp.response = m.text
|
||||
chat.push(tmp)
|
||||
tmp = {}
|
||||
}
|
||||
})
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -341,6 +341,16 @@ export class ChatgptManagement extends plugin {
|
|||
reg: '^#chatgpt必应(禁用|禁止|关闭|启用|开启)搜索$',
|
||||
fnc: 'switchBingSearch',
|
||||
permission: 'master'
|
||||
},
|
||||
{
|
||||
reg: '^#chatgpt查看当前配置$',
|
||||
fnc: 'queryConfig',
|
||||
permission: 'master'
|
||||
},
|
||||
{
|
||||
reg: '^#chatgpt(开启|关闭)(api|API)流$',
|
||||
fnc: 'switchStream',
|
||||
permission: 'master'
|
||||
}
|
||||
]
|
||||
})
|
||||
|
|
@ -1053,21 +1063,21 @@ azure语音:Azure 语音是微软 Azure 平台提供的一项语音服务,
|
|||
return
|
||||
}
|
||||
let map = {
|
||||
精准: 'Sydney',
|
||||
创意: 'Sydney',
|
||||
均衡: 'Sydney',
|
||||
Sydney: 'Sydney',
|
||||
sydney: 'Sydney',
|
||||
悉尼: 'Sydney',
|
||||
默认: 'Sydney',
|
||||
自设定: 'Custom',
|
||||
自定义: 'Custom'
|
||||
精准: 'Precise',
|
||||
创意: 'Creative',
|
||||
均衡: 'Precise',
|
||||
Sydney: 'Creative',
|
||||
sydney: 'Creative',
|
||||
悉尼: 'Creative',
|
||||
默认: 'Creative',
|
||||
自设定: 'Creative',
|
||||
自定义: 'Creative'
|
||||
}
|
||||
if (map[tongStyle]) {
|
||||
Config.toneStyle = map[tongStyle]
|
||||
await e.reply('切换成功')
|
||||
} else {
|
||||
await e.reply('没有这种风格。支持的风格:默认/创意/悉尼、自设定')
|
||||
await e.reply('没有这种风格。支持的风格:`精准`和`创意`,均支持设定')
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1695,26 +1705,20 @@ azure语音:Azure 语音是微软 Azure 平台提供的一项语音服务,
|
|||
|
||||
async setXinghuoModel (e) {
|
||||
this.setContext('saveXinghuoModel')
|
||||
await this.reply('1:星火V1.5\n2:星火V2\n3:星火V3\n4:星火助手')
|
||||
await this.reply('1:星火V1.5\n2:星火V2\n3:星火V3\n4:星火V3.5\n5:星火助手')
|
||||
await this.reply('请发送序号', true)
|
||||
return false
|
||||
}
|
||||
|
||||
async switchBingSearch (e) {
|
||||
if (e.msg.includes('启用') || e.msg.includes('开启')) {
|
||||
Config.sydneyEnableSearch = true
|
||||
await e.reply('已开启必应搜索')
|
||||
} else {
|
||||
Config.sydneyEnableSearch = false
|
||||
await e.reply('已禁用必应搜索')
|
||||
}
|
||||
}
|
||||
|
||||
async saveXinghuoModel (e) {
|
||||
if (!this.e.msg) return
|
||||
let token = this.e.msg
|
||||
let ver
|
||||
switch (token) {
|
||||
case '4':
|
||||
ver = 'V3.5'
|
||||
Config.xhmode = 'apiv3.5'
|
||||
break
|
||||
case '3':
|
||||
ver = 'V3'
|
||||
Config.xhmode = 'apiv3'
|
||||
|
|
@ -1727,7 +1731,7 @@ azure语音:Azure 语音是微软 Azure 平台提供的一项语音服务,
|
|||
ver = 'V1.5'
|
||||
Config.xhmode = 'api'
|
||||
break
|
||||
case '4':
|
||||
case '5':
|
||||
ver = '助手'
|
||||
Config.xhmode = 'assistants'
|
||||
break
|
||||
|
|
@ -1737,4 +1741,46 @@ azure语音:Azure 语音是微软 Azure 平台提供的一项语音服务,
|
|||
await this.reply(`已成功切换到星火${ver}`, true)
|
||||
this.finish('saveXinghuoModel')
|
||||
}
|
||||
|
||||
async switchBingSearch (e) {
|
||||
if (e.msg.includes('启用') || e.msg.includes('开启')) {
|
||||
Config.sydneyEnableSearch = true
|
||||
await e.reply('已开启必应搜索')
|
||||
} else {
|
||||
Config.sydneyEnableSearch = false
|
||||
await e.reply('已禁用必应搜索')
|
||||
}
|
||||
}
|
||||
|
||||
async queryConfig (e) {
|
||||
let use = await redis.get('CHATGPT:USE')
|
||||
let config = []
|
||||
config.push(`当前模式:${use}`)
|
||||
config.push(`\n当前API模型:${Config.model}`)
|
||||
if (e.isPrivate) {
|
||||
config.push(`\n当前APIKey:${Config.apiKey}`)
|
||||
config.push(`\n当前API反代:${Config.openAiBaseUrl}`)
|
||||
config.push(`\n当前必应反代:${Config.sydneyReverseProxy}`)
|
||||
}
|
||||
config.push(`\n当前星火模型:${Config.xhmode}`)
|
||||
e.reply(config)
|
||||
}
|
||||
|
||||
async switchStream (e) {
|
||||
if (e.msg.includes('开启')) {
|
||||
if (Config.apiStream) {
|
||||
await e.reply('已经开启了')
|
||||
return
|
||||
}
|
||||
Config.apiStream = true
|
||||
await e.reply('好的,已经打开API流式输出')
|
||||
} else {
|
||||
if (!Config.apiStream) {
|
||||
await e.reply('已经是关闭得了')
|
||||
return
|
||||
}
|
||||
Config.apiStream = false
|
||||
await e.reply('好的,已经关闭API流式输出')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -149,14 +149,9 @@ export class help extends plugin {
|
|||
}
|
||||
}
|
||||
let use = await redis.get('CHATGPT:USE') || 'api'
|
||||
if (use.toLowerCase() === 'bing') {
|
||||
if (Config.toneStyle === 'Custom') {
|
||||
use = 'Custom'
|
||||
}
|
||||
}
|
||||
const keyMap = {
|
||||
api: 'promptPrefixOverride',
|
||||
Custom: 'sydney',
|
||||
bing: 'sydney',
|
||||
claude: 'slackClaudeGlobalPreset',
|
||||
qwen: 'promptPrefixOverride',
|
||||
gemini: 'geminiPrompt',
|
||||
|
|
@ -176,7 +171,7 @@ export class help extends plugin {
|
|||
await redis.set(`CHATGPT:PROMPT_USE_${use}`, promptName)
|
||||
await e.reply(`你当前正在使用${use}模式,已将该模式设定应用为"${promptName}"。更该设定后建议结束对话以使设定更好生效`, true)
|
||||
} else {
|
||||
await e.reply(`你当前正在使用${use}模式,该模式不支持设定。支持设定的模式有:API、自定义、Claude、通义千问和Gemini`, true)
|
||||
await e.reply(`你当前正在使用${use}模式,该模式不支持设定。支持设定的模式有:API、必应、Claude、通义千问、星火和Gemini`, true)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -277,11 +272,6 @@ export class help extends plugin {
|
|||
// return
|
||||
}
|
||||
let use = await redis.get('CHATGPT:USE') || 'api'
|
||||
if (use.toLowerCase() === 'bing') {
|
||||
if (Config.toneStyle === 'Custom') {
|
||||
use = 'Custom'
|
||||
}
|
||||
}
|
||||
let currentUse = e.msg.replace(/^#(chatgpt|ChatGPT)(上传|分享|共享)设定/, '')
|
||||
if (!currentUse) {
|
||||
currentUse = await redis.get(`CHATGPT:PROMPT_USE_${use}`)
|
||||
|
|
@ -361,7 +351,7 @@ export class help extends plugin {
|
|||
title: currentUse,
|
||||
prompt: content,
|
||||
qq: master || (getUin(this.e) + ''), // 上传者设定为主人qq或机器人qq
|
||||
use: extraData.use === 'Custom' ? 'Sydney' : 'ChatGPT',
|
||||
use: extraData.use === 'bing' ? 'Bing' : 'ChatGPT',
|
||||
r18,
|
||||
description
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue