Merge branch 'ikechan8370:v2' into v2

This commit is contained in:
ifeif 2023-11-24 22:11:27 +08:00 committed by GitHub
commit 9723e6db17
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
92 changed files with 4289 additions and 1073 deletions

View file

@ -1,5 +1,5 @@
![chatgpt-plugin](https://user-images.githubusercontent.com/21212372/232115814-de9a0633-371f-4733-8da0-dd6e912c8a1e.png)
<div align=center> <h1>云崽QQ机器人的ChatGPT插件</h1> </div>
<div align=center> <h1>云崽系机器人的智能聊天插件</h1> </div>
<div align=center>
<img src ="https://img.shields.io/github/issues/ikechan8370/chatgpt-plugin?logo=github"/>
@ -18,9 +18,9 @@
### 推荐的相关文档和参考资料
本README
[手册](https://chatgptplugin.ikechan8370.com/)
[手册](https://yunzai.chat)
[文档1建设中](https://chatgpt-docs.err0r.top/)
[插件常见问题(鹤望兰版)](https://www.wolai.com/4FCxxWAdjbrHF29MCJmAQK)
[插件常见问题(鹤望兰版)](https://chatgptplugin.ikechan8370.com/guide/)
[Yunzai常见问题LUCK小运版](https://www.wolai.com/oA43vuW71aBnv7UsEysn4T)
[憨憨博客](https://blog.hanhanz.top/)
@ -41,6 +41,8 @@
* 2023-05-29 支持gpt-4 API.必应无需cookie即可对话Sydney和自定义模式
* 2023-07 支持智能模式,机器人可以实现禁言、群名片/头衔(需给机器人管理员/群主、分享音乐视频、主动发音频、对接ap,sr和喵喵等插件、联网搜索等需api模式0613系列模型。智能模式所需的额外api和搜索api分别可以参考[chatgpt-plugin-extras](https://github.com/ikechan8370/chatgpt-plugin-extras) 和 [search-api](https://github.com/ikechan8370/search-api) 自行搭建,其中后者提供了一个公益版本,前者可使用[huggingface](https://huggingface.co/spaces/ikechan8370/cp-extra)部署
* 2023-09-10 支持来自claude.ai的claude-2模型
* 2023-10-19 支持读取文件目前适配必应模式和Claude2模式
* 2023-10-25 增加支持通义千问官方API
### 如果觉得这个插件有趣或者对你有帮助请点一个star吧
## 版本要求
@ -50,16 +52,6 @@ Node.js >= 18 / Node.js >= 14(with node-fetch)
## 安装与使用方法
### 安装
在安装之前请先判断自己需要使用哪种模式本插件支持官方API/第三方API/~~浏览器~~/必应四种模式。也可以选择**我全都要**(通过qq发送命令`#chatgpt切换浏览器/API/API3/Bing`实时切换)
> #### API模式和浏览器模式如何选择
>
> * API模式会调用OpenAI官方提供的gpt-3.5-turbo APIChatGPT官网同款模型只需要提供API Key。一般情况下该种方式响应速度更快可配置项多且不会像chatGPT官网一样总出现不可用的现象但注意API调用是收费的新用户有18美元试用金可用于支付价格为`$0.0020/1K tokens`。(问题和回答**加起来**算token
> * API3模式会调用第三方提供的官网反代API他会帮你绕过CF防护需要提供ChatGPT的Token。效果与官网和浏览器一致但稳定性不一定。发送#chatgpt设置token来设置token
> * (Deprecated)浏览器模式通过在本地启动Chrome等浏览器模拟用户访问ChatGPT网站使得获得和官方以及API2模式一模一样的回复质量同时保证安全性。缺点是本方法对环境要求较高需要提供桌面环境和一个可用的代理能够访问ChatGPT的IP地址且响应速度不如API而且高峰期容易无法使用。一般作为API3的下位替代。
> * 必应Bing将调用微软新必应接口进行对话。需要在必应网页能够正常使用新必应且设置有效的Bing登录Cookie方可使用。强烈推荐
1. 进入 Yunzai根目录
2. 请将 chatgpt-plugin 放置在 Yunzai-Bot 的 plugins 目录下
@ -81,12 +73,8 @@ pnpm i
如果是手工下载的 zip 压缩包,请将解压后的 chatgpt-plugin 文件夹(请删除压缩自带的-master或版本号后缀放置在 Yunzai-Bot 目录下的 plugins 文件夹内
> ~~浏览器模式仅为备选,如您需要使用浏览器模式,您还需要有**桌面环境**优先级建议API≈必应>API3>浏览器~~\
> ~~2.20更新必应被大削变得蠢了建议还是API/API3优先~~\
> 4.2更新必应站起来了必应天下第一。建议都用必应别用API/API3了。浏览器模式除非极其特殊的需求否则强烈建议不使用已经不维护了。
3. 修改配置
**本插件配置项比较多,强烈建议使用后台面板或[锅巴面板](https://github.com/guoba-yunzai/Guoba-Plugin)修改**
**本插件配置项比较多,强烈建议使用后台工具箱或[锅巴面板](https://github.com/guoba-yunzai/Guoba-Plugin)修改**
或者创建和编辑config/config.json文件。

View file

@ -1,76 +1,83 @@
import plugin from '../../../lib/plugins/plugin.js'
import _ from 'lodash'
import { Config, defaultOpenAIAPI } from '../utils/config.js'
import { v4 as uuid } from 'uuid'
import {Config, defaultOpenAIAPI} from '../utils/config.js'
import {v4 as uuid} from 'uuid'
import delay from 'delay'
import { ChatGPTAPI } from '../utils/openai/chatgpt-api.js'
import { BingAIClient } from '@waylaidwanderer/chatgpt-api'
import {ChatGPTAPI} from '../utils/openai/chatgpt-api.js'
import {BingAIClient} from '@waylaidwanderer/chatgpt-api'
import SydneyAIClient from '../utils/SydneyAIClient.js'
import { PoeClient } from '../utils/poe/index.js'
import {PoeClient} from '../utils/poe/index.js'
import AzureTTS from '../utils/tts/microsoft-azure.js'
import VoiceVoxTTS from '../utils/tts/voicevox.js'
import Version from '../utils/version.js'
import {
render,
renderUrl,
getMessageById,
makeForwardMsg,
upsertMessage,
randomString,
completeJSON,
isImage,
getUserData,
extractContentFromFile,
formatDate,
formatDate2,
generateAudio,
getDefaultReplySetting,
isCN,
getMasterQQ,
getUserReplySetting,
getImageOcrText,
getImg,
getMaxModelTokens, formatDate, generateAudio, formatDate2, mkdirs
getMasterQQ,
getMaxModelTokens,
getMessageById,
getUin,
getUserData,
getUserReplySetting,
isCN,
isImage,
makeForwardMsg,
randomString,
render,
renderUrl,
upsertMessage
} from '../utils/common.js'
import { ChatGPTPuppeteer } from '../utils/browser.js'
import { KeyvFile } from 'keyv-file'
import { OfficialChatGPTClient } from '../utils/message.js'
import {ChatGPTPuppeteer} from '../utils/browser.js'
import {KeyvFile} from 'keyv-file'
import {OfficialChatGPTClient} from '../utils/message.js'
import fetch from 'node-fetch'
import { deleteConversation, getConversations, getLatestMessageIdByConversationId } from '../utils/conversation.js'
import { convertSpeaker, speakers } from '../utils/tts.js'
import {deleteConversation, getConversations, getLatestMessageIdByConversationId} from '../utils/conversation.js'
import {convertSpeaker, speakers} from '../utils/tts.js'
import ChatGLMClient from '../utils/chatglm.js'
import { convertFaces } from '../utils/face.js'
import { SlackClaudeClient } from '../utils/slack/slackClient.js'
import { getPromptByName } from '../utils/prompts.js'
import {convertFaces} from '../utils/face.js'
import {SlackClaudeClient} from '../utils/slack/slackClient.js'
import {getPromptByName} from '../utils/prompts.js'
import BingDrawClient from '../utils/BingDraw.js'
import XinghuoClient from '../utils/xinghuo/xinghuo.js'
import Bard from '../utils/bard.js'
import { JinyanTool } from '../utils/tools/JinyanTool.js'
import { SendVideoTool } from '../utils/tools/SendBilibiliTool.js'
import { KickOutTool } from '../utils/tools/KickOutTool.js'
import { EditCardTool } from '../utils/tools/EditCardTool.js'
import { SearchVideoTool } from '../utils/tools/SearchBilibiliTool.js'
import { SearchMusicTool } from '../utils/tools/SearchMusicTool.js'
import { QueryStarRailTool } from '../utils/tools/QueryStarRailTool.js'
import { WebsiteTool } from '../utils/tools/WebsiteTool.js'
import { WeatherTool } from '../utils/tools/WeatherTool.js'
import { SerpTool } from '../utils/tools/SerpTool.js'
import { SerpIkechan8370Tool } from '../utils/tools/SerpIkechan8370Tool.js'
import { SendPictureTool } from '../utils/tools/SendPictureTool.js'
import { SerpImageTool } from '../utils/tools/SearchImageTool.js'
import { ImageCaptionTool } from '../utils/tools/ImageCaptionTool.js'
import { SendAudioMessageTool } from '../utils/tools/SendAudioMessageTool.js'
import { ProcessPictureTool } from '../utils/tools/ProcessPictureTool.js'
import { APTool } from '../utils/tools/APTool.js'
import { QueryGenshinTool } from '../utils/tools/QueryGenshinTool.js'
import { HandleMessageMsgTool } from '../utils/tools/HandleMessageMsgTool.js'
import { QueryUserinfoTool } from '../utils/tools/QueryUserinfoTool.js'
import { EliMovieTool } from '../utils/tools/EliMovieTool.js'
import { EliMusicTool } from '../utils/tools/EliMusicTool.js'
import { SendMusicTool } from '../utils/tools/SendMusicTool.js'
import { SendDiceTool } from '../utils/tools/SendDiceTool.js'
import { SendAvatarTool } from '../utils/tools/SendAvatarTool.js'
import { SendMessageToSpecificGroupOrUserTool } from '../utils/tools/SendMessageToSpecificGroupOrUserTool.js'
import { SetTitleTool } from '../utils/tools/SetTitleTool.js'
import { solveCaptchaOneShot } from '../utils/bingCaptcha.js'
import { ClaudeAIClient } from '../utils/claude.ai/index.js'
import fs from 'fs'
import { getProxy } from '../utils/proxy.js'
import {JinyanTool} from '../utils/tools/JinyanTool.js'
import {SendVideoTool} from '../utils/tools/SendBilibiliTool.js'
import {KickOutTool} from '../utils/tools/KickOutTool.js'
import {EditCardTool} from '../utils/tools/EditCardTool.js'
import {SearchVideoTool} from '../utils/tools/SearchBilibiliTool.js'
import {SearchMusicTool} from '../utils/tools/SearchMusicTool.js'
import {QueryStarRailTool} from '../utils/tools/QueryStarRailTool.js'
import {WebsiteTool} from '../utils/tools/WebsiteTool.js'
import {WeatherTool} from '../utils/tools/WeatherTool.js'
import {SerpTool} from '../utils/tools/SerpTool.js'
import {SerpIkechan8370Tool} from '../utils/tools/SerpIkechan8370Tool.js'
import {SendPictureTool} from '../utils/tools/SendPictureTool.js'
import {SerpImageTool} from '../utils/tools/SearchImageTool.js'
import {ImageCaptionTool} from '../utils/tools/ImageCaptionTool.js'
import {SendAudioMessageTool} from '../utils/tools/SendAudioMessageTool.js'
import {ProcessPictureTool} from '../utils/tools/ProcessPictureTool.js'
import {APTool} from '../utils/tools/APTool.js'
import {QueryGenshinTool} from '../utils/tools/QueryGenshinTool.js'
import {HandleMessageMsgTool} from '../utils/tools/HandleMessageMsgTool.js'
import {QueryUserinfoTool} from '../utils/tools/QueryUserinfoTool.js'
import {EliMovieTool} from '../utils/tools/EliMovieTool.js'
import {EliMusicTool} from '../utils/tools/EliMusicTool.js'
import {SendMusicTool} from '../utils/tools/SendMusicTool.js'
import {SendDiceTool} from '../utils/tools/SendDiceTool.js'
import {SendAvatarTool} from '../utils/tools/SendAvatarTool.js'
import {SendMessageToSpecificGroupOrUserTool} from '../utils/tools/SendMessageToSpecificGroupOrUserTool.js'
import {SetTitleTool} from '../utils/tools/SetTitleTool.js'
import {solveCaptchaOneShot} from '../utils/bingCaptcha.js'
import {ClaudeAIClient} from '../utils/claude.ai/index.js'
import {getProxy} from '../utils/proxy.js'
import {QwenApi} from '../utils/alibaba/qwen-api.js'
import {getChatHistoryGroup} from '../utils/chat.js'
try {
await import('@azure/openai')
@ -178,6 +185,12 @@ export class chatgpt extends plugin {
reg: '^#星火(搜索|查找)助手',
fnc: 'searchxhBot'
},
{
/** 命令正则匹配 */
reg: '^#qwen[sS]*',
/** 执行方法 */
fnc: 'qwen'
},
{
/** 命令正则匹配 */
reg: toggleMode === 'at' ? '^[^#][sS]*' : '^#chat[^gpt][sS]*',
@ -315,7 +328,7 @@ export class chatgpt extends plugin {
}
let ats = e.message.filter(m => m.type === 'at')
const isAtMode = Config.toggleMode === 'at'
if (isAtMode) ats = ats.filter(item => item.qq !== Bot.uin)
if (isAtMode) ats = ats.filter(item => item.qq !== getUin(e))
if (ats.length === 0) {
if (use === 'api3') {
await redis.del(`CHATGPT:QQ_CONVERSATION:${(e.isGroup && Config.groupMerge) ? e.group_id.toString() : e.sender.user_id}`)
@ -365,6 +378,14 @@ export class chatgpt extends plugin {
await redis.del(`CHATGPT:CONVERSATIONS:${e.sender.user_id}`)
await this.reply('已结束当前对话,请@我进行聊天以开启新的对话', true)
}
} else if (use === 'qwen') {
let c = await redis.get(`CHATGPT:CONVERSATIONS_QWEN:${e.sender.user_id}`)
if (!c) {
await this.reply('当前没有开启对话', true)
} else {
await redis.del(`CHATGPT:CONVERSATIONS_QWEN:${e.sender.user_id}`)
await this.reply('已结束当前对话,请@我进行聊天以开启新的对话', true)
}
} else if (use === 'bing') {
let c = await redis.get(`CHATGPT:CONVERSATIONS_BING:${e.sender.user_id}`)
if (!c) {
@ -426,6 +447,14 @@ export class chatgpt extends plugin {
await redis.del(`CHATGPT:CONVERSATIONS:${qq}`)
await this.reply(`已结束${atUser}的对话TA仍可以@我进行聊天以开启新的对话`, true)
}
} else if (use === 'qwen') {
let c = await redis.get(`CHATGPT:CONVERSATIONS_QWEN:${qq}`)
if (!c) {
await this.reply(`当前${atUser}没有开启对话`, true)
} else {
await redis.del(`CHATGPT:CONVERSATIONS_QWEN:${qq}`)
await this.reply(`已结束${atUser}的对话TA仍可以@我进行聊天以开启新的对话`, true)
}
} else if (use === 'bing') {
let c = await redis.get(`CHATGPT:CONVERSATIONS_BING:${qq}`)
if (!c) {
@ -537,6 +566,18 @@ export class chatgpt extends plugin {
}
break
}
case 'qwen': {
let qcs = await redis.keys('CHATGPT:CONVERSATIONS_QWEN:*')
for (let i = 0; i < qcs.length; i++) {
await redis.del(qcs[i])
// todo clean last message id
if (Config.debug) {
logger.info('delete qwen conversation bind: ' + qcs[i])
}
deleted++
}
break
}
}
await this.reply(`结束了${deleted}个用户的对话。`, true)
}
@ -548,7 +589,7 @@ export class chatgpt extends plugin {
await this.reply('本功能当前仅支持API3模式', true)
return false
}
if (ats.length === 0 || (ats.length === 1 && e.atme)) {
if (ats.length === 0 || (ats.length === 1 && (e.atme || e.atBot))) {
let conversationId = _.trimStart(e.msg, '#chatgpt删除对话').trim()
if (!conversationId) {
await this.reply('指令格式错误请同时加上对话id或@某人以删除他当前进行的对话', true)
@ -756,19 +797,21 @@ export class chatgpt extends plugin {
* #chatgpt
*/
async chatgpt (e) {
let msg = Version.isTrss ? e.msg : e.raw_message
let prompt
if (this.toggleMode === 'at') {
if (!e.raw_message || e.msg?.startsWith('#')) {
if (!msg || e.msg?.startsWith('#')) {
return false
}
if (e.isGroup && !e.atme) {
if ((e.isGroup || e.group_id) && !(e.atme || e.atBot)) {
return false
}
if (e.user_id == Bot.uin) return false
prompt = e.raw_message.trim()
if (e.user_id == getUin(e)) return false
prompt = msg.trim()
try {
if (e.isGroup && typeof this.e.group.getMemberMap === 'function') {
let mm = await this.e.group.getMemberMap()
let me = mm.get(Bot.uin)
let me = mm.get(getUin(e)) || {}
let card = me.card
let nickname = me.nickname
if (nickname && card) {
@ -795,9 +838,12 @@ export class chatgpt extends plugin {
prompt = prompt.replace(`@${card}`, '').trim()
}
}
} catch (err) {
logger.warn(err)
}
} else {
let ats = e.message.filter(m => m.type === 'at')
if (!e.atme && ats.length > 0) {
if (!(e.atme || e.atBot) && ats.length > 0) {
if (Config.debug) {
logger.mark('艾特别人了,没艾特我,忽略#chat')
}
@ -1023,6 +1069,10 @@ export class chatgpt extends plugin {
key = `CHATGPT:CONVERSATIONS_AZURE:${e.sender.user_id}`
break
}
case 'qwen': {
key = `CHATGPT:CONVERSATIONS_QWEN:${(e.isGroup && Config.groupMerge) ? e.group_id.toString() : e.sender.user_id}`
break
}
}
let ctime = new Date()
previousConversation = (key ? await redis.get(key) : null) || JSON.stringify({
@ -1053,9 +1103,7 @@ export class chatgpt extends plugin {
logger.mark({ conversation })
}
let chatMessage = await this.sendMessage(prompt, conversation, use, e)
if (chatMessage.image) {
this.setContext('solveBingCaptcha', false, 60)
await e.reply([chatMessage.text, segment.image(`base64://${chatMessage.image}`)])
if (chatMessage?.noMsg) {
return false
}
// 处理星火和bard图片
@ -1311,7 +1359,7 @@ export class chatgpt extends plugin {
return false
}
let ats = e.message.filter(m => m.type === 'at')
if (!e.atme && ats.length > 0) {
if (!(e.atme || e.atBot) && ats.length > 0) {
if (Config.debug) {
logger.mark('艾特别人了,没艾特我,忽略#chat1')
}
@ -1330,7 +1378,7 @@ export class chatgpt extends plugin {
return false
}
let ats = e.message.filter(m => m.type === 'at')
if (!e.atme && ats.length > 0) {
if (!(e.atme || e.atBot) && ats.length > 0) {
if (Config.debug) {
logger.mark('艾特别人了,没艾特我,忽略#chat3')
}
@ -1349,7 +1397,7 @@ export class chatgpt extends plugin {
return false
}
let ats = e.message.filter(m => m.type === 'at')
if (!e.atme && ats.length > 0) {
if (!(e.atme || e.atBot) && ats.length > 0) {
if (Config.debug) {
logger.mark('艾特别人了,没艾特我,忽略#chatglm')
}
@ -1368,7 +1416,7 @@ export class chatgpt extends plugin {
return false
}
let ats = e.message.filter(m => m.type === 'at')
if (!e.atme && ats.length > 0) {
if (!(e.atme || e.atBot) && ats.length > 0) {
if (Config.debug) {
logger.mark('艾特别人了,没艾特我,忽略#bing')
}
@ -1387,7 +1435,7 @@ export class chatgpt extends plugin {
return false
}
let ats = e.message.filter(m => m.type === 'at')
if (!e.atme && ats.length > 0) {
if (!(e.atme || e.atBot) && ats.length > 0) {
if (Config.debug) {
logger.mark('艾特别人了,没艾特我,忽略#claude2')
}
@ -1406,7 +1454,7 @@ export class chatgpt extends plugin {
return false
}
let ats = e.message.filter(m => m.type === 'at')
if (!e.atme && ats.length > 0) {
if (!(e.atme || e.atBot) && ats.length > 0) {
if (Config.debug) {
logger.mark('艾特别人了,没艾特我,忽略#claude')
}
@ -1420,12 +1468,31 @@ export class chatgpt extends plugin {
return true
}
async qwen (e) {
if (!Config.allowOtherMode) {
return false
}
let ats = e.message.filter(m => m.type === 'at')
if (!(e.atme || e.atBot) && ats.length > 0) {
if (Config.debug) {
logger.mark('艾特别人了,没艾特我,忽略#xh')
}
return false
}
let prompt = _.replace(e.raw_message.trimStart(), '#qwen', '').trim()
if (prompt.length === 0) {
return false
}
await this.abstractChat(e, prompt, 'qwen')
return true
}
async xh (e) {
if (!Config.allowOtherMode) {
return false
}
let ats = e.message.filter(m => m.type === 'at')
if (!e.atme && ats.length > 0) {
if (!(e.atme || e.atBot) && ats.length > 0) {
if (Config.debug) {
logger.mark('艾特别人了,没艾特我,忽略#xh')
}
@ -1464,7 +1531,7 @@ export class chatgpt extends plugin {
chatViewBotName: Config.chatViewBotName || '',
entry: cacheData.file,
userImg: `https://q1.qlogo.cn/g?b=qq&s=0&nk=${e.sender.user_id}`,
botImg: `https://q1.qlogo.cn/g?b=qq&s=0&nk=${Bot.uin}`,
botImg: `https://q1.qlogo.cn/g?b=qq&s=0&nk=${getUin(e)}`,
cacheHost: Config.serverHost,
qq: e.sender.user_id
})
@ -1573,33 +1640,33 @@ export class chatgpt extends plugin {
opt.qq = e.sender.user_id
opt.nickname = e.sender.card
opt.groupName = e.group.name
opt.botName = e.isGroup ? (e.group.pickMember(Bot.uin).card || e.group.pickMember(Bot.uin).nickname) : Bot.nickname
opt.botName = e.isGroup ? (e.group.pickMember(getUin(e)).card || e.group.pickMember(getUin(e)).nickname) : e.bot.nickname
let master = (await getMasterQQ())[0]
if (master && e.group) {
opt.masterName = e.group.pickMember(parseInt(master)).card || e.group.pickMember(parseInt(master)).nickname
}
if (master && !e.group) {
opt.masterName = Bot.getFriendList().get(parseInt(master))?.nickname
opt.masterName = e.bot.getFriendList().get(parseInt(master))?.nickname
}
let latestChat = await e.group.getChatHistory(0, 1)
let seq = latestChat[0].seq
let chats = []
while (chats.length < Config.groupContextLength) {
let chatHistory = await e.group.getChatHistory(seq, 20)
chats.push(...chatHistory)
}
chats = chats.slice(0, Config.groupContextLength)
let mm = await e.group.getMemberMap()
chats.forEach(chat => {
let sender = mm.get(chat.sender.user_id)
chat.sender = sender
})
// console.log(chats)
opt.chats = chats
opt.chats = await getChatHistoryGroup(e, Config.groupContextLength)
} catch (err) {
logger.warn('获取群聊聊天记录失败,本次对话不携带聊天记录', err)
}
}
let toSummaryFileContent
try {
if (e.source) {
let msgs = e.isGroup ? await e.group.getChatHistory(e.source.seq, 1) : await e.friend.getChatHistory(e.source.time, 1)
let sourceMsg = msgs[0]
let fileMsgElem = sourceMsg.message.find(msg => msg.type === 'file')
if (fileMsgElem) {
toSummaryFileContent = await extractContentFromFile(fileMsgElem, e)
}
}
} catch (err) {
logger.warn('读取文件内容出错, 忽略文件内容', err)
}
opt.toSummaryFileContent = toSummaryFileContent
} else {
// 重新创建client因为token可能换到别的了
if (bingToken?.indexOf('=') > -1) {
@ -1652,6 +1719,13 @@ export class chatgpt extends plugin {
if (Config.debug) {
logger.mark(`开始生成内容:${response.details.imageTag}`)
}
if (Config.bingAPDraw) {
// 调用第三方API进行绘图
let apDraw = new APTool()
apDraw.func({
prompt: response.details.imageTag
}, e)
} else {
let client = new BingDrawClient({
baseUrl: Config.sydneyReverseProxy,
userToken: bingToken
@ -1664,6 +1738,7 @@ export class chatgpt extends plugin {
await e.reply('绘图失败:' + err)
}
}
}
// 如果token曾经有异常则清除异常
let Tokens = JSON.parse((await redis.get('CHATGPT:BING_TOKENS')) || '[]')
@ -1680,7 +1755,7 @@ export class chatgpt extends plugin {
const { maxConv } = error
if (message && typeof message === 'string' && message.indexOf('CaptchaChallenge') > -1) {
if (bingToken) {
if (maxConv > 20) {
if (maxConv >= 20) {
// maxConv为30说明token有效可以通过解验证码码服务过码
await e.reply('出现必应验证码,尝试解决中')
try {
@ -1699,8 +1774,11 @@ export class chatgpt extends plugin {
}
} else {
// 未登录用户maxConv目前为5或10出验证码没救
logger.warn(`token [${bingToken}] 无效或已过期`)
logger.warn(`token [${bingToken}] 无效或已过期如确认token无误请前往网页版必应对话一次`)
retry = 0
}
} else {
retry = 0
}
} else
if (message && typeof message === 'string' && message.indexOf('限流') > -1) {
@ -1756,10 +1834,10 @@ export class chatgpt extends plugin {
text: errorMessage,
error: true
}
} else {
} else if (response?.response) {
return {
text: response?.response,
quote: response.quote,
quote: response?.quote,
suggestedResponses: response.suggestedResponses,
conversationId: response.conversationId,
clientId: response.clientId,
@ -1768,6 +1846,11 @@ export class chatgpt extends plugin {
parentMessageId: response.apology ? conversation.parentMessageId : response.messageId,
bingToken
}
} else {
logger.debug('no message')
return {
noMsg: true
}
}
}
case 'api3': {
@ -1856,40 +1939,30 @@ export class chatgpt extends plugin {
debug: Config.debug,
proxy: Config.proxy
})
let fileUrl, filename, attachments
if (e.source && e.source.message === '[文件]') {
if (e.isGroup) {
let source = (await e.group.getChatHistory(e.source.seq, 1))[0]
let file = source.message.find(m => m.type === 'file')
if (file) {
filename = file.name
fileUrl = await e.group.getFileUrl(file.fid)
}
} else {
let source = (await e.friend.getChatHistory(e.source.time, 1))[0]
let file = source.message.find(m => m.type === 'file')
if (file) {
filename = file.name
fileUrl = await e.group.getFileUrl(file.fid)
let toSummaryFileContent
try {
if (e.source) {
let msgs = e.isGroup ? await e.group.getChatHistory(e.source.seq, 1) : await e.friend.getChatHistory(e.source.time, 1)
let sourceMsg = msgs[0]
let fileMsgElem = sourceMsg.message.find(msg => msg.type === 'file')
if (fileMsgElem) {
toSummaryFileContent = await extractContentFromFile(fileMsgElem, e)
}
}
} catch (err) {
logger.warn('读取文件内容出错, 忽略文件内容', err)
}
if (fileUrl) {
logger.info('文件地址:' + fileUrl)
mkdirs('data/chatgpt/files')
let destinationPath = 'data/chatgpt/files/' + filename
const response = await fetch(fileUrl)
const fileStream = fs.createWriteStream(destinationPath)
await new Promise((resolve, reject) => {
response.body.pipe(fileStream)
response.body.on('error', (err) => {
reject(err)
let attachments = []
if (toSummaryFileContent?.content) {
attachments.push({
extracted_content: toSummaryFileContent.content,
file_name: toSummaryFileContent.name,
file_type: 'pdf',
file_size: 200312,
totalPages: 20
})
fileStream.on('finish', () => {
resolve()
})
})
attachments = [await client.convertDocument(destinationPath, filename)]
logger.info(toSummaryFileContent.content)
}
if (conversationId) {
return await client.sendMessage(prompt, conversationId, attachments)
@ -1939,6 +2012,57 @@ export class chatgpt extends plugin {
let completion = choices[0].message
return { text: completion.content, message: completion }
}
case 'qwen': {
let completionParams = {
parameters: {
top_p: Config.qwenTopP || 0.5,
top_k: Config.qwenTopK || 50,
seed: Config.qwenSeed > 0 ? Config.qwenSeed : Math.floor(Math.random() * 114514),
temperature: Config.qwenTemperature || 1,
enable_search: !!Config.qwenEnableSearch
}
}
if (Config.qwenModel) {
completionParams.model = Config.qwenModel
}
const currentDate = new Date().toISOString().split('T')[0]
async function um (message) {
return await upsertMessage(message, 'QWEN')
}
async function gm (id) {
return await getMessageById(id, 'QWEN')
}
let opts = {
apiKey: Config.qwenApiKey,
debug: false,
upsertMessage: um,
getMessageById: gm,
systemMessage: `You are ${Config.assistantLabel} ${useCast?.api || Config.promptPrefixOverride || defaultPropmtPrefix}
Current date: ${currentDate}`,
completionParams,
assistantLabel: Config.assistantLabel,
fetch: newFetch
}
this.qwenApi = new QwenApi(opts)
let option = {
timeoutMs: 600000,
completionParams
}
if (conversation) {
if (!conversation.conversationId) {
conversation.conversationId = uuid()
}
option = Object.assign(option, conversation)
}
let msg
try {
msg = await this.qwenApi.sendMessage(prompt, option)
} catch (err) {
logger.error(err)
throw new Error(err)
}
return msg
}
case 'bard': {
// 处理cookie
const matchesPSID = /__Secure-1PSID=([^;]+)/.exec(Config.bardPsid)
@ -2005,30 +2129,16 @@ export class chatgpt extends plugin {
opt.groupId = e.group_id
opt.qq = e.sender.user_id
opt.nickname = e.sender.card
opt.groupName = e.group.name
opt.botName = e.isGroup ? (e.group.pickMember(Bot.uin).card || e.group.pickMember(Bot.uin).nickname) : Bot.nickname
opt.groupName = e.group.name || e.group_name
opt.botName = e.isGroup ? (e.group.pickMember(getUin(e)).card || e.group.pickMember(getUin(e)).nickname) : e.bot.nickname
let master = (await getMasterQQ())[0]
if (master && e.group) {
opt.masterName = e.group.pickMember(parseInt(master)).card || e.group.pickMember(parseInt(master)).nickname
}
if (master && !e.group) {
opt.masterName = Bot.getFriendList().get(parseInt(master))?.nickname
opt.masterName = e.bot.getFriendList().get(parseInt(master))?.nickname
}
let latestChat = await e.group.getChatHistory(0, 1)
let seq = latestChat[0].seq
let chats = []
while (chats.length < Config.groupContextLength) {
let chatHistory = await e.group.getChatHistory(seq, 20)
chats.push(...chatHistory.reverse())
}
chats = chats.slice(0, Config.groupContextLength)
// 太多可能会干扰AI对自身qq号和用户qq的判断感觉gpt3.5也处理不了那么多信息
chats = chats > 50 ? 50 : chats
let mm = await e.group.getMemberMap()
chats.forEach(chat => {
let sender = mm.get(chat.sender.user_id)
chat.sender = sender
})
let chats = await getChatHistoryGroup(e, Config.groupContextLength)
opt.chats = chats
const namePlaceholder = '[name]'
const defaultBotName = 'ChatGPT'
@ -2050,7 +2160,7 @@ export class chatgpt extends plugin {
system += chats
.map(chat => {
let sender = chat.sender || {}
// if (sender.user_id === Bot.uin && chat.raw_message.startsWith('建议的回复')) {
// if (sender.user_id === e.bot.uin && chat.raw_message.startsWith('建议的回复')) {
if (chat.raw_message.startsWith('建议的回复')) {
// 建议的回复太容易污染设定导致对话太固定跑偏了
return ''
@ -2097,6 +2207,9 @@ export class chatgpt extends plugin {
}
option.systemMessage = system
if (conversation) {
if (!conversation.conversationId) {
conversation.conversationId = uuid()
}
option = Object.assign(option, conversation)
}
if (Config.smartMode) {
@ -2178,7 +2291,7 @@ export class chatgpt extends plugin {
logger.mark(logger.green('【ChatGPT-Plugin】插件avocado-plugin未安装') + ',安装后可查看最近热映电影与体验可玩性更高的点歌工具。\n可前往 https://github.com/Qz-Sean/avocado-plugin 获取')
}
if (e.isGroup) {
let botInfo = await Bot.getGroupMemberInfo(e.group_id, Bot.uin, true)
let botInfo = await e.bot.getGroupMemberInfo(e.group_id, getUin(e), true)
if (botInfo.role !== 'member') {
// 管理员才给这些工具
tools.push(...[new EditCardTool(), new JinyanTool(), new KickOutTool(), new HandleMessageMsgTool(), new SetTitleTool()])
@ -2430,7 +2543,7 @@ export class chatgpt extends plugin {
}
if (bots.code === 0) {
if (bots.data.pageList.length > 0) {
this.reply(await makeForwardMsg(this.e, bots.data.pageList.map(msg => `${msg.bot.botId} - ${msg.bot.botName}`)))
this.reply(await makeForwardMsg(this.e, bots.data.pageList.map(msg => `${msg.e.bot.botId} - ${msg.e.bot.botName}`)))
} else {
await e.reply('未查到相关助手', true)
}

View file

@ -50,6 +50,10 @@ export class Entertainment extends plugin {
reg: '^#(|最新)词云(\\d{1,2}h{0,1}|)$',
fnc: 'wordcloud_latest'
},
{
reg: '^#(我的)?(本月|本周|今日)?词云$',
fnc: 'wordcloud_new'
},
{
reg: '^#((寄批踢|gpt|GPT)?翻.*|chatgpt翻译帮助)',
fnc: 'translate'
@ -218,7 +222,7 @@ ${translateLangLabels}
const duration = !match[1] ? 12 : parseInt(match[1]) // default 12h
if (duration > 24) {
await e.reply('最多只能统计24小时内的记录哦')
await e.reply('最多只能统计24小时内的记录哦,你可以使用#本周词云和#本月词云获取更长时间的统计~')
return false
}
await e.reply('在统计啦,请稍等...')
@ -236,6 +240,56 @@ ${translateLangLabels}
}
}
async wordcloud_new (e) {
if (e.isGroup) {
let groupId = e.group_id
let userId
if (e.msg.includes('我的')) {
userId = e.sender.user_id
}
let at = e.message.find(m => m.type === 'at')
if (at) {
userId = at.qq
}
let lock = await redis.get(`CHATGPT:WORDCLOUD_NEW:${groupId}_${userId}`)
if (lock) {
await e.reply('别着急,上次统计还没完呢')
return true
}
await e.reply('在统计啦,请稍等...')
let duration = 24
if (e.msg.includes('本周')) {
const now = new Date() // Get the current date and time
let day = now.getDay()
let diff = now.getDate() - day + (day === 0 ? -6 : 1)
const startOfWeek = new Date(new Date().setDate(diff))
startOfWeek.setHours(0, 0, 0, 0) // Set the time to midnight (start of the day)
duration = (now - startOfWeek) / 1000 / 60 / 60
} else if (e.msg.includes('本月')) {
const now = new Date() // Get the current date and time
const startOfMonth = new Date(new Date().setDate(0))
startOfMonth.setHours(0, 0, 0, 0) // Set the time to midnight (start of the day)
duration = (now - startOfMonth) / 1000 / 60 / 60
} else {
// 默认今天
const now = new Date()
const startOfToday = new Date() // Get the current date and time
startOfToday.setHours(0, 0, 0, 0) // Set the time to midnight (start of the day)
duration = (now - startOfToday) / 1000 / 60 / 60
}
await redis.set(`CHATGPT:WORDCLOUD_NEW:${groupId}_${userId}`, '1', { EX: 600 })
try {
await makeWordcloud(e, e.group_id, duration, userId)
} catch (err) {
logger.error(err)
await e.reply(err)
}
await redis.del(`CHATGPT:WORDCLOUD_NEW:${groupId}_${userId}`)
} else {
await e.reply('请在群里发送此命令')
}
}
async combineEmoj (e) {
let left = e.msg.codePointAt(0).toString(16).toLowerCase()
let right = e.msg.codePointAt(2).toString(16).toLowerCase()
@ -296,7 +350,7 @@ ${translateLangLabels}
let groupId = e.msg.replace(/^#chatgpt打招呼/, '')
logger.info(groupId)
groupId = parseInt(groupId)
if (groupId && !Bot.getGroupList().get(groupId)) {
if (groupId && !e.bot.getGroupList().get(groupId)) {
await e.reply('机器人不在这个群里!')
return
}
@ -310,7 +364,7 @@ ${translateLangLabels}
if (!groupId) {
await e.reply(sendable)
} else {
await Bot.sendGroupMsg(groupId, sendable)
await e.bot.sendGroupMsg(groupId, sendable)
await e.reply('发送成功!')
}
}
@ -325,7 +379,7 @@ ${translateLangLabels}
continue
}
let groupId = parseInt(element)
if (Bot.getGroupList().get(groupId)) {
if (this.e.bot.getGroupList().get(groupId)) {
// 打招呼概率
if (Math.floor(Math.random() * 100) < Config.helloProbability) {
let message = await generateHello()
@ -381,12 +435,12 @@ ${translateLangLabels}
}
}
if (useSilk) {
await Bot.sendGroupMsg(groupId, await uploadRecord(audio))
await this.e.bot.sendGroupMsg(groupId, await uploadRecord(audio))
} else {
await Bot.sendGroupMsg(groupId, segment.record(audio))
await this.e.bot.sendGroupMsg(groupId, segment.record(audio))
}
} else {
await Bot.sendGroupMsg(groupId, message)
await this.e.bot.sendGroupMsg(groupId, message)
}
} else {
logger.info(`时机未到,这次就不打招呼给群聊${groupId}`)

View file

@ -1,5 +1,5 @@
import plugin from '../../../lib/plugins/plugin.js'
import { render } from '../utils/common.js'
import { render, getUin } from '../utils/common.js'
import { Config } from '../utils/config.js'
import { KeyvFile } from 'keyv-file'
@ -32,7 +32,7 @@ export class history extends plugin {
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 filtered = e.message.filter(m => m.type === 'at').filter(m => m.qq !== getUin(e))
let queryUser = e.sender.user_id
let user = e.sender
if (filtered.length > 0) {
@ -99,8 +99,8 @@ export class history extends plugin {
name: user.card || user.nickname || user.user_id
},
bot: {
qq: Bot.uin,
name: Bot.nickname
qq: getUin(e),
name: e.bot.nickname
},
chat
}, {})

View file

@ -124,6 +124,11 @@ export class ChatgptManagement extends plugin {
fnc: 'useBardBasedSolution',
permission: 'master'
},
{
reg: '^#chatgpt切换(通义千问|qwen|千问)$',
fnc: 'useQwenSolution',
permission: 'master'
},
{
reg: '^#chatgpt(必应|Bing)切换',
fnc: 'changeBingTone',
@ -876,6 +881,7 @@ azure语音Azure 语音是微软 Azure 平台提供的一项语音服务,
await this.reply('当前已经是星火模式了')
}
}
async useAzureBasedSolution () {
let use = await redis.get('CHATGPT:USE')
if (use !== 'azure') {
@ -896,6 +902,16 @@ azure语音Azure 语音是微软 Azure 平台提供的一项语音服务,
}
}
async useQwenSolution () {
let use = await redis.get('CHATGPT:USE')
if (use !== 'qwen') {
await redis.set('CHATGPT:USE', 'qwen')
await this.reply('已切换到基于通义千问的解决方案')
} else {
await this.reply('当前已经是通义千问模式了')
}
}
async changeBingTone (e) {
let tongStyle = e.msg.replace(/^#chatgpt(必应|Bing)切换/, '')
if (!tongStyle) {
@ -1002,7 +1018,7 @@ Poe 模式会调用 Poe 中的 Claude-instant 进行对话。需要提供 Cookie
}
} else if (match) {
const groupId = parseInt(match[1], 10)
if (Bot.getGroupList().get(groupId)) {
if (e.bot.getGroupList().get(groupId)) {
if (await redis.get(`CHATGPT:SHUT_UP:${groupId}`)) {
await redis.del(`CHATGPT:SHUT_UP:${groupId}`)
await redis.set(`CHATGPT:SHUT_UP:${groupId}`, '1', { EX: time })
@ -1052,7 +1068,7 @@ Poe 模式会调用 Poe 中的 Claude-instant 进行对话。需要提供 Cookie
return false
}
const groupId = parseInt(match[1], 10)
if (Bot.getGroupList().get(groupId)) {
if (e.bot.getGroupList().get(groupId)) {
if (await redis.get(`CHATGPT:SHUT_UP:${groupId}`)) {
await redis.del(`CHATGPT:SHUT_UP:${groupId}`)
await e.reply(`好的主人,我终于又可以在群${groupId}和大家聊天了`)
@ -1287,7 +1303,7 @@ Poe 模式会调用 Poe 中的 Claude-instant 进行对话。需要提供 Cookie
const viewHost = Config.serverHost ? `http://${Config.serverHost}/` : `http://${await getPublicIP()}:${Config.serverPort || 3321}/`
const otp = randomString(6)
await redis.set(
`CHATGPT:SERVER_QUICK`,
'CHATGPT:SERVER_QUICK',
otp,
{ EX: 60000 }
)

View file

@ -2,7 +2,7 @@ import plugin from '../../../lib/plugins/plugin.js'
import fs from 'fs'
import _ from 'lodash'
import { Config } from '../utils/config.js'
import { getMasterQQ, limitString, makeForwardMsg, maskQQ } from '../utils/common.js'
import { getMasterQQ, limitString, makeForwardMsg, maskQQ, getUin } from '../utils/common.js'
import { deleteOnePrompt, getPromptByName, readPrompts, saveOnePrompt } from '../utils/prompts.js'
import AzureTTS from "../utils/tts/microsoft-azure.js";
export class help extends plugin {
@ -157,7 +157,8 @@ export class help extends plugin {
const keyMap = {
api: 'promptPrefixOverride',
Custom: 'sydney',
claude: 'slackClaudeGlobalPreset'
claude: 'slackClaudeGlobalPreset',
qwen: 'promptPrefixOverride'
}
if (keyMap[use]) {
@ -246,7 +247,7 @@ export class help extends plugin {
async removeSharePrompt (e) {
let master = (await getMasterQQ())[0]
let name = e.msg.replace(/^#(chatgpt|ChatGPT)(删除|取消|撤销)共享设定/, '')
let response = await fetch(`https://chatgpt.roki.best/prompt?name=${name}&qq=${master || (Bot.uin + '')}`, {
let response = await fetch(`https://chatgpt.roki.best/prompt?name=${name}&qq=${master || (getUin(e) + '')}`, {
method: 'DELETE',
headers: {
'FROM-CHATGPT': 'ikechan8370'
@ -354,7 +355,7 @@ export class help extends plugin {
let toUploadBody = {
title: currentUse,
prompt: content,
qq: master || (Bot.uin + ''), // 上传者设定为主人qq或机器人qq
qq: master || (getUin(this.e) + ''), // 上传者设定为主人qq或机器人qq
use: extraData.use === 'Custom' ? 'Sydney' : 'ChatGPT',
r18,
description

101
client/BaseClient.js Normal file
View file

@ -0,0 +1,101 @@
/**
* Base LLM Chat Client \
* All the Chat Models should extend this class
*
* @since 2023-10-26
* @author ikechan8370
*/
export class BaseClient {
/**
* create a new client
*
* @param props required fields: e, getMessageById, upsertMessage
*/
constructor (props = {}) {
this.supportFunction = false
this.maxToken = 4096
this.tools = []
const {
e, getMessageById, upsertMessage
} = props
this.e = e
this.getMessageById = getMessageById
this.upsertMessage = upsertMessage
}
/**
* get a message according to the id. note that conversationId is not needed
*
* @type function
* @param {string} id
* @return {Promise<object>} message
*/
getMessageById
/**
* insert or update a message with the id
*
* @type function
* @param {string} id
* @param {object} message
* @return {Promise<void>}
*/
upsertMessage
/**
* Send prompt message with history and return response message \
* if function called, handled internally \
* override this method to implement logic of sending and receiving message
*
* @param msg
* @param opt other options, optional fields: [conversationId, parentMessageId], if not set, random uuid instead
* @returns {Promise<Message>} required fields: [text, conversationId, parentMessageId, id]
*/
async sendMessage (msg, opt = {}) {
throw new Error('not implemented in abstract client')
}
/**
* Get chat history between user and assistant
* override this method to implement logic of getting history
* keyv with local file or redis recommended
*
* @param userId such as qq number
* @param opt other options
* @returns {Promise<void>}
*/
async getHistory (userId, opt = {}) {
throw new Error('not implemented in abstract client')
}
/**
* Destroy a chat history
* @param conversationId conversationId of the chat history
* @param opt other options
* @returns {Promise<void>}
*/
async destroyHistory (conversationId, opt = {}) {
throw new Error('not implemented in abstract client')
}
addTools (...tools) {
if (!this.isSupportFunction) {
throw new Error('function not supported')
}
if (!this.tools) {
this.tools = []
}
this.tools.push(tools)
}
getTools () {
if (!this.isSupportFunction) {
throw new Error('function not supported')
}
return this.tools || []
}
get isSupportFunction () {
return this.supportFunction
}
}

View file

@ -321,7 +321,7 @@ export function supportGuoba () {
{
field: 'model',
label: 'OpenAI 模型',
bottomHelpMessage: 'gpt-4, gpt-4-0613, gpt-4-32k, gpt-4-32k-0613, gpt-3.5-turbo, gpt-3.5-turbo-0613, gpt-3.5-turbo-16k-0613。默认为gpt-3.5-turbogpt-4需账户支持',
bottomHelpMessage: 'gpt-4, gpt-4-0613, gpt-4-1106, gpt-4-32k, gpt-4-32k-0613, gpt-3.5-turbo, gpt-3.5-turbo-0613, gpt-3.5-turbo-1106, gpt-3.5-turbo-16k-0613。默认为gpt-3.5-turbogpt-4需账户支持',
component: 'Input'
},
{
@ -462,7 +462,7 @@ export function supportGuoba () {
{
field: 'sydneyWebsocketUseProxy',
label: '对话使用sydney反代',
bottomHelpMessage: '【一般情况无需也不建议开启】默认情况下仅创建对话走反代,对话时仍然直连微软。开启本选项将使对话过程也走反,需反代支持',
bottomHelpMessage: '默认情况下仅创建对话走反代,对话时仍然直连微软。开启本选项将使对话过程也走反,需反代支持。默认开启',
component: 'Switch'
},
{
@ -511,40 +511,6 @@ export function supportGuoba () {
bottomHelpMessage: '使用GPT-4注意试用配额较低如果用不了就关掉',
component: 'Switch'
},
{
label: '以下为浏览器方式的配置.(Deprecated)',
component: 'Divider'
},
{
field: 'username',
label: '用户名',
bottomHelpMessage: 'OpenAI用户名。',
component: 'Input'
},
{
field: 'password',
label: '密码',
bottomHelpMessage: 'OpenAI密码。',
component: 'InputPassword'
},
{
field: 'UA',
label: '浏览器UA',
bottomHelpMessage: '模拟浏览器UA无特殊需求保持默认即可',
component: 'InputTextArea'
},
{
field: 'headless',
label: '无头模式',
bottomHelpMessage: '无界面的服务器可以开启,但遇到验证码时可能无法使用。(实测很容易卡住,几乎不可用)',
component: 'Switch'
},
{
field: 'chromePath',
label: 'Chrome路径',
bottomHelpMessage: '为空使用默认puppeteer的chromium也可以传递自己本机安装的Chrome可执行文件地址提高通过率。windows可以是C:\\Program Files\\Google\\Chrome\\Application\\chrome.exelinux通过which查找路径',
component: 'Input'
},
{
label: '以下为Slack Claude方式的配置',
component: 'Divider'
@ -631,16 +597,6 @@ export function supportGuoba () {
bottomHelpMessage: '等待响应的超时时间单位为秒默认为120。如果不使用反代而是使用代理可以适当调低。',
component: 'InputNumber'
},
{
label: '以下为ChatGLM方式的配置',
component: 'Divider'
},
{
field: 'chatglmBaseUrl',
label: 'ChatGLM API地址',
bottomHelpMessage: '如 http://localhost:8080',
component: 'Input'
},
{
label: '以下为星火方式的配置',
component: 'Divider'
@ -655,6 +611,7 @@ export function supportGuoba () {
{ label: '体验版', value: 'web' },
{ label: '讯飞星火认知大模型V1.5', value: 'api' },
{ label: '讯飞星火认知大模型V2.0', value: 'apiv2' },
{ label: '讯飞星火认知大模型V3.0', value: 'apiv3' },
{ label: '讯飞星火助手', value: 'assistants' }
]
}
@ -747,6 +704,53 @@ export function supportGuoba () {
bottomHelpMessage: '开启后将通过反代访问bard',
component: 'Switch'
},
{
label: '以下为通义千问API方式的配置',
component: 'Divider'
},
{
field: 'qwenApiKey',
label: '通义千问API Key',
component: 'InputPassword'
},
{
field: 'qwenModel',
label: '通义千问模型',
bottomHelpMessage: '指明需要调用的模型,目前可选 qwen-turbo 和 qwen-plus',
component: 'Input'
},
{
field: 'qwenTopP',
label: '通义千问topP',
bottomHelpMessage: '生成时核采样方法的概率阈值。例如取值为0.8时仅保留累计概率之和大于等于0.8的概率分布中的token作为随机采样的候选集。取值范围为0,1.0),取值越大,生成的随机性越高;取值越低,生成的随机性越低。默认值 0.5。注意取值不要大于等于1',
component: 'InputNumber'
},
{
field: 'qwenTopK',
label: '通义千问topK',
bottomHelpMessage: '生成时采样候选集的大小。例如取值为50时仅将单次生成中得分最高的50个token组成随机采样的候选集。取值越大生成的随机性越高取值越小生成的确定性越高。注意如果top_k的值大于100top_k将采用默认值0表示不启用top_k策略此时仅有top_p策略生效。',
component: 'InputNumber'
},
{
field: 'qwenSeed',
label: '通义千问Seed',
bottomHelpMessage: '生成时随机数的种子用于控制模型生成的随机性。如果使用相同的种子每次运行生成的结果都将相同当需要复现模型的生成结果时可以使用相同的种子。seed参数支持无符号64位整数类型。默认值 0, 表示每次随机生成',
component: 'InputNumber'
},
{
field: 'qwenTemperature',
label: '通义千问温度',
bottomHelpMessage: '用于控制随机性和多样性的程度。具体来说temperature值控制了生成文本时对每个候选词的概率分布进行平滑的程度。较高的temperature值会降低概率分布的峰值使得更多的低概率词被选择生成结果更加多样化而较低的temperature值则会增强概率分布的峰值使得高概率词更容易被选择生成结果更加确定。\n' +
'\n' +
'取值范围: (0, 2),系统默认值1.0',
component: 'InputNumber'
},
{
field: 'qwenEnableSearch',
label: '通义千问允许搜索',
bottomHelpMessage: '生成时是否参考夸克搜索的结果。注意打开搜索并不意味着一定会使用搜索结果如果打开搜索模型会将搜索结果作为prompt进而“自行判断”是否生成结合搜索结果的文本默认为false',
component: 'Switch'
},
{
label: '以下为杂七杂八的配置',
component: 'Divider'

868
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -24,7 +24,7 @@
"js-tiktoken": "^1.0.5",
"keyv": "^4.5.3",
"keyv-file": "^0.2.0",
"microsoft-cognitiveservices-speech-sdk": "^1.30.1",
"microsoft-cognitiveservices-speech-sdk": "1.32.0",
"node-fetch": "^3.3.1",
"openai": "^3.2.1",
"p-timeout": "^6.1.2",
@ -35,14 +35,18 @@
"ws": "^8.13.0"
},
"optionalDependencies": {
"xlsx": "^0.18.5",
"mammoth": "^1.6.0",
"pdfjs-dist": "^3.11.174",
"nodejs-pptx": "^1.2.4",
"@node-rs/jieba": "^1.6.2",
"cycletls": "^1.0.21",
"jimp": "^0.22.7",
"node-silk": "^0.1.0",
"puppeteer-extra": "^3.3.6",
"puppeteer-extra-plugin-recaptcha": "^3.6.8",
"puppeteer-extra-plugin-stealth": "^2.11.2",
"sharp": "^0.32.3",
"cycletls": "^1.0.21"
"sharp": "^0.32.3"
},
"devDependencies": {
"ts-node": "^10.9.1",

View file

@ -122,6 +122,12 @@
"label": "额外工具url",
"placeholder": "测试期间提供一个公益接口,一段时间后撤掉",
"data": "extraUrl"
},
{
"type": "text",
"label": "Trss主账号",
"placeholder": "用于Trss配置脚本时使用的主账号",
"data": "trssBotUin"
}
]
},
@ -630,6 +636,12 @@
"label": "必应验证码pass服务",
"placeholder": "必应出验证码会自动用该服务绕过",
"data": "bingCaptchaOneShotUrl"
},
{
"type": "check",
"label": "第三方绘图",
"placeholder": "使用AP插件代替Bing进行绘图",
"data": "bingAPDraw"
}
]
},
@ -706,6 +718,10 @@
"label": "讯飞星火认知大模型V2.0",
"value": "apiv2"
},
{
"label": "讯飞星火认知大模型V3.0",
"value": "apiv3"
},
{
"label": "讯飞星火助手",
"value": "assistants"

View file

@ -7,16 +7,16 @@ import websocket from '@fastify/websocket'
import fs from 'fs'
import path from 'path'
import os from 'os'
import schedule from 'node-schedule'
import websocketclient from 'ws'
import { Config } from '../utils/config.js'
import { UserInfo, GetUser, AddUser } from './modules/user_data.js'
import { getPublicIP, getUserData, getMasterQQ, randomString } from '../utils/common.js'
import { getPublicIP, getUserData, getMasterQQ, randomString, getUin } from '../utils/common.js'
import webRoute from './modules/web_route.js'
import webUser from './modules/user.js'
import webPrompt from './modules/prompts.js'
import Guoba from './modules/guoba.js'
import SettingView from './modules/setting_view.js'
const __dirname = path.resolve()
@ -24,41 +24,6 @@ const server = fastify({
logger: Config.debug
})
let Statistics = {
SystemAccess: {
count: 0,
oldCount: 0
},
CacheFile: {
count: 0,
oldCount: 0
},
WebAccess: {
count: 0,
oldCount: 0
},
SystemLoad: {
count: 0,
oldCount: 0
}
}
async function getLoad() {
// 获取当前操作系统平台
const platform = os.platform()
// 判断平台是Linux还是Windows
if (platform === 'linux') {
// 如果是Linux使用os.loadavg()方法获取负载平均值
const loadAvg = os.loadavg()
return loadAvg[0] * 100
} else if (platform === 'win32') {
// 如果是Windows不获取性能
return 0
} else {
return 0
}
}
async function setUserData(qq, data) {
const dir = 'resources/ChatGPTCache/user'
const filename = `${qq}.json`
@ -84,6 +49,7 @@ await server.register(webRoute)
await server.register(webUser)
await server.register(SettingView)
await server.register(webPrompt)
await server.register(Guoba)
// 无法访问端口的情况下创建与media的通讯
async function mediaLink() {
@ -107,7 +73,7 @@ async function mediaLink() {
ws.on('open', () => {
ws.send(JSON.stringify({
command: 'register',
region: Bot.uin,
region: getUin(),
type: 'server',
}))
})
@ -118,7 +84,11 @@ async function mediaLink() {
case 'register':
if (data.state) {
let master = (await getMasterQQ())[0]
if (Array.isArray(Bot.uin)) {
Bot.pickFriend(master).sendMsg(`当前chatgpt插件服务无法被外网访问已启用代理链接访问代码${data.token}`)
} else {
Bot.sendPrivateMsg(master, `当前chatgpt插件服务无法被外网访问已启用代理链接访问代码${data.token}`, false)
}
} else {
console.log('注册区域失败')
}
@ -128,30 +98,30 @@ async function mediaLink() {
const user = UserInfo(data.token)
if (user) {
ws.login = true
ws.send(JSON.stringify({ command: data.command, state: true, region: Bot.uin, type: 'server' }))
ws.send(JSON.stringify({ command: data.command, state: true, region: getUin(), type: 'server' }))
} else {
ws.send(JSON.stringify({ command: data.command, state: false, error: '权限验证失败', region: Bot.uin, type: 'server' }))
ws.send(JSON.stringify({ command: data.command, state: false, error: '权限验证失败', region: getUin(), type: 'server' }))
}
}
break
case 'post_login':
if (data.qq && data.passwd) {
const token = randomString(32)
if (data.qq == Bot.uin && await redis.get('CHATGPT:ADMIN_PASSWD') == data.passwd) {
if (data.qq == getUin() && await redis.get('CHATGPT:ADMIN_PASSWD') == data.passwd) {
AddUser({ user: data.qq, token: token, autho: 'admin' })
ws.send(JSON.stringify({ command: data.command, state: true, autho: 'admin', token: token, region: Bot.uin, type: 'server' }))
ws.send(JSON.stringify({ command: data.command, state: true, autho: 'admin', token: token, region: getUin(), type: 'server' }))
} else {
const user = await getUserData(data.qq)
if (user.passwd != '' && user.passwd === data.passwd) {
AddUser({ user: data.qq, token: token, autho: 'user' })
ws.send(JSON.stringify({ command: data.command, state: true, autho: 'user', token: token, region: Bot.uin, type: 'server' }))
ws.send(JSON.stringify({ command: data.command, state: true, autho: 'user', token: token, region: getUin(), type: 'server' }))
} else {
ws.send(JSON.stringify({ command: data.command, state: false, error: `用户名密码错误,如果忘记密码请私聊机器人输入 ${data.qq == Bot.uin ? '#修改管理密码' : '#修改用户密码'} 进行修改`, region: Bot.uin, type: 'server' }))
ws.send(JSON.stringify({ command: data.command, state: false, error: `用户名密码错误,如果忘记密码请私聊机器人输入 ${data.qq == getUin() ? '#修改管理密码' : '#修改用户密码'} 进行修改`, region: getUin(), type: 'server' }))
}
}
} else {
ws.send(JSON.stringify({ command: data.command, state: false, error: '未输入用户名或密码', region: Bot.uin, type: 'server' }))
ws.send(JSON.stringify({ command: data.command, state: false, error: '未输入用户名或密码', region: getUin(), type: 'server' }))
}
break
case 'post_command':
@ -163,7 +133,7 @@ async function mediaLink() {
const response = await fetch(`http://localhost:${Config.serverPort || 3321}${data.postPath}`, fetchOptions)
if (response.ok) {
const json = await response.json()
ws.send(JSON.stringify({ command: data.command, state: true, region: Bot.uin, type: 'server', path: data.postPath, data: json }))
ws.send(JSON.stringify({ command: data.command, state: true, region: getUin(), type: 'server', path: data.postPath, data: json }))
}
break
}
@ -189,7 +159,7 @@ export async function createServer() {
if (body.code) {
const pattern = /^[a-zA-Z0-9]+$/
if (!pattern.test(body.code)) {
reply.send({error: 'bad request'})
reply.send({ error: 'bad request' })
}
const dir = 'resources/ChatGPTCache/page'
const filename = body.code + '.json'
@ -286,7 +256,6 @@ export async function createServer() {
time: data.time
})
await setUserData(body.qq, user)
Statistics.CacheFile.count += 1
reply.send({ file: body.entry, cacheUrl: `http://${ip}:${Config.serverPort || 3321}/page/${body.entry}` })
} catch (err) {
server.log.error(`用户生成缓存${body.entry}时发生错误: ${err}`)
@ -295,12 +264,6 @@ export async function createServer() {
}
return reply
})
// 获取系统状态
server.post('/system-statistics', async (request, reply) => {
Statistics.SystemLoad.count = await getLoad()
reply.send(Statistics)
return reply
})
// 清除缓存数据
server.post('/cleanCache', async (request, reply) => {
@ -329,6 +292,7 @@ export async function createServer() {
connection.socket.send(JSON.stringify(response))
})
connection.socket.on('message', async (message) => {
const isTrss = Array.isArray(Bot.uin)
try {
const data = JSON.parse(message)
const user = UserInfo(data.token)
@ -340,10 +304,18 @@ export async function createServer() {
}
if (data.id && data.message) {
if (data.group) {
if (isTrss) {
Bot[user.user].pickGroup(parseInt(data.id)).sendMsg(data.message)
} else {
Bot.sendGroupMsg(parseInt(data.id), data.message, data.quotable)
}
} else {
if (isTrss) {
Bot[user.user].pickFriend(parseInt(data.id)).sendMsg(data.message)
} else {
Bot.sendPrivateMsg(parseInt(data.id), data.message, data.quotable)
}
}
await connection.socket.send(JSON.stringify({ command: data.command, state: true, }))
} else {
await connection.socket.send(JSON.stringify({ command: data.command, state: false, error: '参数不足' }))
@ -357,7 +329,6 @@ export async function createServer() {
}
break
case 'login': // 登录
if (user) {
clients[user.user] = connection.socket
connection.login = true
@ -371,13 +342,17 @@ export async function createServer() {
await connection.socket.send(JSON.stringify({ command: data.command, state: false, error: '请先登录账号' }))
return
}
if (user.autho != 'admin') {
if (user?.autho != 'admin') {
await connection.socket.send(JSON.stringify({ command: data.command, state: true, error: '普通用户无需进行初始化' }))
return
}
const groupList = Bot.getGroupList()
let _Bot = Bot
if (isTrss) {
_Bot = Bot[user.user]
}
const groupList = await _Bot.getGroupList()
groupList.forEach(async (item) => {
const group = Bot.pickGroup(item.group_id)
const group = _Bot.pickGroup(item.group_id)
const groupMessages = await group.getChatHistory()
groupMessages.forEach(async (e) => {
const messageData = {
@ -402,12 +377,14 @@ export async function createServer() {
await connection.socket.send(JSON.stringify(messageData))
})
})
break
default:
await connection.socket.send(JSON.stringify({ "data": data }))
break
}
} catch (error) {
console.error(error)
await connection.socket.send(JSON.stringify({ "error": error.message }))
}
})
@ -424,7 +401,7 @@ export async function createServer() {
message: e.message,
sender: e.sender,
group: {
isGroup: e.isGroup,
isGroup: e.isGroup || e.group_id != undefined,
group_id: e.group_id,
group_name: e.group_name
},
@ -598,28 +575,6 @@ export async function createServer() {
return reply
})
server.addHook('onRequest', (request, reply, done) => {
if (request.method == 'POST') { Statistics.SystemAccess.count += 1 }
if (request.method == 'GET') { Statistics.WebAccess.count += 1 }
done()
})
// 定时任务
let rule = new schedule.RecurrenceRule()
rule.hour = 0
rule.minute = 0
let job_Statistics = schedule.scheduleJob(rule, function () {
Statistics.SystemAccess.oldCount = Statistics.SystemAccess.count
Statistics.CacheFile.oldCount = Statistics.CacheFile.count
Statistics.WebAccess.oldCount = Statistics.WebAccess.count
Statistics.SystemAccess.count = 0
Statistics.CacheFile.count = 0
Statistics.WebAccess.count = 0
})
let job_Statistics_SystemLoad = schedule.scheduleJob('0 * * * *', async function () {
Statistics.SystemLoad.count = await getLoad()
Statistics.SystemLoad.oldCount = Statistics.SystemLoad.count
})
server.listen({
port: Config.serverPort || 3321,
host: '::'

72
server/modules/guoba.js Normal file
View file

@ -0,0 +1,72 @@
import { UserInfo } from './user_data.js'
async function Guoba(fastify, options) {
// 获取锅巴登陆链接
fastify.post('/guobaLogin', async (request, reply) => {
const token = request.cookies.token || request.body?.token || 'unknown'
let user = UserInfo(token)
if (user && user.autho == 'admin') {
try {
let { LoginService } = await import('../../../Guoba-Plugin/server/service/both/LoginService.js')
const guobaLoginService = new LoginService()
const guobaAPI = await guobaLoginService.setQuickLogin(user.user)
reply.send({ guoba: guobaAPI })
}
catch (err) {
console.error(err)
reply.send({ state: false, error: err })
}
} else {
reply.send({ state: false, error: '用户权限不足' })
}
return reply
})
// 代理锅巴接口
fastify.post('/guobaApi', async (request, reply) => {
const body = request.body || {}
const token = request.cookies.token || request.body?.token || 'unknown'
let user = UserInfo(token)
if (user && user.autho == 'admin' && body.guobaToken) {
try {
let { getAllWebAddress } = await import('../../../Guoba-Plugin/utils/common.js')
const { custom, local, remote } = await getAllWebAddress()
if (local.length > 0) {
const guobaOptions = {
method: body.post ? 'POST' : 'GET',
headers: {
'Content-Type': 'application/json',
'Guoba-Access-Token': body.guobaToken
}
}
if (body.data) {
if (body.post) {
guobaOptions.body = JSON.stringify(body.data)
} else {
let paramsArray = []
Object.keys(body.data).forEach(key => paramsArray.push(key + '=' + body.data[key]))
if (paramsArray.length > 0) {
body.path += '?' + paramsArray.join('&')
}
}
}
const response = await fetch(`${local[0]}/${body.path}`, guobaOptions)
if (response.ok) {
const json = await response.json()
reply.send(json)
}
} else {
reply.send({ state: false, error: '锅巴接口异常' })
}
}
catch (err) {
console.error(err)
reply.send({ state: false, error: err })
}
} else {
reply.send({ state: false, error: '用户权限不足' })
}
return reply
})
}
export default Guoba

View file

@ -1,36 +1,65 @@
import { UserInfo, AddUser } from './user_data.js'
import { randomString, getUserData, getMasterQQ } from '../../utils/common.js'
import { randomString, getUserData, getMasterQQ, getUin } from '../../utils/common.js'
import fs from 'fs'
async function User(fastify, options) {
function getBots () {
if (Bot.uin === 88888) {
// 找适配器
let adapters = Bot.adapter
return adapters?.map(uin => Bot[uin])
} else if (Bot.adapter && Bot.adapter.length > 0) {
let bots = [Bot]
Bot.adapter.forEach(uin => {
bots.push(Bot[uin])
})
return bots
}
}
async function User (fastify, options) {
// 登录
fastify.post('/login', async (request, reply) => {
const body = request.body || {}
let guobaLoginService
let guobaAPI = ''
try {
let { LoginService } = await import('../../../Guoba-Plugin/server/service/both/LoginService.js')
let { getAllWebAddress } = await import('../../../Guoba-Plugin/utils/common.js')
guobaLoginService = new LoginService()
guobaAPI = await getAllWebAddress()
} catch (err) {
console.error(err)
guobaLoginService = {
signToken: () => { return null }
}
}
if (body.qq && body.passwd) {
const token = randomString(32)
if (body.qq == Bot.uin && await redis.get('CHATGPT:ADMIN_PASSWD') == body.passwd) {
AddUser({ user: body.qq, token: token, autho: 'admin' })
if (body.qq == getUin() && await redis.get('CHATGPT:ADMIN_PASSWD') == body.passwd) {
const guobaToken = await guobaLoginService.signToken(body.qq)
AddUser({ user: body.qq, token, autho: 'admin' })
reply.setCookie('token', token, { path: '/' })
reply.send({ login: true, autho: 'admin', token: token })
reply.send({ login: true, autho: 'admin', token, guobaToken, guoba: guobaAPI })
} else {
const user = await getUserData(body.qq)
if (user.passwd != '' && user.passwd === body.passwd) {
AddUser({ user: body.qq, token: token, autho: 'user' })
AddUser({ user: body.qq, token, autho: 'user' })
reply.setCookie('token', token, { path: '/' })
reply.send({ login: true, autho: 'user', token: token })
reply.send({ login: true, autho: 'user', token })
} else {
reply.send({ login: false, err: `用户名密码错误,如果忘记密码请私聊机器人输入 ${body.qq == Bot.uin ? '#修改管理密码' : '#修改用户密码'} 进行修改` })
reply.send({ login: false, err: `用户名密码错误,如果忘记密码请私聊机器人输入 ${body.qq == getUin() ? '#修改管理密码' : '#修改用户密码'} 进行修改` })
}
}
} else if (body.otp) {
const token = randomString(32)
const opt = await redis.get(`CHATGPT:SERVER_QUICK`)
const opt = await redis.get('CHATGPT:SERVER_QUICK')
if (opt && body.otp == opt) {
AddUser({ user: Bot.uin, token: token, autho: 'admin' })
const guobaToken = await guobaLoginService.signToken(getUin())
AddUser({ user: getUin(), token, autho: 'admin' })
reply.setCookie('token', token, { path: '/' })
reply.send({ login: true, autho: 'admin', token: token, user: Bot.uin })
reply.send({ login: true, autho: 'admin', token, user: getUin(), guobaToken, guoba: guobaAPI })
} else {
reply.send({ login: false, err: `快捷登录代码错误,请检查后重试` })
reply.send({ login: false, err: '快捷登录代码错误,请检查后重试' })
}
} else {
reply.send({ login: false, err: '未输入用户名或密码' })
@ -41,12 +70,15 @@ async function User(fastify, options) {
fastify.post('/quick', async (request, reply) => {
const otp = randomString(6)
await redis.set(
`CHATGPT:SERVER_QUICK`,
'CHATGPT:SERVER_QUICK',
otp,
{ EX: 60000 }
)
const master = (await getMasterQQ())[0]
Bot.sendPrivateMsg(master, `收到工具箱快捷登录请求1分钟内有效${otp}`, false)
let bots = getBots()
for (let bot of bots) {
bot.pickUser(master).sendMsg(`收到工具箱快捷登录请求1分钟内有效${otp}`)
}
reply.send({ state: true })
return reply
})
@ -56,7 +88,7 @@ async function User(fastify, options) {
const user = UserInfo(token)
if (!user || token === 'unknown') {
reply.send({
verify: false,
verify: false
})
return
}
@ -64,7 +96,7 @@ async function User(fastify, options) {
verify: true,
user: user.user,
autho: user.autho,
version: 10016,
version: 10016
})
return reply
})
@ -78,10 +110,10 @@ async function User(fastify, options) {
chat: userData.chat || [],
mode: userData.mode || '',
cast: userData.cast || {
api: '', //API设定
bing: '', //必应设定
bing_resource: '', //必应扩展资料
slack: '', //Slack设定
api: '', // API设定
bing: '', // 必应设定
bing_resource: '', // 必应扩展资料
slack: '' // Slack设定
}
})
return reply

View file

@ -50,6 +50,14 @@ async function routes(fastify, options) {
reply.type('text/html').send(stream)
return reply
})
fastify.setNotFoundHandler((request, reply) => {
if (request.method == 'GET') {
const stream = fs.createReadStream('plugins/chatgpt-plugin/server/static/index.html')
reply.type('text/html').send(stream)
} else {
reply.code(404).send(new Error('Not Found'))
}
})
}
export default routes

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1 +1 @@
import{m as g,V as t}from"./VCheckboxBtn.b7a3a8e0.js";import{p as A,ae as F,af as I,n as B,u as U,ag as D,ah as R,o as _,ac as $,ai as j,aj as l,D as u,J as c}from"./index.f985de17.js";const J=A({...F(),...I(g(),["inline"])},"VCheckbox"),z=B()({name:"VCheckbox",inheritAttrs:!1,props:J(),emits:{"update:modelValue":e=>!0,"update:focused":e=>!0},setup(e,r){let{attrs:d,slots:a}=r;const s=U(e,"modelValue"),{isFocused:n,focus:i,blur:m}=D(e),V=R(),b=_(()=>e.id||`checkbox-${V}`);return $(()=>{const[p,k]=j(d),[f,M]=l.filterProps(e),[h,N]=t.filterProps(e);return u(l,c({class:["v-checkbox",e.class]},p,f,{modelValue:s.value,"onUpdate:modelValue":o=>s.value=o,id:b.value,focused:n.value,style:e.style}),{...a,default:o=>{let{id:v,messagesId:x,isDisabled:P,isReadonly:C}=o;return u(t,c(h,{id:v.value,"aria-describedby":x.value,disabled:P.value,readonly:C.value},k,{modelValue:s.value,"onUpdate:modelValue":y=>s.value=y,onFocus:i,onBlur:m}),a)}})}),{}}});export{z as V};
import{m as g,V as t}from"./VCheckboxBtn.ae1aff4b.js";import{p as A,ae as F,af as I,n as B,u as U,ag as D,ah as R,o as _,ac as $,ai as j,aj as l,D as u,J as c}from"./index.a457a291.js";const J=A({...F(),...I(g(),["inline"])},"VCheckbox"),z=B()({name:"VCheckbox",inheritAttrs:!1,props:J(),emits:{"update:modelValue":e=>!0,"update:focused":e=>!0},setup(e,r){let{attrs:d,slots:a}=r;const s=U(e,"modelValue"),{isFocused:n,focus:i,blur:m}=D(e),V=R(),b=_(()=>e.id||`checkbox-${V}`);return $(()=>{const[p,k]=j(d),[f,M]=l.filterProps(e),[h,N]=t.filterProps(e);return u(l,c({class:["v-checkbox",e.class]},p,f,{modelValue:s.value,"onUpdate:modelValue":o=>s.value=o,id:b.value,focused:n.value,style:e.style}),{...a,default:o=>{let{id:v,messagesId:x,isDisabled:P,isReadonly:C}=o;return u(t,c(h,{id:v.value,"aria-describedby":x.value,disabled:P.value,readonly:C.value},k,{modelValue:s.value,"onUpdate:modelValue":y=>s.value=y,onFocus:i,onBlur:m}),a)}})}),{}}});export{z as V};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
import{p as w,O as V,o as D,aD as b,b4 as O,av as k,a_ as x,b5 as L,b6 as j,n as B,u as R,b7 as T,a$ as A,aR as P,ax as C,J as I,ac as N,aT as K,D as S,G as $,b3 as z,b8 as G}from"./index.a457a291.js";const J=(t,f,e)=>t==null||f==null?-1:t.toString().toLocaleLowerCase().indexOf(f.toString().toLocaleLowerCase()),_=w({customFilter:Function,customKeyFilter:Object,filterKeys:[Array,String],filterMode:{type:String,default:"intersection"},noFilter:Boolean},"filter");function Q(t,f,e){var v,l,s;const r=[],d=(v=e==null?void 0:e.default)!=null?v:J,n=e!=null&&e.filterKeys?k(e.filterKeys):!1,m=Object.keys((l=e==null?void 0:e.customKeyFilter)!=null?l:{}).length;if(!(t!=null&&t.length))return r;e:for(let c=0;c<t.length;c++){const a=t[c],o={},i={};let u=-1;if(f&&!(e!=null&&e.noFilter)){if(typeof a=="object"){const h=n||Object.keys(a);for(const F of h){const E=x(a,F,a),M=(s=e==null?void 0:e.customKeyFilter)==null?void 0:s[F];if(u=M?M(E,f,a):d(E,f,a),u!==-1&&u!==!1)M?o[F]=u:i[F]=u;else if((e==null?void 0:e.filterMode)==="every")continue e}}else u=d(a,f,a),u!==-1&&u!==!1&&(i.title=u);const g=Object.keys(i).length,y=Object.keys(o).length;if(!g&&!y||(e==null?void 0:e.filterMode)==="union"&&y!==m&&!g||(e==null?void 0:e.filterMode)==="intersection"&&(y!==m||!g))continue}r.push({index:c,matches:{...i,...o}})}return r}function H(t,f,e,r){const d=V([]),n=V(new Map),m=D(()=>r!=null&&r.transform?b(f).map(r==null?void 0:r.transform):b(f));O(()=>{const l=typeof e=="function"?e():b(e),s=typeof l!="string"&&typeof l!="number"?"":String(l),c=Q(m.value,s,{customKeyFilter:t.customKeyFilter,default:t.customFilter,filterKeys:t.filterKeys,filterMode:t.filterMode,noFilter:t.noFilter}),a=b(f),o=[],i=new Map;c.forEach(u=>{let{index:g,matches:y}=u;const h=a[g];o.push(h),i.set(h.value,y)}),d.value=o,n.value=i});function v(l){return n.value.get(l.value)}return{filteredItems:d,filteredMatches:n,getMatches:v}}const U=w({fullscreen:Boolean,retainFocus:{type:Boolean,default:!0},scrollable:Boolean,...L({origin:"center center",scrollStrategy:"block",transition:{component:j},zIndex:2400})},"VDialog"),X=B()({name:"VDialog",props:U(),emits:{"update:modelValue":t=>!0},setup(t,f){let{slots:e}=f;const r=R(t,"modelValue"),{scopeId:d}=T(),n=V();function m(l){var a,o;const s=l.relatedTarget,c=l.target;if(s!==c&&((a=n.value)==null?void 0:a.contentEl)&&((o=n.value)==null?void 0:o.globalTop)&&![document,n.value.contentEl].includes(c)&&!n.value.contentEl.contains(c)){const i=G(n.value.contentEl);if(!i.length)return;const u=i[0],g=i[i.length-1];s===u?g.focus():u.focus()}}A&&P(()=>r.value&&t.retainFocus,l=>{l?document.addEventListener("focusin",m):document.removeEventListener("focusin",m)},{immediate:!0}),P(r,async l=>{var s,c;await C(),l?(s=n.value.contentEl)==null||s.focus({preventScroll:!0}):(c=n.value.activatorEl)==null||c.focus({preventScroll:!0})});const v=D(()=>I({"aria-haspopup":"dialog","aria-expanded":String(r.value)},t.activatorProps));return N(()=>{const[l]=K.filterProps(t);return S(K,I({ref:n,class:["v-dialog",{"v-dialog--fullscreen":t.fullscreen,"v-dialog--scrollable":t.scrollable},t.class],style:t.style},l,{modelValue:r.value,"onUpdate:modelValue":s=>r.value=s,"aria-modal":"true",activatorProps:v.value,role:"dialog"},d),{activator:e.activator,default:function(){for(var s=arguments.length,c=new Array(s),a=0;a<s;a++)c[a]=arguments[a];return S($,{root:"VDialog"},{default:()=>{var o;return[(o=e.default)==null?void 0:o.call(e,...c)]}})}})}),z({},n)}});export{X as V,_ as m,H as u};

View file

@ -1 +0,0 @@
.v-select .v-field .v-text-field__prefix,.v-select .v-field .v-text-field__suffix,.v-select .v-field .v-field__input,.v-select .v-field.v-field{cursor:pointer}.v-select .v-field .v-field__input>input{align-self:flex-start;opacity:1;flex:0 0;position:absolute;width:100%;transition:none;pointer-events:none;caret-color:transparent}.v-select .v-field--dirty .v-select__selection{margin-inline-end:2px}.v-select .v-select__selection-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.v-select__content{overflow:hidden;box-shadow:0 2px 4px -1px var(--v-shadow-key-umbra-opacity),0 4px 5px 0 var(--v-shadow-key-penumbra-opacity),0 1px 10px 0 var(--v-shadow-key-ambient-opacity);border-radius:4px}.v-select__selection{display:inline-flex;align-items:center;letter-spacing:inherit;line-height:inherit;max-width:100%}.v-select .v-select__selection{margin-top:var(--v-input-chips-margin-top);margin-bottom:var(--v-input-chips-margin-bottom)}.v-select .v-select__selection:first-child{margin-inline-start:0}.v-select--selected .v-field .v-field__input>input{opacity:0}.v-select__menu-icon{margin-inline-start:4px;transition:.2s cubic-bezier(.4,0,.2,1)}.v-select--active-menu .v-select__menu-icon{opacity:var(--v-high-emphasis-opacity);transform:rotate(180deg)}.v-virtual-scroll{display:block;flex:1 1 auto;max-width:100%;overflow:auto;position:relative}.v-virtual-scroll__container{display:block}.v-dialog{align-items:center;justify-content:center;margin:auto}.v-dialog>.v-overlay__content{max-height:calc(100% - 48px);width:calc(100% - 48px);max-width:calc(100% - 48px);margin:24px;display:flex;flex-direction:column}.v-dialog>.v-overlay__content>.v-card,.v-dialog>.v-overlay__content>.v-sheet,.v-dialog>.v-overlay__content>form>.v-card,.v-dialog>.v-overlay__content>form>.v-sheet{--v-scrollbar-offset: 0px;border-radius:6px;overflow-y:auto;box-shadow:0 11px 15px -7px var(--v-shadow-key-umbra-opacity),0 24px 38px 3px var(--v-shadow-key-penumbra-opacity),0 9px 46px 8px var(--v-shadow-key-ambient-opacity)}.v-dialog>.v-overlay__content>.v-card,.v-dialog>.v-overlay__content>form>.v-card{display:flex;flex-direction:column}.v-dialog>.v-overlay__content>.v-card>.v-card-item,.v-dialog>.v-overlay__content>form>.v-card>.v-card-item{padding:20px}.v-dialog>.v-overlay__content>.v-card>.v-card-item+.v-card-text,.v-dialog>.v-overlay__content>form>.v-card>.v-card-item+.v-card-text{padding-top:0}.v-dialog>.v-overlay__content>.v-card>.v-card-text,.v-dialog>.v-overlay__content>form>.v-card>.v-card-text{font-size:inherit;letter-spacing:.0094rem;line-height:inherit;padding:20px}.v-dialog--fullscreen{--v-scrollbar-offset: 0px}.v-dialog--fullscreen>.v-overlay__content{border-radius:0;margin:0;padding:0;width:100%;height:100%;max-width:100%;max-height:100%;overflow-y:auto;top:0;left:0}.v-dialog--fullscreen>.v-overlay__content>.v-card,.v-dialog--fullscreen>.v-overlay__content>.v-sheet,.v-dialog--fullscreen>.v-overlay__content>form>.v-card,.v-dialog--fullscreen>.v-overlay__content>form>.v-sheet{min-height:100%;min-width:100%;border-radius:0}.v-dialog--scrollable>.v-overlay__content,.v-dialog--scrollable>.v-overlay__content>form{display:flex;overflow:hidden}.v-dialog--scrollable>.v-overlay__content>.v-card,.v-dialog--scrollable>.v-overlay__content>form>.v-card{display:flex;flex:1 1 100%;flex-direction:column;max-height:100%;max-width:100%}.v-dialog--scrollable>.v-overlay__content>.v-card>.v-card-text,.v-dialog--scrollable>.v-overlay__content>form>.v-card>.v-card-text{backface-visibility:hidden;overflow-y:auto}

View file

@ -0,0 +1 @@
.v-dialog{align-items:center;justify-content:center;margin:auto}.v-dialog>.v-overlay__content{max-height:calc(100% - 48px);width:calc(100% - 48px);max-width:calc(100% - 48px);margin:24px;display:flex;flex-direction:column}.v-dialog>.v-overlay__content>.v-card,.v-dialog>.v-overlay__content>.v-sheet,.v-dialog>.v-overlay__content>form>.v-card,.v-dialog>.v-overlay__content>form>.v-sheet{--v-scrollbar-offset: 0px;border-radius:6px;overflow-y:auto;box-shadow:0 11px 15px -7px var(--v-shadow-key-umbra-opacity),0 24px 38px 3px var(--v-shadow-key-penumbra-opacity),0 9px 46px 8px var(--v-shadow-key-ambient-opacity)}.v-dialog>.v-overlay__content>.v-card,.v-dialog>.v-overlay__content>form>.v-card{display:flex;flex-direction:column}.v-dialog>.v-overlay__content>.v-card>.v-card-item,.v-dialog>.v-overlay__content>form>.v-card>.v-card-item{padding:20px}.v-dialog>.v-overlay__content>.v-card>.v-card-item+.v-card-text,.v-dialog>.v-overlay__content>form>.v-card>.v-card-item+.v-card-text{padding-top:0}.v-dialog>.v-overlay__content>.v-card>.v-card-text,.v-dialog>.v-overlay__content>form>.v-card>.v-card-text{font-size:inherit;letter-spacing:.0094rem;line-height:inherit;padding:20px}.v-dialog--fullscreen{--v-scrollbar-offset: 0px}.v-dialog--fullscreen>.v-overlay__content{border-radius:0;margin:0;padding:0;width:100%;height:100%;max-width:100%;max-height:100%;overflow-y:auto;top:0;left:0}.v-dialog--fullscreen>.v-overlay__content>.v-card,.v-dialog--fullscreen>.v-overlay__content>.v-sheet,.v-dialog--fullscreen>.v-overlay__content>form>.v-card,.v-dialog--fullscreen>.v-overlay__content>form>.v-sheet{min-height:100%;min-width:100%;border-radius:0}.v-dialog--scrollable>.v-overlay__content,.v-dialog--scrollable>.v-overlay__content>form{display:flex;overflow:hidden}.v-dialog--scrollable>.v-overlay__content>.v-card,.v-dialog--scrollable>.v-overlay__content>form>.v-card{display:flex;flex:1 1 100%;flex-direction:column;max-height:100%;max-width:100%}.v-dialog--scrollable>.v-overlay__content>.v-card>.v-card-text,.v-dialog--scrollable>.v-overlay__content>form>.v-card>.v-card-text{backface-visibility:hidden;overflow-y:auto}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
.v-select .v-field .v-text-field__prefix,.v-select .v-field .v-text-field__suffix,.v-select .v-field .v-field__input,.v-select .v-field.v-field{cursor:pointer}.v-select .v-field .v-field__input>input{align-self:flex-start;opacity:1;flex:0 0;position:absolute;width:100%;transition:none;pointer-events:none;caret-color:transparent}.v-select .v-field--dirty .v-select__selection{margin-inline-end:2px}.v-select .v-select__selection-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.v-select__content{overflow:hidden;box-shadow:0 2px 4px -1px var(--v-shadow-key-umbra-opacity),0 4px 5px 0 var(--v-shadow-key-penumbra-opacity),0 1px 10px 0 var(--v-shadow-key-ambient-opacity);border-radius:4px}.v-select__selection{display:inline-flex;align-items:center;letter-spacing:inherit;line-height:inherit;max-width:100%}.v-select .v-select__selection{margin-top:var(--v-input-chips-margin-top);margin-bottom:var(--v-input-chips-margin-bottom)}.v-select .v-select__selection:first-child{margin-inline-start:0}.v-select--selected .v-field .v-field__input>input{opacity:0}.v-select__menu-icon{margin-inline-start:4px;transition:.2s cubic-bezier(.4,0,.2,1)}.v-select--active-menu .v-select__menu-icon{opacity:var(--v-high-emphasis-opacity);transform:rotate(180deg)}.v-virtual-scroll{display:block;flex:1 1 auto;max-width:100%;overflow:auto;position:relative}.v-virtual-scroll__container{display:block}

View file

@ -1 +1 @@
import{p as d,m as h,a as m,j as b,k as v,n as c,q as f,t as u,ac as g,D as t,ad as T}from"./index.f985de17.js";const x=d({fixedHeader:Boolean,fixedFooter:Boolean,height:[Number,String],hover:Boolean,...h(),...m(),...b(),...v()},"VTable"),V=c()({name:"VTable",props:x(),setup(a,n){let{slots:e}=n;const{themeClasses:r}=f(a),{densityClasses:i}=u(a);return g(()=>t(a.tag,{class:["v-table",{"v-table--fixed-height":!!a.height,"v-table--fixed-header":a.fixedHeader,"v-table--fixed-footer":a.fixedFooter,"v-table--has-top":!!e.top,"v-table--has-bottom":!!e.bottom,"v-table--hover":a.hover},r.value,i.value,a.class],style:a.style},{default:()=>{var o,s,l;return[(o=e.top)==null?void 0:o.call(e),e.default?t("div",{class:"v-table__wrapper",style:{height:T(a.height)}},[t("table",null,[e.default()])]):(s=e.wrapper)==null?void 0:s.call(e),(l=e.bottom)==null?void 0:l.call(e)]}})),{}}});export{V,x as m};
import{p as d,m as h,a as m,j as b,k as v,n as c,q as f,t as u,ac as g,D as t,ad as T}from"./index.a457a291.js";const x=d({fixedHeader:Boolean,fixedFooter:Boolean,height:[Number,String],hover:Boolean,...h(),...m(),...b(),...v()},"VTable"),V=c()({name:"VTable",props:x(),setup(a,n){let{slots:e}=n;const{themeClasses:r}=f(a),{densityClasses:i}=u(a);return g(()=>t(a.tag,{class:["v-table",{"v-table--fixed-height":!!a.height,"v-table--fixed-header":a.fixedHeader,"v-table--fixed-footer":a.fixedFooter,"v-table--has-top":!!e.top,"v-table--has-bottom":!!e.bottom,"v-table--hover":a.hover},r.value,i.value,a.class],style:a.style},{default:()=>{var o,s,l;return[(o=e.top)==null?void 0:o.call(e),e.default?t("div",{class:"v-table__wrapper",style:{height:T(a.height)}},[t("table",null,[e.default()])]):(s=e.wrapper)==null?void 0:s.call(e),(l=e.bottom)==null?void 0:l.call(e)]}})),{}}});export{V,x as m};

View file

@ -1 +1 @@
import{p as Z,ae as p,bf as ee,n as te,bg as ae,u as ne,ag as le,o as y,O as x,aq as oe,b4 as ue,b8 as ie,aT as m,bh as re,ac as se,ai as ce,aj as _,bi as de,D as o,bj as fe,J as I,a2 as R,ar as z,as as ve,bk as xe,bl as me,a_ as ge,ax as S,bm as he,ad as we,az as Ve}from"./index.f985de17.js";const ye=Z({autoGrow:Boolean,autofocus:Boolean,counter:[Boolean,Number,String],counterValue:Function,prefix:String,placeholder:String,persistentPlaceholder:Boolean,persistentCounter:Boolean,noResize:Boolean,rows:{type:[Number,String],default:5,validator:e=>!isNaN(parseFloat(e))},maxRows:{type:[Number,String],validator:e=>!isNaN(parseFloat(e))},suffix:String,modelModifiers:Object,...p(),...ee()},"VTextarea"),be=te()({name:"VTextarea",directives:{Intersect:ae},inheritAttrs:!1,props:ye(),emits:{"click:control":e=>!0,"mousedown:control":e=>!0,"update:focused":e=>!0,"update:modelValue":e=>!0},setup(e,A){let{attrs:F,emit:M,slots:i}=A;const u=ne(e,"modelValue"),{isFocused:f,focus:D,blur:G}=le(e),E=y(()=>typeof e.counterValue=="function"?e.counterValue(u.value):(u.value||"").toString().length),U=y(()=>{if(F.maxlength)return F.maxlength;if(!(!e.counter||typeof e.counter!="number"&&typeof e.counter!="string"))return e.counter});function O(t,n){var a,l;!e.autofocus||!t||(l=(a=n[0].target)==null?void 0:a.focus)==null||l.call(a)}const T=x(),g=x(),B=oe(""),h=x(),j=y(()=>e.persistentPlaceholder||f.value||e.active);function b(){var t;h.value!==document.activeElement&&((t=h.value)==null||t.focus()),f.value||D()}function $(t){b(),M("click:control",t)}function q(t){M("mousedown:control",t)}function J(t){t.stopPropagation(),b(),S(()=>{u.value="",he(e["onClick:clear"],t)})}function K(t){var a;const n=t.target;if(u.value=n.value,(a=e.modelModifiers)!=null&&a.trim){const l=[n.selectionStart,n.selectionEnd];S(()=>{n.selectionStart=l[0],n.selectionEnd=l[1]})}}const c=x(),w=x(+e.rows),C=y(()=>["plain","underlined"].includes(e.variant));ue(()=>{e.autoGrow||(w.value=+e.rows)});function d(){!e.autoGrow||S(()=>{if(!c.value||!g.value)return;const t=getComputedStyle(c.value),n=getComputedStyle(g.value.$el),a=parseFloat(t.getPropertyValue("--v-field-padding-top"))+parseFloat(t.getPropertyValue("--v-input-padding-top"))+parseFloat(t.getPropertyValue("--v-field-padding-bottom")),l=c.value.scrollHeight,V=parseFloat(t.lineHeight),P=Math.max(parseFloat(e.rows)*V+a,parseFloat(n.getPropertyValue("--v-input-control-height"))),k=parseFloat(e.maxRows)*V+a||1/0,s=Ve(l!=null?l:0,P,k);w.value=Math.floor((s-a)/V),B.value=we(s)})}ie(d),m(u,d),m(()=>e.rows,d),m(()=>e.maxRows,d),m(()=>e.density,d);let r;return m(c,t=>{t?(r=new ResizeObserver(d),r.observe(c.value)):r==null||r.disconnect()}),re(()=>{r==null||r.disconnect()}),se(()=>{const t=!!(i.counter||e.counter||e.counterValue),n=!!(t||i.details),[a,l]=ce(F),[{modelValue:V,...P}]=_.filterProps(e),[k]=de(e);return o(_,I({ref:T,modelValue:u.value,"onUpdate:modelValue":s=>u.value=s,class:["v-textarea v-text-field",{"v-textarea--prefixed":e.prefix,"v-textarea--suffixed":e.suffix,"v-text-field--prefixed":e.prefix,"v-text-field--suffixed":e.suffix,"v-textarea--auto-grow":e.autoGrow,"v-textarea--no-resize":e.noResize||e.autoGrow,"v-text-field--plain-underlined":C.value},e.class],style:e.style},a,P,{centerAffix:w.value===1&&!C.value,focused:f.value}),{...i,default:s=>{let{isDisabled:v,isDirty:H,isReadonly:L,isValid:Q}=s;return o(fe,I({ref:g,style:{"--v-textarea-control-height":B.value},onClick:$,onMousedown:q,"onClick:clear":J,"onClick:prependInner":e["onClick:prependInner"],"onClick:appendInner":e["onClick:appendInner"]},k,{active:j.value||H.value,centerAffix:w.value===1&&!C.value,dirty:H.value||e.dirty,disabled:v.value,focused:f.value,error:Q.value===!1}),{...i,default:W=>{let{props:{class:N,...X}}=W;return o(R,null,[e.prefix&&o("span",{class:"v-text-field__prefix"},[e.prefix]),z(o("textarea",I({ref:h,class:N,value:u.value,onInput:K,autofocus:e.autofocus,readonly:L.value,disabled:v.value,placeholder:e.placeholder,rows:e.rows,name:e.name,onFocus:b,onBlur:G},X,l),null),[[ve("intersect"),{handler:O},null,{once:!0}]]),e.autoGrow&&z(o("textarea",{class:[N,"v-textarea__sizer"],"onUpdate:modelValue":Y=>u.value=Y,ref:c,readonly:!0,"aria-hidden":"true"},null),[[xe,u.value]]),e.suffix&&o("span",{class:"v-text-field__suffix"},[e.suffix])])}})},details:n?s=>{var v;return o(R,null,[(v=i.details)==null?void 0:v.call(i,s),t&&o(R,null,[o("span",null,null),o(me,{active:e.persistentCounter||f.value,value:E.value,max:U.value},i.counter)])])}:void 0})}),ge({},T,g,h)}});export{be as V};
import{p as Z,ae as p,bg as ee,n as te,bh as ae,u as ne,ag as le,o as y,O as x,aq as oe,b4 as ue,bd as ie,aR as m,bi as re,ac as se,ai as ce,aj as z,bj as de,D as o,bk as fe,J as R,a2 as I,ar as A,as as ve,bl as xe,bm as me,b3 as ge,ax as S,bn as he,ad as we,az as Ve}from"./index.a457a291.js";const ye=Z({autoGrow:Boolean,autofocus:Boolean,counter:[Boolean,Number,String],counterValue:Function,prefix:String,placeholder:String,persistentPlaceholder:Boolean,persistentCounter:Boolean,noResize:Boolean,rows:{type:[Number,String],default:5,validator:e=>!isNaN(parseFloat(e))},maxRows:{type:[Number,String],validator:e=>!isNaN(parseFloat(e))},suffix:String,modelModifiers:Object,...p(),...ee()},"VTextarea"),Fe=te()({name:"VTextarea",directives:{Intersect:ae},inheritAttrs:!1,props:ye(),emits:{"click:control":e=>!0,"mousedown:control":e=>!0,"update:focused":e=>!0,"update:modelValue":e=>!0},setup(e,_){let{attrs:b,emit:M,slots:i}=_;const u=ne(e,"modelValue"),{isFocused:f,focus:D,blur:G}=le(e),E=y(()=>typeof e.counterValue=="function"?e.counterValue(u.value):(u.value||"").toString().length),U=y(()=>{if(b.maxlength)return b.maxlength;if(!(!e.counter||typeof e.counter!="number"&&typeof e.counter!="string"))return e.counter});function O(t,n){var a,l;!e.autofocus||!t||(l=(a=n[0].target)==null?void 0:a.focus)==null||l.call(a)}const B=x(),g=x(),H=oe(""),h=x(),j=y(()=>e.persistentPlaceholder||f.value||e.active);function F(){var t;h.value!==document.activeElement&&((t=h.value)==null||t.focus()),f.value||D()}function $(t){F(),M("click:control",t)}function q(t){M("mousedown:control",t)}function J(t){t.stopPropagation(),F(),S(()=>{u.value="",he(e["onClick:clear"],t)})}function K(t){var a;const n=t.target;if(u.value=n.value,(a=e.modelModifiers)!=null&&a.trim){const l=[n.selectionStart,n.selectionEnd];S(()=>{n.selectionStart=l[0],n.selectionEnd=l[1]})}}const c=x(),w=x(+e.rows),C=y(()=>["plain","underlined"].includes(e.variant));ue(()=>{e.autoGrow||(w.value=+e.rows)});function d(){!e.autoGrow||S(()=>{if(!c.value||!g.value)return;const t=getComputedStyle(c.value),n=getComputedStyle(g.value.$el),a=parseFloat(t.getPropertyValue("--v-field-padding-top"))+parseFloat(t.getPropertyValue("--v-input-padding-top"))+parseFloat(t.getPropertyValue("--v-field-padding-bottom")),l=c.value.scrollHeight,V=parseFloat(t.lineHeight),P=Math.max(parseFloat(e.rows)*V+a,parseFloat(n.getPropertyValue("--v-input-control-height"))),k=parseFloat(e.maxRows)*V+a||1/0,s=Ve(l!=null?l:0,P,k);w.value=Math.floor((s-a)/V),H.value=we(s)})}ie(d),m(u,d),m(()=>e.rows,d),m(()=>e.maxRows,d),m(()=>e.density,d);let r;return m(c,t=>{t?(r=new ResizeObserver(d),r.observe(c.value)):r==null||r.disconnect()}),re(()=>{r==null||r.disconnect()}),se(()=>{const t=!!(i.counter||e.counter||e.counterValue),n=!!(t||i.details),[a,l]=ce(b),[{modelValue:V,...P}]=z.filterProps(e),[k]=de(e);return o(z,R({ref:B,modelValue:u.value,"onUpdate:modelValue":s=>u.value=s,class:["v-textarea v-text-field",{"v-textarea--prefixed":e.prefix,"v-textarea--suffixed":e.suffix,"v-text-field--prefixed":e.prefix,"v-text-field--suffixed":e.suffix,"v-textarea--auto-grow":e.autoGrow,"v-textarea--no-resize":e.noResize||e.autoGrow,"v-text-field--plain-underlined":C.value},e.class],style:e.style},a,P,{centerAffix:w.value===1&&!C.value,focused:f.value}),{...i,default:s=>{let{isDisabled:v,isDirty:N,isReadonly:L,isValid:Q}=s;return o(fe,R({ref:g,style:{"--v-textarea-control-height":H.value},onClick:$,onMousedown:q,"onClick:clear":J,"onClick:prependInner":e["onClick:prependInner"],"onClick:appendInner":e["onClick:appendInner"]},k,{active:j.value||N.value,centerAffix:w.value===1&&!C.value,dirty:N.value||e.dirty,disabled:v.value,focused:f.value,error:Q.value===!1}),{...i,default:W=>{let{props:{class:T,...X}}=W;return o(I,null,[e.prefix&&o("span",{class:"v-text-field__prefix"},[e.prefix]),A(o("textarea",R({ref:h,class:T,value:u.value,onInput:K,autofocus:e.autofocus,readonly:L.value,disabled:v.value,placeholder:e.placeholder,rows:e.rows,name:e.name,onFocus:F,onBlur:G},X,l),null),[[ve("intersect"),{handler:O},null,{once:!0}]]),e.autoGrow&&A(o("textarea",{class:[T,"v-textarea__sizer"],"onUpdate:modelValue":Y=>u.value=Y,ref:c,readonly:!0,"aria-hidden":"true"},null),[[xe,u.value]]),e.suffix&&o("span",{class:"v-text-field__suffix"},[e.suffix])])}})},details:n?s=>{var v;return o(I,null,[(v=i.details)==null?void 0:v.call(i,s),t&&o(I,null,[o("span",null,null),o(me,{active:e.persistentCounter||f.value,value:E.value,max:U.value},i.counter)])])}:void 0})}),ge({},B,g,h)}});export{Fe as V};

File diff suppressed because one or more lines are too long

View file

@ -1 +1 @@
import{d as a,h as e,V as n,r as o}from"./index.f985de17.js";const s=a({setup(){const t=o("router-view");return()=>e(n,{class:"layout-wrapper layout-blank"},{default:()=>e(t)})}});export{s as default};
import{d as a,h as e,V as n,r as o}from"./index.a457a291.js";const s=a({setup(){const t=o("router-view");return()=>e(n,{class:"layout-wrapper layout-blank"},{default:()=>e(t)})}});export{s as default};

View file

@ -1 +1 @@
.avatar-center[data-v-57768842]{position:absolute;border:3px solid rgb(var(--v-theme-surface));inset-block-start:-2rem;inset-inline-start:1rem}.member-pricing-bg[data-v-57768842]{position:relative;background-color:rgba(var(--v-theme-on-surface),var(--v-hover-opacity))}.membership-pricing sup[data-v-57768842]{inset-block-start:9px}.v-rating{max-width:100%;display:inline-flex;white-space:nowrap}.v-rating--readonly{pointer-events:none}.v-rating__wrapper{align-items:center;display:inline-flex;flex-direction:column}.v-rating__wrapper--bottom{flex-direction:column-reverse}.v-rating__item{display:inline-flex;position:relative}.v-rating__item label{cursor:pointer}.v-rating__item .v-btn--variant-plain{opacity:1}.v-rating__item .v-btn{transition-property:transform}.v-rating__item .v-btn .v-icon{transition:inherit;transition-timing-function:cubic-bezier(0,0,.2,1)}.v-rating--hover .v-rating__item:hover:not(.v-rating__item--focused) .v-btn{transform:scale(1.25)}.v-rating__item--half{overflow:hidden;position:absolute;clip-path:polygon(0 0,50% 0,50% 100%,0 100%);z-index:1}.v-rating__item--half .v-btn__overlay,.v-rating__item--half:hover .v-btn__overlay{opacity:0}.v-rating__hidden{height:0;opacity:0;position:absolute;width:0}
.avatar-center[data-v-cd7ddfc4]{position:absolute;border:3px solid rgb(var(--v-theme-surface));inset-block-start:-2rem;inset-inline-start:1rem}.member-pricing-bg[data-v-cd7ddfc4]{position:relative;background-color:rgba(var(--v-theme-on-surface),var(--v-hover-opacity))}.membership-pricing sup[data-v-cd7ddfc4]{inset-block-start:9px}.v-rating{max-width:100%;display:inline-flex;white-space:nowrap}.v-rating--readonly{pointer-events:none}.v-rating__wrapper{align-items:center;display:inline-flex;flex-direction:column}.v-rating__wrapper--bottom{flex-direction:column-reverse}.v-rating__item{display:inline-flex;position:relative}.v-rating__item label{cursor:pointer}.v-rating__item .v-btn--variant-plain{opacity:1}.v-rating__item .v-btn{transition-property:transform}.v-rating__item .v-btn .v-icon{transition:inherit;transition-timing-function:cubic-bezier(0,0,.2,1)}.v-rating--hover .v-rating__item:hover:not(.v-rating__item--focused) .v-btn{transform:scale(1.25)}.v-rating__item--half{overflow:hidden;position:absolute;clip-path:polygon(0 0,50% 0,50% 100%,0 100%);z-index:1}.v-rating__item--half .v-btn__overlay,.v-rating__item--half:hover .v-btn__overlay{opacity:0}.v-rating__hidden{height:0;opacity:0;position:absolute;width:0}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1 +1 @@
import{Q as a,a1 as o,a0 as c,a2 as d,a3 as m,D as i,S as e,W as s,F as u,bn as r,a4 as n,a5 as p,U as f,H as h}from"./index.f985de17.js";const _={class:"d-flex align-center flex-wrap"},b={class:"text-center"},V={__name:"icons",setup(g){const l=["mdi-ab-testing","mdi-abacus","mdi-abjad-arabic","mdi-abjad-hebrew","mdi-abugida-devanagari","mdi-abugida-thai","mdi-access-point","mdi-access-point-check","mdi-access-point-minus","mdi-access-point-network","mdi-access-point-network-off","mdi-access-point-off","mdi-access-point-plus","mdi-access-point-remove","mdi-account-alert-outline","mdi-account-arrow-left-outline","mdi-account-arrow-right-outline","mdi-account-box-multiple-outline","mdi-account-box-outline","mdi-account-cancel-outline","mdi-account-cash-outline","mdi-account-check-outline","mdi-account-child-outline","mdi-account-circle-outline","mdi-account-clock-outline","mdi-account-cog-outline","mdi-account-details-outline","mdi-alarm-light-outline","mdi-alert-box-outline","mdi-alert-circle-check-outline","mdi-alert-decagram-outline","mdi-alert-minus-outline","mdi-alert-outline","mdi-alert-plus-outline","mdi-check-outline","mdi-clipboard-outline","mdi-clipboard-play-outline","mdi-close-outline","mdi-cloud-check-outline","mdi-cloud-download-outline","mdi-cog-outline","mdi-compass-off-outline","mdi-contactless-payment-circle-outline","mdi-crown-outline","mdi-delete-outline","mdi-diamond-outline","mdi-email-open-outline","mdi-emoticon-happy-outline","mdi-file-multiple-outline","mdi-flask-empty-outline"];return(k,x)=>(a(),o("div",null,[c("div",_,[(a(),o(d,null,m(l,t=>i(f,{key:t,class:"mb-6 me-6"},{default:e(()=>[i(s,{class:"py-3 px-4"},{default:e(()=>[i(u,{size:"30",icon:t},null,8,["icon"])]),_:2},1024),i(r,{location:"top",activator:"parent"},{default:e(()=>[n(p(t),1)]),_:2},1024)]),_:2},1024)),64))]),c("div",b,[i(h,{href:"https://materialdesignicons.com/",rel:"noopener noreferrer",color:"primary",target:"_blank"},{default:e(()=>[n(" View All Material Design Icons ")]),_:1})])]))}};export{V as default};
import{Q as a,a1 as o,a0 as c,a2 as d,a3 as m,D as i,S as e,W as s,F as u,bo as r,a4 as n,a5 as p,U as f,H as h}from"./index.a457a291.js";const _={class:"d-flex align-center flex-wrap"},b={class:"text-center"},V={__name:"icons",setup(g){const l=["mdi-ab-testing","mdi-abacus","mdi-abjad-arabic","mdi-abjad-hebrew","mdi-abugida-devanagari","mdi-abugida-thai","mdi-access-point","mdi-access-point-check","mdi-access-point-minus","mdi-access-point-network","mdi-access-point-network-off","mdi-access-point-off","mdi-access-point-plus","mdi-access-point-remove","mdi-account-alert-outline","mdi-account-arrow-left-outline","mdi-account-arrow-right-outline","mdi-account-box-multiple-outline","mdi-account-box-outline","mdi-account-cancel-outline","mdi-account-cash-outline","mdi-account-check-outline","mdi-account-child-outline","mdi-account-circle-outline","mdi-account-clock-outline","mdi-account-cog-outline","mdi-account-details-outline","mdi-alarm-light-outline","mdi-alert-box-outline","mdi-alert-circle-check-outline","mdi-alert-decagram-outline","mdi-alert-minus-outline","mdi-alert-outline","mdi-alert-plus-outline","mdi-check-outline","mdi-clipboard-outline","mdi-clipboard-play-outline","mdi-close-outline","mdi-cloud-check-outline","mdi-cloud-download-outline","mdi-cog-outline","mdi-compass-off-outline","mdi-contactless-payment-circle-outline","mdi-crown-outline","mdi-delete-outline","mdi-diamond-outline","mdi-email-open-outline","mdi-emoticon-happy-outline","mdi-file-multiple-outline","mdi-flask-empty-outline"];return(k,x)=>(a(),o("div",null,[c("div",_,[(a(),o(d,null,m(l,t=>i(f,{key:t,class:"mb-6 me-6"},{default:e(()=>[i(s,{class:"py-3 px-4"},{default:e(()=>[i(u,{size:"30",icon:t},null,8,["icon"])]),_:2},1024),i(r,{location:"top",activator:"parent"},{default:e(()=>[n(p(t),1)]),_:2},1024)]),_:2},1024)),64))]),c("div",b,[i(h,{href:"https://materialdesignicons.com/",rel:"noopener noreferrer",color:"primary",target:"_blank"},{default:e(()=>[n(" View All Material Design Icons ")]),_:1})])]))}};export{V as default};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,4 +1,4 @@
import{ak as commonjsGlobal}from"./index.f985de17.js";var md5$1={exports:{}};/**
import{ak as commonjsGlobal}from"./index.a457a291.js";var md5$1={exports:{}};/**
* [js-md5]{@link https://github.com/emn178/js-md5}
*
* @namespace md5

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1 +1 @@
import{bs as b,Q as y,a1 as x,a3 as T,D as e,aD as d,H as g,a2 as C,O as _,o as D,r as I,S as a,aE as M,a0 as s,bt as L,aF as P,a4 as c,W as v,Z as U,aN as B,_ as F,T as n,$ as m,at as N,Y as V,U as S,aC as p}from"./index.f985de17.js";import{a as j,b as A,c as E,d as H}from"./auth-v1-tree.f5524167.js";import{b as h}from"./route-block.7577f022.js";import{V as R}from"./VCheckbox.833361ee.js";import"./VCheckboxBtn.b7a3a8e0.js";const $={__name:"AuthProvider",setup(k){const o=b(),u=[{icon:"mdi-facebook",color:"#4267b2",colorInDark:"#4267b2"},{icon:"mdi-twitter",color:"#1da1f2",colorInDark:"#1da1f2"},{icon:"mdi-github",color:"#272727",colorInDark:"#fff"},{icon:"mdi-google",color:"#db4437",colorInDark:"#db4437"}];return(f,r)=>(y(),x(C,null,T(u,i=>e(g,{key:i.icon,icon:i.icon,variant:"text",color:d(o).global.name.value==="dark"?i.colorInDark:i.color},null,8,["icon","color"])),64))}};const O={class:"auth-wrapper d-flex align-center justify-center pa-4"},Q={class:"d-flex"},W=["innerHTML"],Y=s("h5",{class:"text-h5 font-weight-semibold mb-1"}," Adventure starts here \u{1F680} ",-1),Z=s("p",{class:"mb-0"}," Make your app management easy and fun! ",-1),q={class:"d-flex align-center mt-1 mb-4"},z=s("span",{class:"me-1"},"I agree to",-1),G=s("a",{href:"javascript:void(0)",class:"text-primary"},"privacy policy & terms",-1),J=s("span",null,"Already have an account?",-1),K=s("span",{class:"mx-4"},"or",-1),X={__name:"register",setup(k){const o=_({username:"",email:"",password:"",privacyPolicies:!1}),u=b(),f=D(()=>u.global.name.value==="light"?j:A),r=_(!1);return(i,t)=>{const w=I("RouterLink");return y(),x("div",O,[e(S,{class:"auth-card pa-4 pt-7","max-width":"448"},{default:a(()=>[e(M,{class:"justify-center"},{prepend:a(()=>[s("div",Q,[s("div",{innerHTML:d(L)},null,8,W)])]),default:a(()=>[e(P,{class:"font-weight-semibold text-2xl text-uppercase"},{default:a(()=>[c(" Materio ")]),_:1})]),_:1}),e(v,{class:"pt-2"},{default:a(()=>[Y,Z]),_:1}),e(v,null,{default:a(()=>[e(U,{onSubmit:t[5]||(t[5]=B(()=>{},["prevent"]))},{default:a(()=>[e(F,null,{default:a(()=>[e(n,{cols:"12"},{default:a(()=>[e(m,{modelValue:o.value.username,"onUpdate:modelValue":t[0]||(t[0]=l=>o.value.username=l),label:"Username"},null,8,["modelValue"])]),_:1}),e(n,{cols:"12"},{default:a(()=>[e(m,{modelValue:o.value.email,"onUpdate:modelValue":t[1]||(t[1]=l=>o.value.email=l),label:"Email",type:"email"},null,8,["modelValue"])]),_:1}),e(n,{cols:"12"},{default:a(()=>[e(m,{modelValue:o.value.password,"onUpdate:modelValue":t[2]||(t[2]=l=>o.value.password=l),label:"Password",type:r.value?"text":"password","append-inner-icon":r.value?"mdi-eye-off-outline":"mdi-eye-outline","onClick:appendInner":t[3]||(t[3]=l=>r.value=!r.value)},null,8,["modelValue","type","append-inner-icon"]),s("div",q,[e(R,{id:"privacy-policy",modelValue:o.value.privacyPolicies,"onUpdate:modelValue":t[4]||(t[4]=l=>o.value.privacyPolicies=l),inline:""},null,8,["modelValue"]),e(N,{for:"privacy-policy",style:{opacity:"1"}},{default:a(()=>[z,G]),_:1})]),e(g,{block:"",type:"submit"},{default:a(()=>[c(" Sign up ")]),_:1})]),_:1}),e(n,{cols:"12",class:"text-center text-base"},{default:a(()=>[J,e(w,{class:"text-primary ms-2",to:"login"},{default:a(()=>[c(" Sign in instead ")]),_:1})]),_:1}),e(n,{cols:"12",class:"d-flex align-center"},{default:a(()=>[e(V),K,e(V)]),_:1}),e(n,{cols:"12",class:"text-center"},{default:a(()=>[e($)]),_:1})]),_:1})]),_:1})]),_:1})]),_:1}),e(p,{class:"auth-footer-start-tree d-none d-md-block",src:d(E),width:250},null,8,["src"]),e(p,{src:d(H),class:"auth-footer-end-tree d-none d-md-block",width:350},null,8,["src"]),e(p,{class:"auth-footer-mask d-none d-md-block",src:d(f)},null,8,["src"])])}}};typeof h=="function"&&h(X);export{X as default};
import{bt as b,Q as y,a1 as x,a3 as T,D as e,aD as d,H as g,a2 as C,O as _,o as D,r as I,S as a,aE as M,a0 as s,bu as L,aF as P,a4 as c,W as v,Z as U,aO as B,_ as F,T as n,$ as m,at as S,Y as V,U as j,aC as p}from"./index.a457a291.js";import{a as A,b as E,c as H,d as N}from"./auth-v1-tree.f5524167.js";import{b as h}from"./route-block.7577f022.js";import{V as R}from"./VCheckbox.650ef329.js";import"./VCheckboxBtn.ae1aff4b.js";const $={__name:"AuthProvider",setup(k){const o=b(),u=[{icon:"mdi-facebook",color:"#4267b2",colorInDark:"#4267b2"},{icon:"mdi-twitter",color:"#1da1f2",colorInDark:"#1da1f2"},{icon:"mdi-github",color:"#272727",colorInDark:"#fff"},{icon:"mdi-google",color:"#db4437",colorInDark:"#db4437"}];return(f,r)=>(y(),x(C,null,T(u,i=>e(g,{key:i.icon,icon:i.icon,variant:"text",color:d(o).global.name.value==="dark"?i.colorInDark:i.color},null,8,["icon","color"])),64))}};const O={class:"auth-wrapper d-flex align-center justify-center pa-4"},Q={class:"d-flex"},W=["innerHTML"],Y=s("h5",{class:"text-h5 font-weight-semibold mb-1"}," Adventure starts here \u{1F680} ",-1),Z=s("p",{class:"mb-0"}," Make your app management easy and fun! ",-1),q={class:"d-flex align-center mt-1 mb-4"},z=s("span",{class:"me-1"},"I agree to",-1),G=s("a",{href:"javascript:void(0)",class:"text-primary"},"privacy policy & terms",-1),J=s("span",null,"Already have an account?",-1),K=s("span",{class:"mx-4"},"or",-1),X={__name:"register",setup(k){const o=_({username:"",email:"",password:"",privacyPolicies:!1}),u=b(),f=D(()=>u.global.name.value==="light"?A:E),r=_(!1);return(i,t)=>{const w=I("RouterLink");return y(),x("div",O,[e(j,{class:"auth-card pa-4 pt-7","max-width":"448"},{default:a(()=>[e(M,{class:"justify-center"},{prepend:a(()=>[s("div",Q,[s("div",{innerHTML:d(L)},null,8,W)])]),default:a(()=>[e(P,{class:"font-weight-semibold text-2xl text-uppercase"},{default:a(()=>[c(" Materio ")]),_:1})]),_:1}),e(v,{class:"pt-2"},{default:a(()=>[Y,Z]),_:1}),e(v,null,{default:a(()=>[e(U,{onSubmit:t[5]||(t[5]=B(()=>{},["prevent"]))},{default:a(()=>[e(F,null,{default:a(()=>[e(n,{cols:"12"},{default:a(()=>[e(m,{modelValue:o.value.username,"onUpdate:modelValue":t[0]||(t[0]=l=>o.value.username=l),label:"Username"},null,8,["modelValue"])]),_:1}),e(n,{cols:"12"},{default:a(()=>[e(m,{modelValue:o.value.email,"onUpdate:modelValue":t[1]||(t[1]=l=>o.value.email=l),label:"Email",type:"email"},null,8,["modelValue"])]),_:1}),e(n,{cols:"12"},{default:a(()=>[e(m,{modelValue:o.value.password,"onUpdate:modelValue":t[2]||(t[2]=l=>o.value.password=l),label:"Password",type:r.value?"text":"password","append-inner-icon":r.value?"mdi-eye-off-outline":"mdi-eye-outline","onClick:appendInner":t[3]||(t[3]=l=>r.value=!r.value)},null,8,["modelValue","type","append-inner-icon"]),s("div",q,[e(R,{id:"privacy-policy",modelValue:o.value.privacyPolicies,"onUpdate:modelValue":t[4]||(t[4]=l=>o.value.privacyPolicies=l),inline:""},null,8,["modelValue"]),e(S,{for:"privacy-policy",style:{opacity:"1"}},{default:a(()=>[z,G]),_:1})]),e(g,{block:"",type:"submit"},{default:a(()=>[c(" Sign up ")]),_:1})]),_:1}),e(n,{cols:"12",class:"text-center text-base"},{default:a(()=>[J,e(w,{class:"text-primary ms-2",to:"login"},{default:a(()=>[c(" Sign in instead ")]),_:1})]),_:1}),e(n,{cols:"12",class:"d-flex align-center"},{default:a(()=>[e(V),K,e(V)]),_:1}),e(n,{cols:"12",class:"text-center"},{default:a(()=>[e($)]),_:1})]),_:1})]),_:1})]),_:1})]),_:1}),e(p,{class:"auth-footer-start-tree d-none d-md-block",src:d(H),width:250},null,8,["src"]),e(p,{src:d(N),class:"auth-footer-end-tree d-none d-md-block",width:350},null,8,["src"]),e(p,{class:"auth-footer-mask d-none d-md-block",src:d(f)},null,8,["src"])])}}};typeof h=="function"&&h(X);export{X as default};

File diff suppressed because one or more lines are too long

View file

@ -1 +0,0 @@
import{K as F,O as i,Q as B,R as S,S as a,D as e,bv as I,bJ as H,a4 as n,Y as J,aI as f,H as c,J as V,U as k,aF as C,W as P,b1 as Y,_ as y,T as N,$ as q,aH as x,aY as z,a5 as A,bn as O,a0 as w,F as Q,aD as W,P as D}from"./index.f985de17.js";import{d as b}from"./VDialog.311575a1.js";import{q as j}from"./VDataTable.fa01315e.js";import"./VCheckboxBtn.b7a3a8e0.js";import"./VTable.e8eece46.js";const E=w("span",{class:"text-h5"},"\u65B0\u589EToken",-1),G=["onClick"],L={__name:"BingTokens",setup(R){const s=F(),_=i([{title:"Token",align:"start",sortable:!1,key:"Token"},{title:"\u7528\u91CF",key:"Usage"},{title:"\u72B6\u6001",key:"State"},{title:"",key:"actions",sortable:!1}]),r=i(),d=i(),u=i(),m=i(),g=i(),U=o=>o>800?"error":o>600?"warning":"success",p=()=>{D.post(`${s.getters.serverApi}sysconfig`,{token:s.getters.userToken}).then(o=>{o.data&&(o.data.error?s.commit("app/ADD_SNACKBAR",{message:o.data.error,color:"error"}):r.value=o.data.redisConfig.bingTokens)}).catch(o=>{s.commit("app/ADD_SNACKBAR",{message:o.message,color:"error"}),console.log(o)})},v=o=>{s.getters.runmode==="online"?D.post(`${s.getters.serverApi}saveconfig`,{token:s.getters.userToken,...o}).then(l=>{var t;(t=l.data)!=null&&t.error?s.commit("app/ADD_SNACKBAR",{message:l.data.error,color:"error"}):s.commit("app/ADD_SNACKBAR",{message:"\u4FDD\u5B58\u6210\u529F",color:"success"}),p()}).catch(l=>{p(),s.commit("app/ADD_SNACKBAR",{message:l.message,color:"error"}),console.log(l)}):s.commit("app/ADD_SNACKBAR",{message:"\u4EC5\u652F\u6301\u5728\u7EBF\u6A21\u5F0F\u64CD\u4F5C",color:"warn"})},h=()=>{const o={redisConfig:{bingTokens:[...r.value,{Token:m.value,State:"\u6B63\u5E38",Usage:0}]}};v(o),d.value=!1},K=()=>{const o=r.value.findIndex(t=>t.Token===g.value);o!==-1&&r.value.splice(o,1);const l={redisConfig:{bingTokens:[...r.value]}};v(l),u.value=!1},$=async o=>{try{await navigator.clipboard.writeText(o),s.commit("app/ADD_SNACKBAR",{message:"\u5DF2\u590D\u5236\u5230\u526A\u8D34\u677F",color:"info"})}catch(l){console.error("\u526A\u8D34\u677F\u590D\u5236\u5931\u8D25: ",l)}};return p(),(o,l)=>(B(),S(W(j),{headers:_.value,items:r.value,class:"elevation-1"},{top:a(()=>[e(I,{flat:""},{default:a(()=>[e(H,null,{default:a(()=>[n("Bing Token \u7BA1\u7406")]),_:1}),e(J,{class:"mx-4",inset:"",vertical:""}),e(f),e(b,{modelValue:d.value,"onUpdate:modelValue":l[2]||(l[2]=t=>d.value=t),"max-width":"500px"},{activator:a(({props:t})=>[e(c,V({color:"primary",dark:"",class:"mb-2"},t),{default:a(()=>[n(" \u6DFB\u52A0Token ")]),_:2},1040)]),default:a(()=>[e(k,null,{default:a(()=>[e(C,null,{default:a(()=>[E]),_:1}),e(P,null,{default:a(()=>[e(Y,null,{default:a(()=>[e(y,null,{default:a(()=>[e(N,{cols:"12"},{default:a(()=>[e(q,{modelValue:m.value,"onUpdate:modelValue":l[0]||(l[0]=t=>m.value=t),label:"Token"},null,8,["modelValue"])]),_:1})]),_:1})]),_:1})]),_:1}),e(x,null,{default:a(()=>[e(f),e(c,{color:"blue-darken-1",variant:"text",onClick:l[1]||(l[1]=t=>{d.value=!1,m.value=""})},{default:a(()=>[n(" \u53D6\u6D88 ")]),_:1}),e(c,{color:"blue-darken-1",variant:"text",onClick:h},{default:a(()=>[n(" \u6DFB\u52A0 ")]),_:1})]),_:1})]),_:1})]),_:1},8,["modelValue"]),e(b,{modelValue:u.value,"onUpdate:modelValue":l[4]||(l[4]=t=>u.value=t),"max-width":"550px"},{default:a(()=>[e(k,null,{default:a(()=>[e(C,{class:"text-h5"},{default:a(()=>[n("\u662F\u5426\u786E\u8BA4\u5220\u9664\u8BE5Token\uFF1F\u5220\u9664\u540E\u5C06\u65E0\u6CD5\u6062\u590D\uFF01")]),_:1}),e(x,null,{default:a(()=>[e(f),e(c,{color:"blue-darken-1",variant:"text",onClick:l[3]||(l[3]=t=>u.value=!1)},{default:a(()=>[n("\u53D6\u6D88")]),_:1}),e(c,{color:"error",variant:"text",onClick:K},{default:a(()=>[n("\u786E\u8BA4\u5220\u9664")]),_:1}),e(f)]),_:1})]),_:1})]),_:1},8,["modelValue"])]),_:1})]),"item.Usage":a(({item:t})=>[e(z,{color:U(t.columns.Usage)},{default:a(()=>[n(A(t.columns.Usage),1)]),_:2},1032,["color"])]),"item.Token":a(({item:t})=>[e(O,{activator:"parent",location:"bottom",text:t.columns.Token},{activator:a(({props:T})=>[w("span",V(T,{onClick:M=>$(t.columns.Token)}),A(t.columns.Token.substring(0,50))+"... ",17,G)]),_:2},1032,["text"])]),"item.actions":a(({item:t})=>[e(Q,{size:"small",onClick:T=>{g.value=t.raw.Token,u.value=!0}},{default:a(()=>[n(" mdi-delete ")]),_:2},1032,["onClick"])]),_:1},8,["headers","items"]))}},oe={__name:"tokens",setup(R){return(s,_)=>(B(),S(y,null,{default:a(()=>[e(N,{cols:"12"},{default:a(()=>[e(k,null,{default:a(()=>[e(L)]),_:1})]),_:1})]),_:1}))}};export{oe as default};

View file

@ -0,0 +1 @@
import{K as F,O as i,Q as B,R as S,S as a,D as e,bw as I,bK as H,a4 as n,Y as P,aI as f,H as c,J as V,U as k,aF as C,W as q,aV as z,_ as w,T as y,$ as J,aH as x,aU as O,a5 as A,bo as Q,a0 as N,F as W,aD as Y,P as D}from"./index.a457a291.js";import{V as b}from"./VDialog.368f468c.js";import{q as j}from"./VDataTable.e3c98ce6.js";import"./VSelect.5c080fb6.js";import"./VCheckboxBtn.ae1aff4b.js";import"./VTable.4358e1b9.js";const E=N("span",{class:"text-h5"},"\u65B0\u589EToken",-1),G=["onClick"],L={__name:"BingTokens",setup(U){const s=F(),_=i([{title:"Token",align:"start",sortable:!1,key:"Token"},{title:"\u7528\u91CF",key:"Usage"},{title:"\u72B6\u6001",key:"State"},{title:"",key:"actions",sortable:!1}]),r=i(),d=i(),u=i(),m=i(),g=i(),K=o=>o>800?"error":o>600?"warning":"success",p=()=>{D.post(`${s.getters.serverApi}sysconfig`,{token:s.getters.userToken}).then(o=>{o.data&&(o.data.error?s.commit("app/ADD_SNACKBAR",{message:o.data.error,color:"error"}):r.value=o.data.redisConfig.bingTokens)}).catch(o=>{s.commit("app/ADD_SNACKBAR",{message:o.message,color:"error"}),console.log(o)})},v=o=>{s.getters.runmode==="online"?D.post(`${s.getters.serverApi}saveconfig`,{token:s.getters.userToken,...o}).then(l=>{var t;(t=l.data)!=null&&t.error?s.commit("app/ADD_SNACKBAR",{message:l.data.error,color:"error"}):s.commit("app/ADD_SNACKBAR",{message:"\u4FDD\u5B58\u6210\u529F",color:"success"}),p()}).catch(l=>{p(),s.commit("app/ADD_SNACKBAR",{message:l.message,color:"error"}),console.log(l)}):s.commit("app/ADD_SNACKBAR",{message:"\u4EC5\u652F\u6301\u5728\u7EBF\u6A21\u5F0F\u64CD\u4F5C",color:"warn"})},R=()=>{const o={redisConfig:{bingTokens:[...r.value,{Token:m.value,State:"\u6B63\u5E38",Usage:0}]}};v(o),d.value=!1},h=()=>{const o=r.value.findIndex(t=>t.Token===g.value);o!==-1&&r.value.splice(o,1);const l={redisConfig:{bingTokens:[...r.value]}};v(l),u.value=!1},$=async o=>{try{await navigator.clipboard.writeText(o),s.commit("app/ADD_SNACKBAR",{message:"\u5DF2\u590D\u5236\u5230\u526A\u8D34\u677F",color:"info"})}catch(l){console.error("\u526A\u8D34\u677F\u590D\u5236\u5931\u8D25: ",l)}};return p(),(o,l)=>(B(),S(Y(j),{headers:_.value,items:r.value,class:"elevation-1"},{top:a(()=>[e(I,{flat:""},{default:a(()=>[e(H,null,{default:a(()=>[n("Bing Token \u7BA1\u7406")]),_:1}),e(P,{class:"mx-4",inset:"",vertical:""}),e(f),e(b,{modelValue:d.value,"onUpdate:modelValue":l[2]||(l[2]=t=>d.value=t),"max-width":"500px"},{activator:a(({props:t})=>[e(c,V({color:"primary",dark:"",class:"mb-2"},t),{default:a(()=>[n(" \u6DFB\u52A0Token ")]),_:2},1040)]),default:a(()=>[e(k,null,{default:a(()=>[e(C,null,{default:a(()=>[E]),_:1}),e(q,null,{default:a(()=>[e(z,null,{default:a(()=>[e(w,null,{default:a(()=>[e(y,{cols:"12"},{default:a(()=>[e(J,{modelValue:m.value,"onUpdate:modelValue":l[0]||(l[0]=t=>m.value=t),label:"Token"},null,8,["modelValue"])]),_:1})]),_:1})]),_:1})]),_:1}),e(x,null,{default:a(()=>[e(f),e(c,{color:"blue-darken-1",variant:"text",onClick:l[1]||(l[1]=t=>{d.value=!1,m.value=""})},{default:a(()=>[n(" \u53D6\u6D88 ")]),_:1}),e(c,{color:"blue-darken-1",variant:"text",onClick:R},{default:a(()=>[n(" \u6DFB\u52A0 ")]),_:1})]),_:1})]),_:1})]),_:1},8,["modelValue"]),e(b,{modelValue:u.value,"onUpdate:modelValue":l[4]||(l[4]=t=>u.value=t),"max-width":"550px"},{default:a(()=>[e(k,null,{default:a(()=>[e(C,{class:"text-h5"},{default:a(()=>[n("\u662F\u5426\u786E\u8BA4\u5220\u9664\u8BE5Token\uFF1F\u5220\u9664\u540E\u5C06\u65E0\u6CD5\u6062\u590D\uFF01")]),_:1}),e(x,null,{default:a(()=>[e(f),e(c,{color:"blue-darken-1",variant:"text",onClick:l[3]||(l[3]=t=>u.value=!1)},{default:a(()=>[n("\u53D6\u6D88")]),_:1}),e(c,{color:"error",variant:"text",onClick:h},{default:a(()=>[n("\u786E\u8BA4\u5220\u9664")]),_:1}),e(f)]),_:1})]),_:1})]),_:1},8,["modelValue"])]),_:1})]),"item.Usage":a(({item:t})=>[e(O,{color:K(t.columns.Usage)},{default:a(()=>[n(A(t.columns.Usage),1)]),_:2},1032,["color"])]),"item.Token":a(({item:t})=>[e(Q,{activator:"parent",location:"bottom",text:t.columns.Token},{activator:a(({props:T})=>[N("span",V(T,{onClick:M=>$(t.columns.Token)}),A(t.columns.Token.substring(0,50))+"... ",17,G)]),_:2},1032,["text"])]),"item.actions":a(({item:t})=>[e(W,{size:"small",onClick:T=>{g.value=t.raw.Token,u.value=!0}},{default:a(()=>[n(" mdi-delete ")]),_:2},1032,["onClick"])]),_:1},8,["headers","items"]))}},le={__name:"tokens",setup(U){return(s,_)=>(B(),S(w,null,{default:a(()=>[e(y,{cols:"12"},{default:a(()=>[e(k,null,{default:a(()=>[e(L)]),_:1})]),_:1})]),_:1}))}};export{le as default};

View file

@ -1 +1 @@
import{aB as c,Q as l,R as n,S as e,D as s,W as d,U as _,a0 as t,_ as h,T as o}from"./index.f985de17.js";const u={},r=t("div",null,[t("h1",{class:"text-h1"}," Heading 1 "),t("span",null,"font-size: 6rem / line-height: 6rem / font-weight: 300")],-1),m=t("div",null,[t("h2",{class:"text-h2"}," Heading 2 "),t("span",null,"font-size: 3.75rem / line-height: 3.75rem / font-weight: 300")],-1),f=t("div",null,[t("h3",{class:"text-h3"}," Heading 3 "),t("span",null,"font-size: 3rem / line-height: 3.125rem / font-weight: 400")],-1),p=t("div",null,[t("h4",{class:"text-h4"}," Heading 4 "),t("span",null,"font-size: 2.125rem / line-height: 2.5rem / font-weight: 400")],-1),x=t("div",null,[t("h5",{class:"text-h5"}," Heading 5 "),t("span",null,"font-size: 1.5rem / line-height: 2rem / font-weight: 400")],-1),g=t("div",null,[t("h6",{class:"text-h6"}," Heading 6 "),t("span",null,"font-size: 1.25rem / line-height: 2rem / font-weight: 500")],-1);function b(a,i){return l(),n(_,{title:"Headlines"},{default:e(()=>[s(d,{class:"d-flex flex-column gap-y-8"},{default:e(()=>[r,m,f,p,x,g]),_:1})]),_:1})}const w=c(u,[["render",b]]),k={},y=t("span",{class:"text-subtitle-1 text-no-wrap"},"text-subtitle-1",-1),z=t("p",{class:"text-subtitle-1 text-truncate mb-0"}," Cupcake ipsum dolor sit amet fruitcake donut chocolate. ",-1),C=t("small",null,"font-size: 1rem / line-height: 1.75rem / font-weight: 400",-1),v=t("span",{class:"text-subtitle-2 text-no-wrap"},"text-subtitle-2",-1),$=t("p",{class:"text-subtitle-2 mb-0"}," Cupcake ipsum dolor sit amet fruitcake donut chocolate. ",-1),H=t("small",null,"font-size: 0.875rem / line-height: 1.375rem / font-weight: 500",-1),T=t("span",{class:"text-body-1 text-no-wrap"},"text-body-1",-1),V=t("p",{class:"text-body-1 mb-0"}," Cupcake ipsum dolor sit amet fruitcake donut chocolate. ",-1),B=t("small",null,"font-size: 1rem / line-height: 1.5rem / font-weight: 400",-1),N=t("span",{class:"text-body-2 text-no-wrap"},"text-body-2",-1),R=t("p",{class:"text-body-2 mb-0"}," Cupcake ipsum dolor sit amet fruitcake donut chocolate. ",-1),D=t("small",null,"font-size: 0.875rem / line-height: 1.25rem / font-weight: 400",-1),Q=t("span",{class:"text-caption"},"text-caption",-1),S=t("p",{class:"text-caption mb-0"}," Cupcake ipsum dolor sit amet fruitcake donut chocolate. ",-1),U=t("small",null,"font-size: 0.75rem / line-height: 1.25rem / font-weight: 400",-1),W=t("span",{class:"text-overline text-no-wrap"},"text-overline",-1),j=t("p",{class:"text-overline mb-0"}," Cupcake ipsum dolor sit amet fruitcake donut chocolate. ",-1),q=t("small",null,"font-size: 0.75rem / line-height: 2rem / font-weight: 500",-1),A=t("span",{class:"text-button"},"text-button",-1),E=t("p",{class:"text-button mb-0"}," Cupcake ipsum dolor sit amet fruitcake donut chocolate. ",-1),F=t("small",null,"font-size: 0.875rem / line-height: 2.25rem / font-weight: 500",-1);function G(a,i){return l(),n(_,{title:"Texts"},{default:e(()=>[s(d,null,{default:e(()=>[s(h,null,{default:e(()=>[s(o,{cols:"4",md:"2"},{default:e(()=>[y]),_:1}),s(o,{cols:"8",md:"10"},{default:e(()=>[z,C]),_:1}),s(o,{cols:"4",md:"2"},{default:e(()=>[v]),_:1}),s(o,{cols:"8",md:"10"},{default:e(()=>[$,H]),_:1}),s(o,{cols:"4",md:"2"},{default:e(()=>[T]),_:1}),s(o,{cols:"8",md:"10"},{default:e(()=>[V,B]),_:1}),s(o,{cols:"4",md:"2"},{default:e(()=>[N]),_:1}),s(o,{cols:"8",md:"10"},{default:e(()=>[R,D]),_:1}),s(o,{cols:"4",md:"2"},{default:e(()=>[Q]),_:1}),s(o,{cols:"8",md:"10"},{default:e(()=>[S,U]),_:1}),s(o,{cols:"4",md:"2"},{default:e(()=>[W]),_:1}),s(o,{cols:"8",md:"10"},{default:e(()=>[j,q]),_:1}),s(o,{cols:"4",md:"2"},{default:e(()=>[A]),_:1}),s(o,{cols:"8",md:"10"},{default:e(()=>[E,F]),_:1})]),_:1})]),_:1})]),_:1})}const I=c(k,[["render",G]]),L={__name:"typography",setup(a){return(i,J)=>(l(),n(h,null,{default:e(()=>[s(o,{cols:"12"},{default:e(()=>[s(w)]),_:1}),s(o,{cols:"12"},{default:e(()=>[s(I)]),_:1})]),_:1}))}};export{L as default};
import{aB as c,Q as l,R as n,S as e,D as s,W as d,U as _,a0 as t,_ as h,T as o}from"./index.a457a291.js";const u={},r=t("div",null,[t("h1",{class:"text-h1"}," Heading 1 "),t("span",null,"font-size: 6rem / line-height: 6rem / font-weight: 300")],-1),m=t("div",null,[t("h2",{class:"text-h2"}," Heading 2 "),t("span",null,"font-size: 3.75rem / line-height: 3.75rem / font-weight: 300")],-1),f=t("div",null,[t("h3",{class:"text-h3"}," Heading 3 "),t("span",null,"font-size: 3rem / line-height: 3.125rem / font-weight: 400")],-1),p=t("div",null,[t("h4",{class:"text-h4"}," Heading 4 "),t("span",null,"font-size: 2.125rem / line-height: 2.5rem / font-weight: 400")],-1),x=t("div",null,[t("h5",{class:"text-h5"}," Heading 5 "),t("span",null,"font-size: 1.5rem / line-height: 2rem / font-weight: 400")],-1),g=t("div",null,[t("h6",{class:"text-h6"}," Heading 6 "),t("span",null,"font-size: 1.25rem / line-height: 2rem / font-weight: 500")],-1);function b(a,i){return l(),n(_,{title:"Headlines"},{default:e(()=>[s(d,{class:"d-flex flex-column gap-y-8"},{default:e(()=>[r,m,f,p,x,g]),_:1})]),_:1})}const w=c(u,[["render",b]]),k={},y=t("span",{class:"text-subtitle-1 text-no-wrap"},"text-subtitle-1",-1),z=t("p",{class:"text-subtitle-1 text-truncate mb-0"}," Cupcake ipsum dolor sit amet fruitcake donut chocolate. ",-1),C=t("small",null,"font-size: 1rem / line-height: 1.75rem / font-weight: 400",-1),v=t("span",{class:"text-subtitle-2 text-no-wrap"},"text-subtitle-2",-1),$=t("p",{class:"text-subtitle-2 mb-0"}," Cupcake ipsum dolor sit amet fruitcake donut chocolate. ",-1),H=t("small",null,"font-size: 0.875rem / line-height: 1.375rem / font-weight: 500",-1),T=t("span",{class:"text-body-1 text-no-wrap"},"text-body-1",-1),V=t("p",{class:"text-body-1 mb-0"}," Cupcake ipsum dolor sit amet fruitcake donut chocolate. ",-1),B=t("small",null,"font-size: 1rem / line-height: 1.5rem / font-weight: 400",-1),N=t("span",{class:"text-body-2 text-no-wrap"},"text-body-2",-1),R=t("p",{class:"text-body-2 mb-0"}," Cupcake ipsum dolor sit amet fruitcake donut chocolate. ",-1),D=t("small",null,"font-size: 0.875rem / line-height: 1.25rem / font-weight: 400",-1),Q=t("span",{class:"text-caption"},"text-caption",-1),S=t("p",{class:"text-caption mb-0"}," Cupcake ipsum dolor sit amet fruitcake donut chocolate. ",-1),U=t("small",null,"font-size: 0.75rem / line-height: 1.25rem / font-weight: 400",-1),W=t("span",{class:"text-overline text-no-wrap"},"text-overline",-1),j=t("p",{class:"text-overline mb-0"}," Cupcake ipsum dolor sit amet fruitcake donut chocolate. ",-1),q=t("small",null,"font-size: 0.75rem / line-height: 2rem / font-weight: 500",-1),A=t("span",{class:"text-button"},"text-button",-1),E=t("p",{class:"text-button mb-0"}," Cupcake ipsum dolor sit amet fruitcake donut chocolate. ",-1),F=t("small",null,"font-size: 0.875rem / line-height: 2.25rem / font-weight: 500",-1);function G(a,i){return l(),n(_,{title:"Texts"},{default:e(()=>[s(d,null,{default:e(()=>[s(h,null,{default:e(()=>[s(o,{cols:"4",md:"2"},{default:e(()=>[y]),_:1}),s(o,{cols:"8",md:"10"},{default:e(()=>[z,C]),_:1}),s(o,{cols:"4",md:"2"},{default:e(()=>[v]),_:1}),s(o,{cols:"8",md:"10"},{default:e(()=>[$,H]),_:1}),s(o,{cols:"4",md:"2"},{default:e(()=>[T]),_:1}),s(o,{cols:"8",md:"10"},{default:e(()=>[V,B]),_:1}),s(o,{cols:"4",md:"2"},{default:e(()=>[N]),_:1}),s(o,{cols:"8",md:"10"},{default:e(()=>[R,D]),_:1}),s(o,{cols:"4",md:"2"},{default:e(()=>[Q]),_:1}),s(o,{cols:"8",md:"10"},{default:e(()=>[S,U]),_:1}),s(o,{cols:"4",md:"2"},{default:e(()=>[W]),_:1}),s(o,{cols:"8",md:"10"},{default:e(()=>[j,q]),_:1}),s(o,{cols:"4",md:"2"},{default:e(()=>[A]),_:1}),s(o,{cols:"8",md:"10"},{default:e(()=>[E,F]),_:1})]),_:1})]),_:1})]),_:1})}const I=c(k,[["render",G]]),L={__name:"typography",setup(a){return(i,J)=>(l(),n(h,null,{default:e(()=>[s(o,{cols:"12"},{default:e(()=>[s(w)]),_:1}),s(o,{cols:"12"},{default:e(()=>[s(I)]),_:1})]),_:1}))}};export{L as default};

View file

@ -7,8 +7,8 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>ChatGPT 工具箱</title>
<link rel="stylesheet" type="text/css" href="./loader.css" />
<script type="module" crossorigin src="./assets/index.f985de17.js"></script>
<link rel="stylesheet" href="./assets/index.7236eb96.css">
<script type="module" crossorigin src="./assets/index.a457a291.js"></script>
<link rel="stylesheet" href="./assets/index.6bc88549.css">
</head>
<body>

View file

@ -7,10 +7,11 @@ import fetch, {
import crypto from 'crypto'
import WebSocket from 'ws'
import { Config, pureSydneyInstruction } from './config.js'
import { formatDate, getMasterQQ, isCN, getUserData } from './common.js'
import { formatDate, getMasterQQ, isCN, getUserData, limitString } from './common.js'
import delay from 'delay'
import moment from 'moment'
import { getProxy } from './proxy.js'
import Version from './version.js'
if (!globalThis.fetch) {
globalThis.fetch = fetch
@ -80,7 +81,7 @@ export default class SydneyAIClient {
// 'x-ms-client-request-id': crypto.randomUUID(),
// 'x-ms-useragent': 'azsdk-js-api-client-factory/1.0.0-beta.1 core-rest-pipeline/1.10.3 OS/macOS',
// cookie: this.opts.cookies || `_U=${this.opts.userToken}`,
Referer: 'https://edgeservices.bing.com/edgesvc/chat?udsframed=1&form=SHORUN&clientscopes=chat,noheader,channelstable,',
Referer: 'https://edgeservices.bing.com/edgesvc/chat?udsframed=1&form=SHORUN&clientscopes=chat,noheader,channelstable,'
// 'Referrer-Policy': 'origin-when-cross-origin',
// Workaround for request being blocked due to geolocation
// 'x-forwarded-for': '1.1.1.1'
@ -100,12 +101,12 @@ export default class SydneyAIClient {
this.opts.host = 'https://edgeservices.bing.com/edgesvc'
}
logger.mark('使用host' + this.opts.host)
let response = await fetch(`${this.opts.host}/turing/conversation/create?bundleVersion=1.1055.6`, fetchOptions)
let response = await fetch(`${this.opts.host}/turing/conversation/create?bundleVersion=1.1055.10`, fetchOptions)
let text = await response.text()
let retry = 10
while (retry >= 0 && response.status === 200 && !text) {
await delay(400)
response = await fetch(`${this.opts.host}/turing/conversation/create`, fetchOptions)
response = await fetch(`${this.opts.host}/turing/conversation/create?bundleVersion=1.1055.10`, fetchOptions)
text = await response.text()
retry--
}
@ -137,8 +138,12 @@ export default class SydneyAIClient {
agent = proxy(this.opts.proxy)
}
if (Config.sydneyWebsocketUseProxy) {
if (!Config.sydneyReverseProxy) {
logger.warn('用户开启了对话反代,但是没有配置反代,忽略反代配置')
} else {
sydneyHost = Config.sydneyReverseProxy.replace('https://', 'wss://').replace('http://', 'ws://')
}
}
logger.mark(`use sydney websocket host: ${sydneyHost}`)
let host = sydneyHost + '/sydney/ChatHub'
if (encryptedconversationsignature) {
@ -221,8 +226,8 @@ export default class SydneyAIClient {
timeout = Config.defaultTimeoutMs,
firstMessageTimeout = Config.sydneyFirstMessageTimeout,
groupId, nickname, qq, groupName, chats, botName, masterName,
messageType = 'Chat'
messageType = 'Chat',
toSummaryFileContent
} = opts
// if (messageType === 'Chat') {
// logger.warn('该Bing账户token已被限流降级至使用非搜索模式。本次对话AI将无法使用Bing搜索返回的内容')
@ -371,6 +376,10 @@ export default class SydneyAIClient {
let maxConv = Config.maxNumUserMessagesInConversation
const currentDate = moment().format('YYYY-MM-DDTHH:mm:ssZ')
const imageDate = await this.kblobImage(opts.imageUrl)
if (toSummaryFileContent?.content) {
// message = `请不要进行搜索,用户的问题是:"${message}"`
messageType = 'Chat'
}
let argument0 = {
source: 'cib',
optionsSets,
@ -414,10 +423,12 @@ export default class SydneyAIClient {
text: message,
messageType,
userIpAddress: await generateRandomIP(),
timestamp: currentDate
timestamp: currentDate,
privacy: 'Internal'
// messageType: 'SearchQuery'
},
tone: 'Creative',
privacy: 'Internal',
conversationSignature,
participant: {
id: clientId
@ -439,7 +450,7 @@ export default class SydneyAIClient {
}
// simulates document summary function on Edge's Bing sidebar
// unknown character limit, at least up to 7k
if (groupId) {
if (groupId && !toSummaryFileContent?.content) {
context += '注意你现在正在一个qq群里和人聊天现在问你问题的人是' + `${nickname}(${qq})。`
if (Config.enforceMaster && master) {
if (qq === master) {
@ -461,13 +472,11 @@ export default class SydneyAIClient {
admin: '管理员'
}
if (chats) {
context += `以下是一段qq群内的对话提供给你作为上下文你在回答所有问题时必须优先考虑这些信息结合这些上下文进行回答这很重要。"
`
context += '以下是一段qq群内的对话提供给你作为上下文你在回答所有问题时必须优先考虑这些信息结合这些上下文进行回答这很重要。"'
context += chats
.map(chat => {
let sender = chat.sender || {}
// if (sender.user_id === Bot.uin && chat.raw_message.startsWith('建议的回复')) {
if (chat.raw_message.startsWith('建议的回复')) {
let sender = chat.sender || chat || {}
if (chat.raw_message?.startsWith('建议的回复')) {
// 建议的回复太容易污染设定导致对话太固定跑偏了
return ''
}
@ -486,7 +495,19 @@ export default class SydneyAIClient {
}).join('\n')
context += '\n'
}
if (context) {
if (toSummaryFileContent?.content) {
// 忽略context 不然可能会爆炸
obj.arguments[0].previousMessages.push({
author: 'user',
description: limitString(toSummaryFileContent?.content, 20000, true),
contextType: 'WebPage',
messageType: 'Context',
sourceName: toSummaryFileContent?.name,
sourceUrl: 'file:///C:/Users/turing/Downloads/Documents/' + toSummaryFileContent?.name || 'file.pdf',
// locale: 'und',
// privacy: 'Internal'
})
} else if (context) {
obj.arguments[0].previousMessages.push({
author: 'user',
description: context,
@ -655,7 +676,7 @@ export default class SydneyAIClient {
text: replySoFar.join('')
}
// 获取到图片内容
if (messages.some(obj => obj.contentType === "IMAGE")) {
if (messages.some(obj => obj.contentType === 'IMAGE')) {
message.imageTag = messages.filter(m => m.contentType === 'IMAGE').map(m => m.text).join('')
}
message.text = messages.filter(m => m.author === 'bot' && m.contentType != 'IMAGE').map(m => m.text).join('')

394
utils/alibaba/qwen-api.js Normal file
View file

@ -0,0 +1,394 @@
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (g && (g = 0, op[0] && (_ = 0)), _) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
import Keyv from 'keyv';
import pTimeout from 'p-timeout';
import QuickLRU from 'quick-lru';
import { v4 as uuidv4 } from 'uuid';
import * as tokenizer from './tokenizer.js';
import * as types from './types.js';
import globalFetch from 'node-fetch';
var CHATGPT_MODEL = 'qwen-turbo'; // qwen-plus
var USER_LABEL_DEFAULT = 'User';
var ASSISTANT_LABEL_DEFAULT = '同义千问';
var QwenApi = /** @class */ (function () {
/**
* Creates a new client wrapper around Qwen's chat completion API, mimicing the official ChatGPT webapp's functionality as closely as possible.
*
* @param opts
*/
function QwenApi(opts) {
var apiKey = opts.apiKey, _a = opts.apiBaseUrl, apiBaseUrl = _a === void 0 ? 'https://dashscope.aliyuncs.com/api/v1' : _a, _b = opts.debug, debug = _b === void 0 ? false : _b, messageStore = opts.messageStore, completionParams = opts.completionParams, parameters = opts.parameters, systemMessage = opts.systemMessage, getMessageById = opts.getMessageById, upsertMessage = opts.upsertMessage, _c = opts.fetch, fetch = _c === void 0 ? globalFetch : _c;
this._apiKey = apiKey;
this._apiBaseUrl = apiBaseUrl;
this._debug = !!debug;
this._fetch = fetch;
this._completionParams = __assign({ model: CHATGPT_MODEL, parameters: __assign({ top_p: 0.5, top_k: 50, temperature: 1.0, seed: 114514, enable_search: true, result_format: "text", incremental_output: false }, parameters) }, completionParams);
this._systemMessage = systemMessage;
if (this._systemMessage === undefined) {
var currentDate = new Date().toISOString().split('T')[0];
this._systemMessage = "You are ChatGPT, a large language model trained by Qwen. Answer as concisely as possible.\nKnowledge cutoff: 2021-09-01\nCurrent date: ".concat(currentDate);
}
this._getMessageById = getMessageById !== null && getMessageById !== void 0 ? getMessageById : this._defaultGetMessageById;
this._upsertMessage = upsertMessage !== null && upsertMessage !== void 0 ? upsertMessage : this._defaultUpsertMessage;
if (messageStore) {
this._messageStore = messageStore;
}
else {
this._messageStore = new Keyv({
store: new QuickLRU({ maxSize: 10000 })
});
}
if (!this._apiKey) {
throw new Error('Qwen missing required apiKey');
}
if (!this._fetch) {
throw new Error('Invalid environment; fetch is not defined');
}
if (typeof this._fetch !== 'function') {
throw new Error('Invalid "fetch" is not a function');
}
}
/**
* Sends a message to the Qwen chat completions endpoint, waits for the response
* to resolve, and returns the response.
*
* If you want your response to have historical context, you must provide a valid `parentMessageId`.
*
* If you want to receive a stream of partial responses, use `opts.onProgress`.
*
* Set `debug: true` in the `ChatGPTAPI` constructor to log more info on the full prompt sent to the Qwen chat completions API. You can override the `systemMessage` in `opts` to customize the assistant's instructions.
*
* @param message - The prompt message to send
* @param opts.parentMessageId - Optional ID of the previous message in the conversation (defaults to `undefined`)
* @param opts.conversationId - Optional ID of the conversation (defaults to `undefined`)
* @param opts.messageId - Optional ID of the message to send (defaults to a random UUID)
* @param opts.systemMessage - Optional override for the chat "system message" which acts as instructions to the model (defaults to the ChatGPT system message)
* @param opts.timeoutMs - Optional timeout in milliseconds (defaults to no timeout)
* @param opts.onProgress - Optional callback which will be invoked every time the partial response is updated
* @param opts.abortSignal - Optional callback used to abort the underlying `fetch` call using an [AbortController](https://developer.mozilla.org/en-US/docs/Web/API/AbortController)
* @param completionParams - Optional overrides to send to the [Qwen chat completion API](https://platform.openai.com/docs/api-reference/chat/create). Options like `temperature` and `presence_penalty` can be tweaked to change the personality of the assistant.
*
* @returns The response from ChatGPT
*/
QwenApi.prototype.sendMessage = function (text, opts, role) {
if (opts === void 0) { opts = {}; }
if (role === void 0) { role = 'user'; }
return __awaiter(this, void 0, void 0, function () {
var parentMessageId, _a, messageId, timeoutMs, completionParams, conversationId, abortSignal, abortController, message, latestQuestion, _b, messages, maxTokens, numTokens, result, responseP;
var _this = this;
return __generator(this, function (_c) {
switch (_c.label) {
case 0:
parentMessageId = opts.parentMessageId, _a = opts.messageId, messageId = _a === void 0 ? uuidv4() : _a, timeoutMs = opts.timeoutMs, completionParams = opts.completionParams, conversationId = opts.conversationId;
abortSignal = opts.abortSignal;
abortController = null;
if (timeoutMs && !abortSignal) {
abortController = new AbortController();
abortSignal = abortController.signal;
}
message = {
role: role,
id: messageId,
conversationId: conversationId,
parentMessageId: parentMessageId,
text: text,
};
latestQuestion = message;
return [4 /*yield*/, this._buildMessages(text, role, opts, completionParams)];
case 1:
_b = _c.sent(), messages = _b.messages, maxTokens = _b.maxTokens, numTokens = _b.numTokens;
console.log("maxTokens: ".concat(maxTokens, ", numTokens: ").concat(numTokens));
result = {
role: 'assistant',
id: uuidv4(),
conversationId: conversationId,
parentMessageId: messageId,
text: undefined,
};
this._completionParams.input = { messages: messages };
responseP = new Promise(function (resolve, reject) { return __awaiter(_this, void 0, void 0, function () {
var url, headers, body, res, reason, msg, error, response, err_1;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
url = "".concat(this._apiBaseUrl, "/services/aigc/text-generation/generation");
headers = {
'Content-Type': 'application/json',
Authorization: "Bearer ".concat(this._apiKey)
};
body = __assign(__assign({}, this._completionParams), completionParams);
if (this._debug) {
console.log(JSON.stringify(body));
}
if (this._debug) {
console.log("sendMessage (".concat(numTokens, " tokens)"), body);
}
_a.label = 1;
case 1:
_a.trys.push([1, 6, , 7]);
return [4 /*yield*/, this._fetch(url, {
method: 'POST',
headers: headers,
body: JSON.stringify(body),
signal: abortSignal
})];
case 2:
res = _a.sent();
if (!!res.ok) return [3 /*break*/, 4];
return [4 /*yield*/, res.text()];
case 3:
reason = _a.sent();
msg = "Qwen error ".concat(res.status || res.statusText, ": ").concat(reason);
error = new types.ChatGPTError(msg, { cause: res });
error.statusCode = res.status;
error.statusText = res.statusText;
return [2 /*return*/, reject(error)];
case 4: return [4 /*yield*/, res.json()];
case 5:
response = _a.sent();
if (this._debug) {
console.log(response);
}
if (response === null || response === void 0 ? void 0 : response.request_id) {
result.id = response.request_id;
}
result.detail = response;
result.text = response.output.text;
return [2 /*return*/, resolve(result)];
case 6:
err_1 = _a.sent();
return [2 /*return*/, reject(err_1)];
case 7: return [2 /*return*/];
}
});
}); }).then(function (message) { return __awaiter(_this, void 0, void 0, function () {
return __generator(this, function (_a) {
return [2 /*return*/, Promise.all([
this._upsertMessage(latestQuestion),
this._upsertMessage(message)
]).then(function () { return message; })];
});
}); });
if (timeoutMs) {
if (abortController) {
// This will be called when a timeout occurs in order for us to forcibly
// ensure that the underlying HTTP request is aborted.
;
responseP.cancel = function () {
abortController.abort();
};
}
return [2 /*return*/, pTimeout(responseP, {
milliseconds: timeoutMs,
message: 'Qwen timed out waiting for response'
})];
}
else {
return [2 /*return*/, responseP];
}
return [2 /*return*/];
}
});
});
};
Object.defineProperty(QwenApi.prototype, "apiKey", {
get: function () {
return this._apiKey;
},
set: function (apiKey) {
this._apiKey = apiKey;
},
enumerable: false,
configurable: true
});
QwenApi.prototype._buildMessages = function (text, role, opts, completionParams) {
return __awaiter(this, void 0, void 0, function () {
var _a, systemMessage, parentMessageId, userLabel, assistantLabel, maxNumTokens, messages, systemMessageOffset, nextMessages, functionToken, numTokens, prompt_1, nextNumTokensEstimate, _i, nextMessages_1, m1, _b, isValidPrompt, parentMessage, parentMessageRole, maxTokens;
return __generator(this, function (_c) {
switch (_c.label) {
case 0:
_a = opts.systemMessage, systemMessage = _a === void 0 ? this._systemMessage : _a;
parentMessageId = opts.parentMessageId;
userLabel = USER_LABEL_DEFAULT;
assistantLabel = ASSISTANT_LABEL_DEFAULT;
maxNumTokens = 6000;
messages = [];
if (systemMessage) {
messages.push({
role: 'system',
content: systemMessage
});
}
systemMessageOffset = messages.length;
nextMessages = text
? messages.concat([
{
role: role,
content: text
}
])
: messages;
functionToken = 0;
numTokens = functionToken;
_c.label = 1;
case 1:
prompt_1 = nextMessages
.reduce(function (prompt, message) {
switch (message.role) {
case 'system':
return prompt.concat(["Instructions:\n".concat(message.content)]);
case 'user':
return prompt.concat(["".concat(userLabel, ":\n").concat(message.content)]);
default:
return message.content ? prompt.concat(["".concat(assistantLabel, ":\n").concat(message.content)]) : prompt;
}
}, [])
.join('\n\n');
return [4 /*yield*/, this._getTokenCount(prompt_1)];
case 2:
nextNumTokensEstimate = _c.sent();
_i = 0, nextMessages_1 = nextMessages;
_c.label = 3;
case 3:
if (!(_i < nextMessages_1.length)) return [3 /*break*/, 6];
m1 = nextMessages_1[_i];
_b = nextNumTokensEstimate;
return [4 /*yield*/, this._getTokenCount('')];
case 4:
nextNumTokensEstimate = _b + _c.sent();
_c.label = 5;
case 5:
_i++;
return [3 /*break*/, 3];
case 6:
isValidPrompt = nextNumTokensEstimate + functionToken <= maxNumTokens;
if (prompt_1 && !isValidPrompt) {
return [3 /*break*/, 9];
}
messages = nextMessages;
numTokens = nextNumTokensEstimate + functionToken;
if (!isValidPrompt) {
return [3 /*break*/, 9];
}
if (!parentMessageId) {
return [3 /*break*/, 9];
}
return [4 /*yield*/, this._getMessageById(parentMessageId)];
case 7:
parentMessage = _c.sent();
if (!parentMessage) {
return [3 /*break*/, 9];
}
parentMessageRole = parentMessage.role || 'user';
nextMessages = nextMessages.slice(0, systemMessageOffset).concat(__spreadArray([
{
role: parentMessageRole,
content: parentMessage.text
}
], nextMessages.slice(systemMessageOffset), true));
parentMessageId = parentMessage.parentMessageId;
_c.label = 8;
case 8:
if (true) return [3 /*break*/, 1];
_c.label = 9;
case 9:
maxTokens = Math.max(1, Math.min(this._maxModelTokens - numTokens, this._maxResponseTokens));
return [2 /*return*/, { messages: messages, maxTokens: maxTokens, numTokens: numTokens }];
}
});
});
};
QwenApi.prototype._getTokenCount = function (text) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
if (!text) {
return [2 /*return*/, 0];
}
// TODO: use a better fix in the tokenizer
text = text.replace(/<\|endoftext\|>/g, '');
return [2 /*return*/, tokenizer.encode(text).length];
});
});
};
QwenApi.prototype._defaultGetMessageById = function (id) {
return __awaiter(this, void 0, void 0, function () {
var res;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this._messageStore.get(id)];
case 1:
res = _a.sent();
return [2 /*return*/, res];
}
});
});
};
QwenApi.prototype._defaultUpsertMessage = function (message) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this._messageStore.set(message.request_id, message)];
case 1:
_a.sent();
return [2 /*return*/];
}
});
});
};
return QwenApi;
}());
export { QwenApi };

382
utils/alibaba/qwen-api.ts Normal file
View file

@ -0,0 +1,382 @@
import Keyv from 'keyv'
import pTimeout from 'p-timeout'
import QuickLRU from 'quick-lru'
import { v4 as uuidv4 } from 'uuid'
import * as tokenizer from './tokenizer'
import * as types from './types'
import globalFetch from 'node-fetch'
import {qwen, Role} from "./types";
const CHATGPT_MODEL = 'qwen-turbo' // qwen-plus
const USER_LABEL_DEFAULT = 'User'
const ASSISTANT_LABEL_DEFAULT = '同义千问'
export class QwenApi {
protected _apiKey: string
protected _apiBaseUrl: string
protected _debug: boolean
protected _systemMessage: string
protected _completionParams: Omit<
types.qwen.CreateChatCompletionRequest,
'messages' | 'n'
>
protected _maxModelTokens: number
protected _maxResponseTokens: number
protected _fetch: types.FetchFn
protected _getMessageById: types.GetMessageByIdFunction
protected _upsertMessage: types.UpsertMessageFunction
protected _messageStore: Keyv<types.ChatMessage>
/**
* Creates a new client wrapper around Qwen's chat completion API, mimicing the official ChatGPT webapp's functionality as closely as possible.
*
* @param opts
*/
constructor(opts: types.QWenAPIOptions) {
const {
apiKey,
apiBaseUrl = 'https://dashscope.aliyuncs.com/api/v1',
debug = false,
messageStore,
completionParams,
parameters,
systemMessage,
getMessageById,
upsertMessage,
fetch = globalFetch
} = opts
this._apiKey = apiKey
this._apiBaseUrl = apiBaseUrl
this._debug = !!debug
this._fetch = fetch
this._completionParams = {
model: CHATGPT_MODEL,
parameters: {
top_p: 0.5,
top_k: 50,
temperature: 1.0,
seed: 114514,
enable_search: true,
result_format: "text",
incremental_output: false,
...parameters
},
...completionParams
}
this._systemMessage = systemMessage
if (this._systemMessage === undefined) {
const currentDate = new Date().toISOString().split('T')[0]
this._systemMessage = `You are ChatGPT, a large language model trained by Qwen. Answer as concisely as possible.\nKnowledge cutoff: 2021-09-01\nCurrent date: ${currentDate}`
}
this._getMessageById = getMessageById ?? this._defaultGetMessageById
this._upsertMessage = upsertMessage ?? this._defaultUpsertMessage
if (messageStore) {
this._messageStore = messageStore
} else {
this._messageStore = new Keyv<types.ChatMessage, any>({
store: new QuickLRU<string, types.ChatMessage>({ maxSize: 10000 })
})
}
if (!this._apiKey) {
throw new Error('Qwen missing required apiKey')
}
if (!this._fetch) {
throw new Error('Invalid environment; fetch is not defined')
}
if (typeof this._fetch !== 'function') {
throw new Error('Invalid "fetch" is not a function')
}
}
/**
* Sends a message to the Qwen chat completions endpoint, waits for the response
* to resolve, and returns the response.
*
* If you want your response to have historical context, you must provide a valid `parentMessageId`.
*
* If you want to receive a stream of partial responses, use `opts.onProgress`.
*
* Set `debug: true` in the `ChatGPTAPI` constructor to log more info on the full prompt sent to the Qwen chat completions API. You can override the `systemMessage` in `opts` to customize the assistant's instructions.
*
* @param message - The prompt message to send
* @param opts.parentMessageId - Optional ID of the previous message in the conversation (defaults to `undefined`)
* @param opts.conversationId - Optional ID of the conversation (defaults to `undefined`)
* @param opts.messageId - Optional ID of the message to send (defaults to a random UUID)
* @param opts.systemMessage - Optional override for the chat "system message" which acts as instructions to the model (defaults to the ChatGPT system message)
* @param opts.timeoutMs - Optional timeout in milliseconds (defaults to no timeout)
* @param opts.onProgress - Optional callback which will be invoked every time the partial response is updated
* @param opts.abortSignal - Optional callback used to abort the underlying `fetch` call using an [AbortController](https://developer.mozilla.org/en-US/docs/Web/API/AbortController)
* @param completionParams - Optional overrides to send to the [Qwen chat completion API](https://platform.openai.com/docs/api-reference/chat/create). Options like `temperature` and `presence_penalty` can be tweaked to change the personality of the assistant.
*
* @returns The response from ChatGPT
*/
async sendMessage(
text: string,
opts: types.SendMessageOptions = {},
role: Role = 'user',
): Promise<types.ChatMessage> {
const {
parentMessageId,
messageId = uuidv4(),
timeoutMs,
completionParams,
conversationId
} = opts
let { abortSignal } = opts
let abortController: AbortController = null
if (timeoutMs && !abortSignal) {
abortController = new AbortController()
abortSignal = abortController.signal
}
const message: types.ChatMessage = {
role,
id: messageId,
conversationId,
parentMessageId,
text,
}
const latestQuestion = message
const { messages, maxTokens, numTokens } = await this._buildMessages(
text,
role,
opts,
completionParams
)
console.log(`maxTokens: ${maxTokens}, numTokens: ${numTokens}`)
const result: types.ChatMessage = {
role: 'assistant',
id: uuidv4(),
conversationId,
parentMessageId: messageId,
text: undefined,
}
this._completionParams.input = { messages }
const responseP = new Promise<types.ChatMessage>(
async (resolve, reject) => {
const url = `${this._apiBaseUrl}/services/aigc/text-generation/generation`
const headers = {
'Content-Type': 'application/json',
Authorization: `Bearer ${this._apiKey}`
}
const body = {
...this._completionParams,
...completionParams
}
if (this._debug) {
console.log(JSON.stringify(body))
}
if (this._debug) {
console.log(`sendMessage (${numTokens} tokens)`, body)
}
try {
const res = await this._fetch(url, {
method: 'POST',
headers,
body: JSON.stringify(body),
signal: abortSignal
})
if (!res.ok) {
const reason = await res.text()
const msg = `Qwen error ${
res.status || res.statusText
}: ${reason}`
const error = new types.ChatGPTError(msg, { cause: res })
error.statusCode = res.status
error.statusText = res.statusText
return reject(error)
}
const response: types.qwen.CreateChatCompletionResponse =
await res.json()
if (this._debug) {
console.log(response)
}
if (response?.request_id) {
result.id = response.request_id
}
result.detail = response
result.text = response.output.text
return resolve(result)
} catch (err) {
return reject(err)
}
}
).then(async (message) => {
return Promise.all([
this._upsertMessage(latestQuestion),
this._upsertMessage(message)
]).then(() => message)
})
if (timeoutMs) {
if (abortController) {
// This will be called when a timeout occurs in order for us to forcibly
// ensure that the underlying HTTP request is aborted.
;(responseP as any).cancel = () => {
abortController.abort()
}
}
return pTimeout(responseP, {
milliseconds: timeoutMs,
message: 'Qwen timed out waiting for response'
})
} else {
return responseP
}
}
get apiKey(): string {
return this._apiKey
}
set apiKey(apiKey: string) {
this._apiKey = apiKey
}
protected async _buildMessages(text: string, role: Role, opts: types.SendMessageOptions, completionParams: Partial<
Omit<qwen.CreateChatCompletionRequest, 'messages' | 'n' | 'stream'>
>) {
const { systemMessage = this._systemMessage } = opts
let { parentMessageId } = opts
const userLabel = USER_LABEL_DEFAULT
const assistantLabel = ASSISTANT_LABEL_DEFAULT
// fix number of qwen
const maxNumTokens = 6000
let messages: types.qwen.ChatCompletionRequestMessage[] = []
if (systemMessage) {
messages.push({
role: 'system',
content: systemMessage
})
}
const systemMessageOffset = messages.length
let nextMessages = text
? messages.concat([
{
role,
content: text
}
])
: messages
let functionToken = 0
let numTokens = functionToken
do {
const prompt = nextMessages
.reduce((prompt, message) => {
switch (message.role) {
case 'system':
return prompt.concat([`Instructions:\n${message.content}`])
case 'user':
return prompt.concat([`${userLabel}:\n${message.content}`])
default:
return message.content ? prompt.concat([`${assistantLabel}:\n${message.content}`]) : prompt
}
}, [] as string[])
.join('\n\n')
let nextNumTokensEstimate = await this._getTokenCount(prompt)
for (const m1 of nextMessages) {
nextNumTokensEstimate += await this._getTokenCount('')
}
const isValidPrompt = nextNumTokensEstimate + functionToken <= maxNumTokens
if (prompt && !isValidPrompt) {
break
}
messages = nextMessages
numTokens = nextNumTokensEstimate + functionToken
if (!isValidPrompt) {
break
}
if (!parentMessageId) {
break
}
const parentMessage = await this._getMessageById(parentMessageId)
if (!parentMessage) {
break
}
const parentMessageRole = parentMessage.role || 'user'
nextMessages = nextMessages.slice(0, systemMessageOffset).concat([
{
role: parentMessageRole,
content: parentMessage.text
},
...nextMessages.slice(systemMessageOffset)
])
parentMessageId = parentMessage.parentMessageId
} while (true)
// Use up to 4096 tokens (prompt + response), but try to leave 1000 tokens
// for the response.
const maxTokens = Math.max(
1,
Math.min(this._maxModelTokens - numTokens, this._maxResponseTokens)
)
return { messages, maxTokens, numTokens }
}
protected async _getTokenCount(text: string) {
if (!text) {
return 0
}
// TODO: use a better fix in the tokenizer
text = text.replace(/<\|endoftext\|>/g, '')
return tokenizer.encode(text).length
}
protected async _defaultGetMessageById(
id: string
): Promise<types.ChatMessage> {
const res = await this._messageStore.get(id)
return res
}
protected async _defaultUpsertMessage(
message: types.ChatMessage
): Promise<void> {
await this._messageStore.set(message.request_id, message)
}
}

View file

@ -0,0 +1,6 @@
import { getEncoding } from 'js-tiktoken';
// TODO: make this configurable
var tokenizer = getEncoding('cl100k_base');
export function encode(input) {
return new Uint32Array(tokenizer.encode(input));
}

View file

@ -0,0 +1,8 @@
import { getEncoding } from 'js-tiktoken'
// TODO: make this configurable
const tokenizer = getEncoding('cl100k_base')
export function encode(input: string): Uint32Array {
return new Uint32Array(tokenizer.encode(input))
}

View file

@ -0,0 +1,5 @@
{
"compilerOptions": {
"module": "es2020"
}
}

26
utils/alibaba/types.js Normal file
View file

@ -0,0 +1,26 @@
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var ChatGPTError = /** @class */ (function (_super) {
__extends(ChatGPTError, _super);
function ChatGPTError() {
return _super !== null && _super.apply(this, arguments) || this;
}
return ChatGPTError;
}(Error));
export { ChatGPTError };
export var qwen;
(function (qwen) {
})(qwen || (qwen = {}));

313
utils/alibaba/types.ts Normal file
View file

@ -0,0 +1,313 @@
import Keyv from 'keyv'
export type Role = 'user' | 'assistant' | 'system'
export type FetchFn = typeof fetch
export type QWenAPIOptions = {
apiKey: string
/** @defaultValue `'https://dashscope.aliyuncs.com/api/v1'` **/
apiBaseUrl?: string
apiOrg?: string
/** @defaultValue `false` **/
debug?: boolean
completionParams?: Partial<
Omit<qwen.CreateChatCompletionRequest, 'messages' | 'n' | 'stream'>
>
parameters?: qwen.QWenParameters,
systemMessage?: string
messageStore?: Keyv
getMessageById?: GetMessageByIdFunction
upsertMessage?: UpsertMessageFunction
fetch?: FetchFn
}
export type SendMessageOptions = {
/**
* function role name
*/
name?: string
messageId?: string
stream?: boolean
systemMessage?: string
parentMessageId?: string
conversationId?: string
timeoutMs?: number
onProgress?: (partialResponse: ChatMessage) => void
abortSignal?: AbortSignal
completionParams?: Partial<
Omit<qwen.CreateChatCompletionRequest, 'messages' | 'n' | 'stream'>
>
}
export type MessageActionType = 'next' | 'variant'
export type SendMessageBrowserOptions = {
conversationId?: string
parentMessageId?: string
messageId?: string
action?: MessageActionType
timeoutMs?: number
onProgress?: (partialResponse: ChatMessage) => void
abortSignal?: AbortSignal
}
export interface ChatMessage {
id: string
text: string
role: Role
parentMessageId?: string
conversationId?: string
detail?:
| qwen.CreateChatCompletionResponse
| CreateChatCompletionStreamResponse
}
export class ChatGPTError extends Error {
statusCode?: number
statusText?: string
isFinal?: boolean
accountId?: string
}
/** Returns a chat message from a store by it's ID (or null if not found). */
export type GetMessageByIdFunction = (id: string) => Promise<ChatMessage>
/** Upserts a chat message to a store. */
export type UpsertMessageFunction = (message: ChatMessage) => Promise<void>
export interface CreateChatCompletionStreamResponse
extends openai.CreateChatCompletionDeltaResponse {
usage: CreateCompletionStreamResponseUsage
}
export interface CreateCompletionStreamResponseUsage
extends openai.CreateCompletionResponseUsage {
estimated: true
}
/**
* https://chat.openapi.com/backend-api/conversation
*/
export type ConversationJSONBody = {
/**
* The action to take
*/
action: string
/**
* The ID of the conversation
*/
conversation_id?: string
/**
* Prompts to provide
*/
messages: Prompt[]
/**
* The model to use
*/
model: string
/**
* The parent message ID
*/
parent_message_id: string
}
export type Prompt = {
/**
* The content of the prompt
*/
content: PromptContent
/**
* The ID of the prompt
*/
id: string
/**
* The role played in the prompt
*/
role: Role
}
export type ContentType = 'text'
export type PromptContent = {
/**
* The content type of the prompt
*/
content_type: ContentType
/**
* The parts to the prompt
*/
parts: string[]
}
export type ConversationResponseEvent = {
message?: Message
conversation_id?: string
error?: string | null
}
export type Message = {
id: string
content: MessageContent
role: Role
user: string | null
create_time: string | null
update_time: string | null
end_turn: null
weight: number
recipient: string
metadata: MessageMetadata
}
export type MessageContent = {
content_type: string
parts: string[]
}
export type MessageMetadata = any
export namespace qwen {
export interface CreateChatCompletionDeltaResponse {
id: string
object: 'chat.completion.chunk'
created: number
model: string
choices: [
{
delta: {
role: Role
content?: string,
function_call?: {name: string, arguments: string}
}
index: number
finish_reason: string | null
}
]
}
/**
*
* @export
* @interface ChatCompletionRequestMessage
*/
export interface ChatCompletionRequestMessage {
/**
* The role of the author of this message.
* @type {string}
* @memberof ChatCompletionRequestMessage
*/
role: ChatCompletionRequestMessageRoleEnum
/**
* The contents of the message
* @type {string}
* @memberof ChatCompletionRequestMessage
*/
content: string
}
export declare const ChatCompletionRequestMessageRoleEnum: {
readonly System: 'system'
readonly User: 'user'
readonly Assistant: 'assistant'
}
export declare type ChatCompletionRequestMessageRoleEnum =
(typeof ChatCompletionRequestMessageRoleEnum)[keyof typeof ChatCompletionRequestMessageRoleEnum]
export interface QWenInput {
messages: Array<ChatCompletionRequestMessage>
}
export interface QWenParameters {
result_format: string
top_p: number
top_k: number
seed: number
temperature: number
enable_search: boolean
incremental_output: boolean
}
/**
*
* @export
* @interface CreateChatCompletionRequest
*/
export interface CreateChatCompletionRequest {
/**
* ID of the model to use. Currently, only `gpt-3.5-turbo` and `gpt-3.5-turbo-0301` are supported.
* @type {string}
* @memberof CreateChatCompletionRequest
*/
model: string
/**
* The messages to generate chat completions for, in the [chat format](/docs/guides/chat/introduction).
* @type {Array<ChatCompletionRequestMessage>}
* @memberof CreateChatCompletionRequest
*/
input?: QWenInput
parameters: QWenParameters
}
/**
*
* @export
* @interface CreateChatCompletionResponse
*/
export interface CreateChatCompletionResponse {
/**
*
* @type {string}
* @memberof CreateChatCompletionResponse
*/
request_id: string
/**
*
* @type {QWenOutput}
* @memberof CreateChatCompletionResponse
*/
output: QWenOutput
/**
*
* @type {CreateCompletionResponseUsage}
* @memberof CreateChatCompletionResponse
*/
usage?: CreateCompletionResponseUsage
}
export interface QWenOutput {
finish_reason: string
text: string
}
/**
*
* @export
* @interface CreateCompletionResponseUsage
*/
export interface CreateCompletionResponseUsage {
/**
*
* @type {number}
* @memberof CreateCompletionResponseUsage
*/
input_tokens: number
/**
*
* @type {number}
* @memberof CreateCompletionResponseUsage
*/
output_tokens: number
}
}

71
utils/bilibili/wbi.js Normal file
View file

@ -0,0 +1,71 @@
import md5 from 'md5'
import fetch from 'node-fetch'
const mixinKeyEncTab = [
46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5, 49,
33, 9, 42, 19, 29, 28, 14, 39, 12, 38, 41, 13, 37, 48, 7, 16, 24, 55, 40,
61, 26, 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63, 57, 62, 11,
36, 20, 34, 44, 52
]
// 对 imgKey 和 subKey 进行字符顺序打乱编码
function getMixinKey (orig) {
let temp = ''
mixinKeyEncTab.forEach((n) => {
temp += orig[n]
})
return temp.slice(0, 32)
}
// 为请求参数进行 wbi 签名
function encWbi (params, imgKey, subKey) {
const mixinKey = getMixinKey(imgKey + subKey)
const currTime = Math.round(Date.now() / 1000)
const chrFilter = /[!'()*]/g
let query = []
Object.assign(params, { wts: currTime }) // 添加 wts 字段
// 按照 key 重排参数
Object.keys(params).sort().forEach((key) => {
query.push(
`${encodeURIComponent(key)}=${encodeURIComponent(
// 过滤 value 中的 "!'()*" 字符
params[key].toString().replace(chrFilter, '')
)}`
)
})
query = query.join('&')
const wbiSign = md5(query + mixinKey) // 计算 w_rid
return query + '&w_rid=' + wbiSign
}
// 获取最新的 img_key 和 sub_key
async function getWbiKeys () {
const resp = await fetch('https://api.bilibili.com/x/web-interface/nav')
const jsonContent = resp.data
const imgUrl = jsonContent.data.wbi_img.img_url
const subUrl = jsonContent.data.wbi_img.sub_url
return {
img_key: imgUrl.slice(
imgUrl.lastIndexOf('/') + 1,
imgUrl.lastIndexOf('.')
),
sub_key: subUrl.slice(
subUrl.lastIndexOf('/') + 1,
subUrl.lastIndexOf('.')
)
}
}
// getWbiKeys().then((wbi_keys) => {
// const query = encWbi(
// {
// foo: '114',
// bar: '514',
// baz: 1919810
// },
// wbi_keys.img_key,
// wbi_keys.sub_key
// )
// console.log(query)
// })

34
utils/chat.js Normal file
View file

@ -0,0 +1,34 @@
export async function getChatHistoryGroup (e, num) {
// if (e.adapter === 'shamrock') {
// return await e.group.getChatHistory(0, num, false)
// } else {
let latestChats = await e.group.getChatHistory(0, 1)
if (latestChats.length > 0) {
let latestChat = latestChats[0]
if (latestChat) {
let seq = latestChat.seq || latestChat.message_id
let chats = []
while (chats.length < num) {
let chatHistory = await e.group.getChatHistory(seq, 20)
chats.push(...chatHistory)
seq = chatHistory[0].seq || chatHistory[0].message_id
}
chats = chats.slice(0, num)
try {
let mm = await e.group.getMemberMap()
chats.forEach(chat => {
let sender = mm.get(chat.sender.user_id)
if (sender) {
chat.sender = sender
}
})
} catch (err) {
logger.warn(err)
}
// console.log(chats)
return chats
}
}
// }
return []
}

View file

@ -186,6 +186,7 @@ export class ClaudeAIClient {
} else if (streamDataRes.status === 408) {
throw new Error('claude.ai响应超时可能是回复文本太多请调高超时时间重试')
} else {
logger.error(streamDataRes.status, streamDataRes.body)
throw new Error('unknown error')
}
}

View file

@ -1,24 +1,38 @@
// import { remark } from 'remark'
// import stripMarkdown from 'strip-markdown'
import {exec} from 'child_process'
import { exec } from 'child_process'
import lodash from 'lodash'
import fs from 'node:fs'
import path from 'node:path'
import buffer from 'buffer'
import yaml from 'yaml'
import puppeteer from '../../../lib/puppeteer/puppeteer.js'
import {Config} from './config.js'
import {convertSpeaker, generateVitsAudio, speakers as vitsRoleList} from './tts.js'
import VoiceVoxTTS, {supportConfigurations as voxRoleList} from './tts/voicevox.js'
import AzureTTS, {supportConfigurations as azureRoleList} from './tts/microsoft-azure.js'
import {translate} from './translate.js'
import common from '../../../lib/common/common.js'
import { Config } from './config.js'
import { convertSpeaker, generateVitsAudio, speakers as vitsRoleList } from './tts.js'
import VoiceVoxTTS, { supportConfigurations as voxRoleList } from './tts/voicevox.js'
import AzureTTS, { supportConfigurations as azureRoleList } from './tts/microsoft-azure.js'
import { translate } from './translate.js'
import uploadRecord from './uploadRecord.js'
// export function markdownToText (markdown) {
// return remark()
// .use(stripMarkdown)
// .processSync(markdown ?? '')
// .toString()
// }
import Version from './version.js'
import fetch from 'node-fetch'
let pdfjsLib
try {
pdfjsLib = (await import('pdfjs-dist')).default
} catch (err) {}
let mammoth
try {
mammoth = (await import('mammoth')).default
} catch (err) {}
let XLSX
try {
XLSX = (await import('xlsx')).default
} catch (err) {}
let PPTX
try {
PPTX = (await import('nodejs-pptx')).default
} catch (err) {}
let _puppeteer
try {
@ -59,12 +73,18 @@ export function randomString (length = 5) {
return str.substr(0, length)
}
export async function upsertMessage (message) {
await redis.set(`CHATGPT:MESSAGE:${message.id}`, JSON.stringify(message))
export async function upsertMessage (message, suffix = '') {
if (suffix) {
suffix = '_' + suffix
}
await redis.set(`CHATGPT:MESSAGE${suffix}:${message.id}`, JSON.stringify(message))
}
export async function getMessageById (id) {
let messageStr = await redis.get(`CHATGPT:MESSAGE:${id}`)
export async function getMessageById (id, suffix = '') {
if (suffix) {
suffix = '_' + suffix
}
let messageStr = await redis.get(`CHATGPT:MESSAGE${suffix}:${id}`)
return JSON.parse(messageStr)
}
@ -81,17 +101,20 @@ export async function tryTimes (promiseFn, maxTries = 10) {
}
export async function makeForwardMsg (e, msg = [], dec = '') {
let nickname = Bot.nickname
if (Version.isTrss) {
return common.makeForwardMsg(e, msg, dec)
}
let nickname = e.bot.nickname
if (e.isGroup) {
try {
let info = await Bot.getGroupMemberInfo(e.group_id, Bot.uin)
let info = await e.bot.getGroupMemberInfo(e.group_id, getUin(e))
nickname = info.card || info.nickname
} catch (err) {
console.error(`Failed to get group member info: ${err}`)
}
}
let userInfo = {
user_id: Bot.uin,
user_id: getUin(e),
nickname
}
@ -109,7 +132,7 @@ export async function makeForwardMsg (e, msg = [], dec = '') {
} else if (e.friend) {
forwardMsg = await e.friend.makeForwardMsg(forwardMsg)
} else {
return false
return msg.join('\n')
}
let forwardMsg_json = forwardMsg.data
if (typeof (forwardMsg_json) === 'object') {
@ -787,7 +810,7 @@ export async function getImageOcrText (e) {
let resultArr = []
let eachImgRes = ''
for (let i in img) {
const imgOCR = await Bot.imageOcr(img[i])
const imgOCR = await e.bot.imageOcr(img[i])
for (let text of imgOCR.wordslist) {
eachImgRes += (`${text?.words} \n`)
}
@ -797,6 +820,7 @@ export async function getImageOcrText (e) {
// logger.warn('resultArr', resultArr)
return resultArr
} catch (err) {
logger.warn('OCR失败可能使用的适配器不支持OCR')
return false
// logger.error(err)
}
@ -809,8 +833,10 @@ export function getMaxModelTokens (model = 'gpt-3.5-turbo') {
if (model.startsWith('gpt-3.5-turbo')) {
if (model.includes('16k')) {
return 16000
} else {
} else if (model.includes('0613') || model.includes('0314')) {
return 4000
} else {
return 16000
}
} else {
if (model.includes('32k')) {
@ -821,6 +847,20 @@ export function getMaxModelTokens (model = 'gpt-3.5-turbo') {
}
}
export function getUin (e) {
if (e?.bot?.uin) return e.bot.uin
if (Array.isArray(Bot.uin)) {
if (Config.trssBotUin && Bot.uin.indexOf(Config.trssBotUin) > -1) { return Config.trssBotUin } else {
Bot.uin.forEach((u) => {
if (Bot[u].self_id) {
return Bot[u].self_id
}
})
return Bot.uin[Bot.uin.length - 1]
}
} else return Bot.uin
}
/**
* 生成当前语音模式下可发送的音频信息
* @param e - 上下文对象
@ -833,6 +873,7 @@ export async function generateAudio (e, pendingText, speakingEmotion, emotionDeg
if (!Config.ttsSpace && !Config.azureTTSKey && !Config.voicevoxSpace) return false
let wav
const speaker = getUserSpeaker(await getUserReplySetting(e))
let ignoreEncode = e.adapter === 'shamrock'
try {
if (Config.ttsMode === 'vits-uma-genshin-honkai' && Config.ttsSpace) {
if (Config.autoJapanese) {
@ -845,7 +886,7 @@ export async function generateAudio (e, pendingText, speakingEmotion, emotionDeg
}
wav = await generateVitsAudio(pendingText, speaker, '中日混合(中文用[ZH][ZH]包裹起来,日文用[JA][JA]包裹起来)')
} else if (Config.ttsMode === 'azure' && Config.azureTTSKey) {
return await generateAzureAudio(pendingText, speaker, speakingEmotion, emotionDegree)
return await generateAzureAudio(pendingText, speaker, speakingEmotion, emotionDegree, ignoreEncode)
} else if (Config.ttsMode === 'voicevox' && Config.voicevoxSpace) {
pendingText = (await translate(pendingText, '日')).replace('\n', '')
wav = await VoiceVoxTTS.generateAudio(pendingText, {
@ -859,7 +900,7 @@ export async function generateAudio (e, pendingText, speakingEmotion, emotionDeg
let sendable
try {
try {
sendable = await uploadRecord(wav, Config.ttsMode)
sendable = await uploadRecord(wav, Config.ttsMode, ignoreEncode)
if (!sendable) {
// 如果合成失败尝试使用ffmpeg合成
sendable = segment.record(wav)
@ -889,9 +930,10 @@ export async function generateAudio (e, pendingText, speakingEmotion, emotionDeg
* @param role - 发言人
* @param speakingEmotion - 发言人情绪
* @param emotionDegree - 发言人情绪强度
* @param ignoreEncode - 不在客户端处理编码
* @returns {Promise<{file: string, type: string}|boolean>}
*/
export async function generateAzureAudio (pendingText, role = '随机', speakingEmotion, emotionDegree = 1) {
export async function generateAzureAudio (pendingText, role = '随机', speakingEmotion, emotionDegree = 1, ignoreEncode = false) {
if (!Config.azureTTSKey) return false
let speaker
try {
@ -911,7 +953,6 @@ export async function generateAzureAudio (pendingText, role = '随机', speaking
let languagePrefix = azureRoleList.find(config => config.code === speaker).languageDetail.charAt(0)
languagePrefix = languagePrefix.startsWith('E') ? '英' : languagePrefix
pendingText = (await translate(pendingText, languagePrefix)).replace('\n', '')
} else {
let role, languagePrefix
role = azureRoleList[Math.floor(Math.random() * azureRoleList.length)]
@ -933,11 +974,13 @@ export async function generateAzureAudio (pendingText, role = '随机', speaking
pendingText,
emotionDegree
})
return await uploadRecord(
await AzureTTS.generateAudio(pendingText, {
let record = await AzureTTS.generateAudio(pendingText, {
speaker
}, await ssml)
, Config.ttsMode
return await uploadRecord(
record
, Config.ttsMode,
ignoreEncode
)
} catch (err) {
logger.error(err)
@ -954,3 +997,208 @@ export function getUserSpeaker (userSetting) {
}
}
/**
*
* @param url 要下载的文件链接
* @param destPath 目标路径如received/abc.pdf. 目前如果文件名重复会覆盖
* @param absolute 是否是绝对路径默认为false此时拼接在data/chatgpt下
* @returns {Promise<string>} 最终下载文件的存储位置
*/
export async function downloadFile (url, destPath, absolute = false) {
let response = await fetch(url)
if (!response.ok) {
throw new Error(`download file http error: status: ${response.status}`)
}
let dest = destPath
if (!absolute) {
const _path = process.cwd()
dest = path.join(_path, 'data', 'chatgpt', dest)
const lastLevelDirPath = path.dirname(dest)
mkdirs(lastLevelDirPath)
}
const fileStream = fs.createWriteStream(dest)
await new Promise((resolve, reject) => {
response.body.pipe(fileStream)
response.body.on('error', err => {
reject(err)
})
fileStream.on('finish', function () {
resolve()
})
})
logger.info(`File downloaded successfully! URL: ${url}, Destination: ${dest}`)
return dest
}
export function isPureText (filename) {
const ext = path.extname(filename).toLowerCase()
// List of file extensions that can be treated as pure text
const textFileExtensions = ['.txt', '.log', '.md', '.csv', '.html', '.css', '.js', '.json', '.xml', '.py', '.java', '.cpp', '.c', '.rb', '.php', '.sql', '.sh', '.pl', '.r', '.swift', '.go', '.ts', '.htm', '.yaml', '.yml', '.ini', '.properties', '.tsv']
// File types that require additional processing
const processingExtensions = ['.docx', '.pptx', '.xlsx', '.pdf', '.epub']
if (textFileExtensions.includes(ext)) {
return 'text'
} else if (processingExtensions.includes(ext)) {
// Return the file extension if additional processing is needed
return ext.replace('.', '')
} else {
return false
}
}
/**
* 从文件中提取文本内容
* @param fileMsgElem MessageElem
* @param e
* @returns {Promise<{}>} 提取的文本内容和文件名
*/
export async function extractContentFromFile (fileMsgElem, e) {
logger.info('filename: ' + fileMsgElem.name)
let fileType = isPureText(fileMsgElem.name)
if (fileType) {
// 可读的文件类型
let fileUrl = e.isGroup ? await e.group.getFileUrl(fileMsgElem.fid) : await e.friend.getFileUrl(fileMsgElem.fid)
let filePath = await downloadFile(fileUrl, path.join('received', fileMsgElem.name))
switch (fileType) {
case 'pdf': {
if (!pdfjsLib) {
return {}
}
const data = new Uint8Array(fs.readFileSync(filePath))
let loadingTask = pdfjsLib.getDocument(data)
try {
const pdfDocument = await loadingTask.promise
const numPages = pdfDocument.numPages
let pdfText = ''
// limit pages to prevent OOM or LLM down
let maxPage = 100
// Iterate through each page and extract text
for (let pageNum = 1; pageNum <= Math.min(numPages, maxPage); ++pageNum) {
const page = await pdfDocument.getPage(pageNum)
const textContent = await page.getTextContent()
const pageText = textContent.items.map(item => item.str).join(' ')
pdfText += pageText
}
return {
content: pdfText,
name: fileMsgElem.name
}
} catch (error) {
console.error('Error reading PDF file:', error)
return {}
}
}
case 'doc': {
logger.error('not supported file type now')
return ''
}
case 'docx': {
if (!mammoth) {
return {}
}
try {
const { value } = await mammoth.extractRawText({ path: filePath })
return {
content: value,
name: fileMsgElem.name
}
} catch (error) {
logger.error('Error reading .docx file:', error)
return {}
}
}
case 'xls': {
logger.error('not supported file type now')
return {}
}
case 'xlsx': {
if (!XLSX) {
return {}
}
try {
const workbook = XLSX.readFile(filePath)
const sheetName = workbook.SheetNames[0] // Assuming the first sheet is the one you want to read
const sheet = workbook.Sheets[sheetName]
const data = XLSX.utils.sheet_to_json(sheet, { header: 1 })
// Convert the 2D array to plain text
return {
content: data.map(row => row.join('\t')).join('\n'),
name: fileMsgElem.name
}
} catch (error) {
console.error('Error reading .xlsx file:', error)
return {}
}
}
case 'ppt': {
logger.error('not supported file type now')
return {}
}
case 'pptx': {
if (!PPTX) {
return {}
}
try {
let pptx = new PPTX.Composer()
await pptx.load(filePath)
let presentationContent = []
let slideNumber = 1
let maxSlideNumber = 60
while (slideNumber <= maxSlideNumber) {
let slide
try {
slide = pptx.getSlide(slideNumber)
} catch (error) {
// Slide number out of range, break the loop
break
}
let slideContent = []
// Iterate through slide elements and extract text content
slide.elements.forEach(element => {
if (element.text) {
slideContent.push(element.text)
}
})
// Add slide content to the presentation content array
presentationContent.push(slideContent.join('\n'))
// Move to the next slide
slideNumber++
}
return {
content: presentationContent.join('\n'),
name: fileMsgElem.name
}
} catch (error) {
console.error('Error reading .pptx file:', error)
return {}
}
}
case 'epub': {
logger.error('not supported file type now')
return {}
}
default: {
// text type
const data = fs.readFileSync(filePath)
let text = String(data)
if (text) {
return {
content: text,
name: fileMsgElem.name
}
}
}
}
return {}
}
}

View file

@ -30,11 +30,11 @@ const defaultConfig = {
drawCD: 30,
model: '',
temperature: 0.8,
toneStyle: 'balanced', // or creative, precise
toneStyle: 'Sydney', // or creative, precise
sydney: pureSydneyInstruction,
sydneyReverseProxy: 'https://666102.201666.xyz',
sydneyForceUseReverse: false,
sydneyWebsocketUseProxy: false,
sydneyWebsocketUseProxy: true,
sydneyBrainWash: true,
sydneyBrainWashStrength: 15,
sydneyBrainWashName: 'Sydney',
@ -93,9 +93,10 @@ const defaultConfig = {
groupContextTip: '你看看我们群里的聊天记录吧,回答问题的时候要主动参考我们的聊天记录进行回答或提问。但要看清楚哦,不要把我和其他人弄混啦,也不要把自己看晕啦~~',
groupContextLength: 50,
enableRobotAt: true,
maxNumUserMessagesInConversation: 20,
maxNumUserMessagesInConversation: 30,
sydneyApologyIgnored: true,
enforceMaster: false,
bingAPDraw: false,
serverPort: 3321,
serverHost: '',
viewHost: '',
@ -144,7 +145,7 @@ const defaultConfig = {
serpSource: 'ikechan8370',
extraUrl: 'https://cpe.ikechan8370.com',
smartMode: false,
bingCaptchaOneShotUrl: 'http://bingcaptcha.ikechan8370.com/bing',
bingCaptchaOneShotUrl: '',
// claude2
claudeAIOrganizationId: '',
claudeAISessionKey: '',
@ -152,7 +153,17 @@ const defaultConfig = {
claudeAITimeout: 120,
claudeAIJA3: '772,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,27-5-65281-13-35-0-51-18-16-43-10-45-11-17513-23,29-23-24,0',
claudeAIUA: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36',
version: 'v2.7.5'
// trss配置
trssBotUin: '',
// 同义千问
qwenApiKey: '',
qwenModel: 'qwen-turbo',
qwenTopP: 0.5,
qwenTopK: 50,
qwenSeed: 0,
qwenTemperature: 1,
qwenEnableSearch: true,
version: 'v2.7.7'
}
const _path = process.cwd()
let config = {}

View file

@ -1,278 +0,0 @@
import { readFileSync } from 'fs'
import { scrape } from './credential.js'
import fetch from 'node-fetch'
import crypto from 'crypto'
// used when test as a single file
// const _path = process.cwd()
const _path = process.cwd() + '/plugins/chatgpt-plugin/utils/poe'
const gqlDir = `${_path}/graphql`
const queries = {
// chatViewQuery: readFileSync(gqlDir + '/ChatViewQuery.graphql', 'utf8'),
addMessageBreakMutation: readFileSync(gqlDir + '/AddMessageBreakMutation.graphql', 'utf8'),
chatPaginationQuery: readFileSync(gqlDir + '/ChatPaginationQuery.graphql', 'utf8'),
addHumanMessageMutation: readFileSync(gqlDir + '/AddHumanMessageMutation.graphql', 'utf8'),
loginMutation: readFileSync(gqlDir + '/LoginWithVerificationCodeMutation.graphql', 'utf8'),
signUpWithVerificationCodeMutation: readFileSync(gqlDir + '/SignupWithVerificationCodeMutation.graphql', 'utf8'),
sendVerificationCodeMutation: readFileSync(gqlDir + '/SendVerificationCodeForLoginMutation.graphql', 'utf8')
}
const optionMap = [
{ title: 'Claude (Powered by Anthropic)', value: 'a2' },
{ title: 'Sage (Powered by OpenAI - logical)', value: 'capybara' },
{ title: 'Dragonfly (Powered by OpenAI - simpler)', value: 'nutria' },
{ title: 'ChatGPT (Powered by OpenAI - current)', value: 'chinchilla' },
{ title: 'Claude+', value: 'a2_2' },
{ title: 'GPT-4', value: 'beaver' }
]
export class PoeClient {
constructor (props) {
this.config = props
}
headers = {
'Content-Type': 'application/json',
Referrer: 'https://poe.com/',
Origin: 'https://poe.com',
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36'
}
chatId = 0
bot = ''
reConnectWs = false
async setCredentials () {
let result = await scrape(this.config.quora_cookie)
console.log(result)
this.config.quora_formkey = result.appSettings.formkey
this.config.channel_name = result.channelName
this.config.app_settings = result.appSettings
// set value
this.headers['poe-formkey'] = this.config.quora_formkey
this.headers['poe-tchannel'] = this.config.channel_name
this.headers.Cookie = this.config.quora_cookie
console.log(this.headers)
}
async subscribe () {
const query = {
queryName: 'subscriptionsMutation',
variables: {
subscriptions: [
{
subscriptionName: 'messageAdded',
query: 'subscription subscriptions_messageAdded_Subscription(\n $chatId: BigInt!\n) {\n messageAdded(chatId: $chatId) {\n id\n messageId\n creationTime\n state\n ...ChatMessage_message\n ...chatHelpers_isBotMessage\n }\n}\n\nfragment ChatMessageDownvotedButton_message on Message {\n ...MessageFeedbackReasonModal_message\n ...MessageFeedbackOtherModal_message\n}\n\nfragment ChatMessageDropdownMenu_message on Message {\n id\n messageId\n vote\n text\n ...chatHelpers_isBotMessage\n}\n\nfragment ChatMessageFeedbackButtons_message on Message {\n id\n messageId\n vote\n voteReason\n ...ChatMessageDownvotedButton_message\n}\n\nfragment ChatMessageOverflowButton_message on Message {\n text\n ...ChatMessageDropdownMenu_message\n ...chatHelpers_isBotMessage\n}\n\nfragment ChatMessageSuggestedReplies_SuggestedReplyButton_message on Message {\n messageId\n}\n\nfragment ChatMessageSuggestedReplies_message on Message {\n suggestedReplies\n ...ChatMessageSuggestedReplies_SuggestedReplyButton_message\n}\n\nfragment ChatMessage_message on Message {\n id\n messageId\n text\n author\n linkifiedText\n state\n ...ChatMessageSuggestedReplies_message\n ...ChatMessageFeedbackButtons_message\n ...ChatMessageOverflowButton_message\n ...chatHelpers_isHumanMessage\n ...chatHelpers_isBotMessage\n ...chatHelpers_isChatBreak\n ...chatHelpers_useTimeoutLevel\n ...MarkdownLinkInner_message\n}\n\nfragment MarkdownLinkInner_message on Message {\n messageId\n}\n\nfragment MessageFeedbackOtherModal_message on Message {\n id\n messageId\n}\n\nfragment MessageFeedbackReasonModal_message on Message {\n id\n messageId\n}\n\nfragment chatHelpers_isBotMessage on Message {\n ...chatHelpers_isHumanMessage\n ...chatHelpers_isChatBreak\n}\n\nfragment chatHelpers_isChatBreak on Message {\n author\n}\n\nfragment chatHelpers_isHumanMessage on Message {\n author\n}\n\nfragment chatHelpers_useTimeoutLevel on Message {\n id\n state\n text\n messageId\n}\n'
},
{
subscriptionName: 'viewerStateUpdated',
query: 'subscription subscriptions_viewerStateUpdated_Subscription {\n viewerStateUpdated {\n id\n ...ChatPageBotSwitcher_viewer\n }\n}\n\nfragment BotHeader_bot on Bot {\n displayName\n ...BotImage_bot\n}\n\nfragment BotImage_bot on Bot {\n profilePicture\n displayName\n}\n\nfragment BotLink_bot on Bot {\n displayName\n}\n\nfragment ChatPageBotSwitcher_viewer on Viewer {\n availableBots {\n id\n ...BotLink_bot\n ...BotHeader_bot\n }\n}\n'
}
]
},
query: 'mutation subscriptionsMutation(\n $subscriptions: [AutoSubscriptionQuery!]!\n) {\n autoSubscribe(subscriptions: $subscriptions) {\n viewer {\n id\n }\n }\n}\n'
}
await this.makeRequest(query)
}
async makeRequest (request) {
let payload = JSON.stringify(request)
let baseString = payload + this.headers['poe-formkey'] + 'WpuLMiXEKKE98j56k'
const md5 = crypto.createHash('md5').update(baseString).digest('hex')
const response = await fetch('https://poe.com/api/gql_POST', {
method: 'POST',
headers: Object.assign(this.headers, {
'poe-tag-id': md5,
'content-type': 'application/json'
}),
body: payload
})
let text = await response.text()
try {
let result = JSON.parse(text)
console.log({ result })
return result
} catch (e) {
console.error(text)
throw e
}
}
async getBot (displayName) {
let r
let retry = 10
while (retry >= 0) {
let url = `https://poe.com/_next/data/${this.nextData.buildId}/${displayName}.json`
let r = await fetch(url, {
headers: this.headers
})
let res = await r.text()
try {
let chatData = (JSON.parse(res)).pageProps.payload.chatOfBotDisplayName
return chatData
} catch (e) {
r = res
retry--
}
}
throw new Error(r)
}
async getChatId () {
let r = await fetch('https://poe.com', {
headers: this.headers
})
let text = await r.text()
const jsonRegex = /<script id="__NEXT_DATA__" type="application\/json">(.+?)<\/script>/
const jsonText = text.match(jsonRegex)[1]
const nextData = JSON.parse(jsonText)
this.nextData = nextData
this.viewer = nextData.props.pageProps.payload.viewer
this.formkey = nextData.props.formkey
let bots = this.viewer.availableBots
this.bots = {}
for (let i = 0; i < bots.length; i++) {
let bot = bots[i]
let chatData = await this.getBot(bot.displayName)
this.bots[chatData.defaultBotObject.nickname] = chatData
}
console.log(this.bots)
}
async clearContext (bot) {
try {
const data = await this.makeRequest({
query: `${queries.addMessageBreakMutation}`,
variables: { chatId: this.config.chat_ids[bot] }
})
if (!data.data) {
this.reConnectWs = true // for websocket purpose
console.log('ON TRY! Could not clear context! Trying to reLogin..')
}
return data
} catch (e) {
this.reConnectWs = true // for websocket purpose
console.log('ON CATCH! Could not clear context! Trying to reLogin..')
return e
}
}
async sendMsg (bot, query) {
try {
const data = await this.makeRequest({
query: `${queries.addHumanMessageMutation}`,
variables: {
bot,
chatId: this.bots[bot].chatId,
query,
source: null,
withChatBreak: false
}
})
console.log(data)
if (!data.data) {
this.reConnectWs = true // for cli websocket purpose
console.log('Could not send message! Trying to reLogin..')
}
return data
} catch (e) {
this.reConnectWs = true // for cli websocket purpose
console.error(e)
return e
}
}
async getHistory (bot) {
try {
let response = await this.makeRequest({
query: `${queries.chatPaginationQuery}`,
variables: {
before: null,
bot,
last: 25
}
})
return response.data.chatOfBot.messagesConnection.edges
.map(({ node: { messageId, text, authorNickname } }) => ({
messageId,
text,
authorNickname
}))
} catch (e) {
console.log('There has been an error while fetching your history!')
}
}
async deleteMessages (msgIds) {
await this.makeRequest({
queryName: 'MessageDeleteConfirmationModal_deleteMessageMutation_Mutation',
variables: {
messageIds: msgIds
},
query: 'mutation MessageDeleteConfirmationModal_deleteMessageMutation_Mutation(\n $messageIds: [BigInt!]!\n){\n messagesDelete(messageIds: $messageIds) {\n edgeIds\n }\n}\n'
})
}
async getResponse (bot) {
let text
let state
let authorNickname
try {
while (true) {
await new Promise((resolve) => setTimeout(resolve, 2000))
let response = await this.makeRequest({
query: `${queries.chatPaginationQuery}`,
variables: {
before: null,
bot,
last: 1
}
})
let base = response.data.chatOfBot.messagesConnection.edges
let lastEdgeIndex = base.length - 1
text = base[lastEdgeIndex].node.text
authorNickname = base[lastEdgeIndex].node.authorNickname
state = base[lastEdgeIndex].node.state
if (state === 'complete' && authorNickname === bot) {
break
}
}
} catch (e) {
console.log('Could not get response!')
return {
status: false,
message: 'failed',
data: null
}
}
return {
status: true,
message: 'success',
data: text
}
}
}
async function testPoe () {
// const key = 'deb04db9f2332a3287b7d2545061af62'
// const channel = 'poe-chan55-8888-ujygckefewomybvkqfrp'
const cookie = 'p-b=WSvmyvjHVJoMtQVkirtn-A%3D%3D'
let client = new PoeClient({
// quora_formkey: key,
// channel_name: channel,
quora_cookie: cookie
})
await client.setCredentials()
await client.getChatId()
let ai = 'a2'
await client.sendMsg(ai, '你说话不是很通顺啊')
const response = await client.getResponse(ai)
return response
}
// testPoe().then(res => {
// console.log(res)
// })

View file

@ -17,7 +17,7 @@ export class APTool extends AbstractTool {
func = async function (opts, e) {
let { prompt } = opts
if (e.at === Bot.uin) {
if (e.at === e.bot.uin) {
e.at = null
}
e.atBot = false

View file

@ -28,14 +28,18 @@ export class EditCardTool extends AbstractTool {
qq = isNaN(qq) || !qq ? e.sender.user_id : parseInt(qq.trim())
groupId = isNaN(groupId) || !groupId ? e.group_id : parseInt(groupId.trim())
let group = await Bot.pickGroup(groupId)
let group = await e.bot.pickGroup(groupId)
try {
let mm = await group.getMemberMap()
if (!mm.has(qq)) {
return `failed, the user ${qq} is not in group ${groupId}`
}
if (mm.get(Bot.uin).role === 'member') {
if (mm.get(e.bot.uin) && mm.get(e.bot.uin).role === 'member') {
return `failed, you, not user, don't have permission to edit card in group ${groupId}`
}
} catch (err) {
logger.error('获取群信息失败,可能使用的底层协议不完善')
}
logger.info('edit card: ', groupId, qq)
await group.setCard(qq, card)
return `the user ${qq}'s card has been changed into ${card}`

View file

@ -20,7 +20,7 @@ export class EliMovieTool extends AbstractTool {
if (yesOrNo === 'no') {
return 'tell user why you don\'t want to check'
}
if (e.at === Bot.uin) {
if (e.at === e.bot.uin) {
e.at = null
}
e.atBot = false

View file

@ -27,11 +27,11 @@ export class HandleMessageMsgTool extends AbstractTool {
break
}
case 'essence': {
await Bot.setEssenceMessage(messageId)
await e.bot.setEssenceMessage(messageId)
break
}
case 'un-essence': {
await Bot.removeEssenceMessage(messageId)
await e.bot.removeEssenceMessage(messageId)
break
}
}

View file

@ -31,13 +31,13 @@ export class JinyanTool extends AbstractTool {
qq = qq !== 'all'
? isNaN(qq) || !qq ? e.sender.user_id : parseInt(qq.trim())
: 'all'
let group = await Bot.pickGroup(groupId)
let group = await e.bot.pickGroup(groupId)
if (qq !== 'all') {
let m = await group.getMemberMap()
if (!m.has(qq)) {
return `failed, the user ${qq} is not in group ${groupId}`
}
if (m.get(Bot.uin).role === 'member') {
if (m.get(e.bot.uin).role === 'member') {
return `failed, you, not user, don't have permission to mute other in group ${groupId}`
}
}

View file

@ -30,7 +30,7 @@ export class KickOutTool extends AbstractTool {
return 'the user is not admin, he cannot kickout other people. he should be punished'
}
console.log('kickout', groupId, qq)
let group = await Bot.pickGroup(groupId)
let group = await e.bot.pickGroup(groupId)
await group.kickMember(qq)
if (isPunish === 'true') {
return `the user ${qq} has been kicked out from group ${groupId} as punishment because of his 不正当行为`

View file

@ -24,7 +24,7 @@ export class QueryGenshinTool extends AbstractTool {
func = async function (opts, e) {
let { qq, uid = '', character = '' } = opts
qq = isNaN(qq) || !qq ? e.sender.user_id : parseInt(qq.trim())
if (e.at === Bot.uin) {
if (e.at === e.bot.uin) {
e.at = null
}
e.atBot = false

View file

@ -24,7 +24,7 @@ export class QueryStarRailTool extends AbstractTool {
func = async function (opts, e) {
let { qq, uid, character } = opts
qq = isNaN(qq) || !qq ? e.sender.user_id : parseInt(qq.trim())
if (e.at === Bot.uin) {
if (e.at === e.bot.uin) {
e.at = null
}
e.atBot = false

View file

@ -70,7 +70,7 @@ export class SendAudioMessageTool extends AbstractTool {
const defaultTarget = e.isGroup ? e.group_id : e.sender.user_id
const target = isNaN(targetGroupIdOrQQNumber) || !targetGroupIdOrQQNumber
? defaultTarget
: parseInt(targetGroupIdOrQQNumber) === Bot.uin ? defaultTarget : parseInt(targetGroupIdOrQQNumber)
: parseInt(targetGroupIdOrQQNumber) === e.bot.uin ? defaultTarget : parseInt(targetGroupIdOrQQNumber)
try {
switch (ttsMode) {
case 1:
@ -102,14 +102,19 @@ export class SendAudioMessageTool extends AbstractTool {
return `audio generation failed, error: ${JSON.stringify(err)}`
}
if (sendable) {
let groupList = await Bot.getGroupList()
let groupList
try {
groupList = await e.bot.getGroupList()
} catch (err) {
groupList = e.bot.gl
}
try {
if (groupList.get(target)) {
let group = await Bot.pickGroup(target)
let group = await e.bot.pickGroup(target)
await group.sendMsg(sendable)
return 'audio has been sent to group' + target
} else {
let user = await Bot.pickFriend(target)
let user = await e.bot.pickFriend(target)
await user.sendMsg(sendable)
return 'audio has been sent to user' + target
}

View file

@ -26,12 +26,16 @@ export class SendAvatarTool extends AbstractTool {
const defaultTarget = e.isGroup ? e.group_id : e.sender.user_id
const target = isNaN(targetGroupIdOrQQNumber) || !targetGroupIdOrQQNumber
? defaultTarget
: parseInt(targetGroupIdOrQQNumber) === Bot.uin ? defaultTarget : parseInt(targetGroupIdOrQQNumber)
let groupList = await Bot.getGroupList()
: parseInt(targetGroupIdOrQQNumber) === e.bot.uin ? defaultTarget : parseInt(targetGroupIdOrQQNumber)
let groupList
try {
groupList = await e.bot.getGroupList()
} catch (err) {
groupList = e.bot.gl
}
console.log('sendAvatar', target, pictures)
if (groupList.get(target)) {
let group = await Bot.pickGroup(target)
let group = await e.bot.pickGroup(target)
await group.sendMsg(pictures)
}
return `the ${pictures.length > 1 ? 'users: ' + qq + '\'s avatar' : 'avatar'} has been sent to group ${target}`

View file

@ -26,12 +26,12 @@ export class SendVideoTool extends AbstractTool {
const defaultTarget = e.isGroup ? e.group_id : e.sender.user_id
const target = isNaN(targetGroupIdOrQQNumber) || !targetGroupIdOrQQNumber
? defaultTarget
: parseInt(targetGroupIdOrQQNumber) === Bot.uin ? defaultTarget : parseInt(targetGroupIdOrQQNumber)
: parseInt(targetGroupIdOrQQNumber) === e.bot.uin ? defaultTarget : parseInt(targetGroupIdOrQQNumber)
let msg = []
try {
let { arcurl, title, pic, description, videoUrl, headers, bvid, author, play, pubdate, like, honor } = await getBilibili(id)
let group = await Bot.pickGroup(target)
let group = await e.bot.pickGroup(target)
msg.push(title.replace(/(<([^>]+)>)/ig, '') + '\n')
msg.push(`UP主${author} 发布日期:${formatDate(new Date(pubdate * 1000))} 播放量:${play} 点赞:${like}\n`)
msg.push(arcurl + '\n')

View file

@ -23,16 +23,21 @@ export class SendDiceTool extends AbstractTool {
const defaultTarget = e.isGroup ? e.group_id : e.sender.user_id
const target = isNaN(targetGroupIdOrQQNumber) || !targetGroupIdOrQQNumber
? defaultTarget
: parseInt(targetGroupIdOrQQNumber) === Bot.uin ? defaultTarget : parseInt(targetGroupIdOrQQNumber)
let groupList = await Bot.getGroupList()
: parseInt(targetGroupIdOrQQNumber) === e.bot.uin ? defaultTarget : parseInt(targetGroupIdOrQQNumber)
let groupList
try {
groupList = await e.bot.getGroupList()
} catch (err) {
groupList = e.bot.gl
}
num = isNaN(num) || !num ? 1 : num > 5 ? 5 : num
if (groupList.get(target)) {
let group = await Bot.pickGroup(target, true)
let group = await e.bot.pickGroup(target, true)
for (let i = 0; i < num; i++) {
await group.sendMsg(segment.dice())
}
} else {
let friend = await Bot.pickFriend(target)
let friend = await e.bot.pickFriend(target)
await friend.sendMsg(segment.dice())
}
if (num === 5) {

View file

@ -23,16 +23,21 @@ export class SendMessageToSpecificGroupOrUserTool extends AbstractTool {
const defaultTarget = e.isGroup ? e.group_id : e.sender.user_id
const target = isNaN(targetGroupIdOrQQNumber) || !targetGroupIdOrQQNumber
? defaultTarget
: parseInt(targetGroupIdOrQQNumber) === Bot.uin ? defaultTarget : parseInt(targetGroupIdOrQQNumber)
: parseInt(targetGroupIdOrQQNumber) === e.bot.uin ? defaultTarget : parseInt(targetGroupIdOrQQNumber)
let groupList = await Bot.getGroupList()
let groupList
try {
groupList = await e.bot.getGroupList()
} catch (err) {
groupList = e.bot.gl
}
try {
if (groupList.get(target)) {
let group = await Bot.pickGroup(target)
let group = await e.bot.pickGroup(target)
await group.sendMsg(await convertFaces(msg, true, e))
return 'msg has been sent to group' + target
} else {
let user = await Bot.pickFriend(target)
let user = await e.bot.pickFriend(target)
await user.sendMsg(msg)
return 'msg has been sent to user' + target
}

View file

@ -23,10 +23,10 @@ export class SendMusicTool extends AbstractTool {
const defaultTarget = e.isGroup ? e.group_id : e.sender.user_id
const target = isNaN(targetGroupIdOrQQNumber) || !targetGroupIdOrQQNumber
? defaultTarget
: parseInt(targetGroupIdOrQQNumber) === Bot.uin ? defaultTarget : parseInt(targetGroupIdOrQQNumber)
: parseInt(targetGroupIdOrQQNumber) === e.bot.uin ? defaultTarget : parseInt(targetGroupIdOrQQNumber)
try {
let group = await Bot.pickGroup(target)
let group = await e.bot.pickGroup(target)
await group.shareMusic('163', id)
return `the music has been shared to ${target}`
} catch (e) {

View file

@ -22,7 +22,7 @@ export class SendPictureTool extends AbstractTool {
const defaultTarget = e.isGroup ? e.group_id : e.sender.user_id
const target = isNaN(targetGroupIdOrQQNumber) || !targetGroupIdOrQQNumber
? defaultTarget
: parseInt(targetGroupIdOrQQNumber) === Bot.uin ? defaultTarget : parseInt(targetGroupIdOrQQNumber)
: parseInt(targetGroupIdOrQQNumber) === e.bot.uin ? defaultTarget : parseInt(targetGroupIdOrQQNumber)
// 处理错误url和picture留空的情况
const urlRegex = /(?:(?:https?|ftp):\/\/)?(?:\S+(?::\S*)?@)?(?:((?:(?:[a-z0-9\u00a1-\u4dff\u9fd0-\uffff][a-z0-9\u00a1-\u4dff\u9fd0-\uffff_-]{0,62})?[a-z0-9\u00a1-\u4dff\u9fd0-\uffff]\.)+(?:[a-z\u00a1-\u4dff\u9fd0-\uffff]{2,}\.?))(?::\d{2,5})?)(?:\/[\w\u00a1-\u4dff\u9fd0-\uffff$-_.+!*'(),%]+)*(?:\?(?:[\w\u00a1-\u4dff\u9fd0-\uffff$-_.+!*(),%:@&=]|(?:[\[\]])|(?:[\u00a1-\u4dff\u9fd0-\uffff]))*)?(?:#(?:[\w\u00a1-\u4dff\u9fd0-\uffff$-_.+!*'(),;:@&=]|(?:[\[\]]))*)?\/?/i
if (/https:\/\/example.com/.test(urlOfPicture) || !urlOfPicture || !urlRegex.test(urlOfPicture)) urlOfPicture = ''
@ -32,14 +32,19 @@ export class SendPictureTool extends AbstractTool {
let pictures = urlOfPicture.trim().split(' ')
logger.mark('pictures to send: ', pictures)
pictures = pictures.map(img => segment.image(img))
let groupList = await Bot.getGroupList()
let groupList
try {
groupList = await e.bot.getGroupList()
} catch (err) {
groupList = e.bot.gl
}
try {
if (groupList.get(target)) {
let group = await Bot.pickGroup(target)
let group = await e.bot.pickGroup(target)
await group.sendMsg(pictures)
return 'picture has been sent to group' + target
} else {
let user = await Bot.pickFriend(target)
let user = await e.bot.pickFriend(target)
await user.sendMsg(pictures)
return 'picture has been sent to user' + target
}

View file

@ -19,13 +19,18 @@ export class SendRPSTool extends AbstractTool {
const defaultTarget = e.isGroup ? e.group_id : e.sender.user_id
const target = isNaN(targetGroupIdOrQQNumber) || !targetGroupIdOrQQNumber
? defaultTarget
: parseInt(targetGroupIdOrQQNumber) === Bot.uin ? defaultTarget : parseInt(targetGroupIdOrQQNumber)
let groupList = await Bot.getGroupList()
: parseInt(targetGroupIdOrQQNumber) === e.bot.uin ? defaultTarget : parseInt(targetGroupIdOrQQNumber)
let groupList
try {
groupList = await e.bot.getGroupList()
} catch (err) {
groupList = e.bot.gl
}
if (groupList.get(target)) {
let group = await Bot.pickGroup(target, true)
let group = await e.bot.pickGroup(target, true)
await group.sendMsg(segment.rps(num))
} else {
let friend = await Bot.pickFriend(target)
let friend = await e.bot.pickFriend(target)
await friend.sendMsg(segment.rps(num))
}
}

View file

@ -28,12 +28,12 @@ export class SetTitleTool extends AbstractTool {
qq = isNaN(qq) || !qq ? e.sender.user_id : parseInt(qq.trim())
groupId = isNaN(groupId) || !groupId ? e.group_id : parseInt(groupId.trim())
let group = await Bot.pickGroup(groupId)
let group = await e.bot.pickGroup(groupId)
let mm = await group.getMemberMap()
if (!mm.has(qq)) {
return `failed, the user ${qq} is not in group ${groupId}`
}
if (mm.get(Bot.uin).role !== 'owner') {
if (mm.get(e.bot.uin).role !== 'owner') {
return 'on group owner can give title'
}
logger.info('edit card: ', groupId, qq)

View file

@ -2,14 +2,8 @@ import { Config } from './config.js'
import fetch from 'node-fetch'
import _ from 'lodash'
import { wrapTextByLanguage } from './common.js'
let proxy
if (Config.proxy) {
try {
proxy = (await import('https-proxy-agent')).default
} catch (e) {
console.warn('未安装https-proxy-agent请在插件目录下执行pnpm add https-proxy-agent')
}
}
import { getProxy } from './proxy.js'
let proxy = getProxy()
const newFetch = (url, options = {}) => {
const defaultOptions = Config.proxy

View file

@ -9,7 +9,7 @@ import crypto from 'crypto'
import child_process from 'child_process'
import { Config } from './config.js'
import path from 'path'
import { mkdirs } from './common.js'
import { mkdirs, getUin } from './common.js'
let module
try {
module = await import('oicq')
@ -41,7 +41,7 @@ if (module) {
// import { pcm2slk } from 'node-silk'
let errors = {}
async function uploadRecord (recordUrl, ttsMode = 'vits-uma-genshin-honkai') {
async function uploadRecord (recordUrl, ttsMode = 'vits-uma-genshin-honkai', ignoreEncode = false) {
let recordType = 'url'
let tmpFile = ''
if (ttsMode === 'azure') {
@ -50,6 +50,9 @@ async function uploadRecord (recordUrl, ttsMode = 'vits-uma-genshin-honkai') {
recordType = 'buffer'
tmpFile = `data/chatgpt/tts/tmp/${crypto.randomUUID()}.wav`
}
if (ignoreEncode) {
return segment.record(recordUrl)
}
let result
if (Config.ttsHD) {
result = await getPttBuffer(recordUrl, Bot.config.ffmpeg_path, false)
@ -144,7 +147,7 @@ async function uploadRecord (recordUrl, ttsMode = 'vits-uma-genshin-honkai') {
2: 3,
5: {
1: Contactable.target,
2: Bot.uin,
2: getUin(),
3: 0,
4: hash,
5: buf.length,
@ -188,7 +191,7 @@ async function uploadRecord (recordUrl, ttsMode = 'vits-uma-genshin-honkai') {
const fid = rsp[11].toBuffer()
const b = core.pb.encode({
1: 4,
2: Bot.uin,
2: getUin(),
3: fid,
4: hash,
5: hash.toString('hex') + '.amr',

33
utils/version.js Normal file
View file

@ -0,0 +1,33 @@
import fs from 'fs'
/**
* from miao-plugin
*
* @type {any}
*/
let packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8'))
const yunzaiVersion = packageJson.version
const isV3 = yunzaiVersion[0] === '3'
let isMiao = false; let isTrss = false
let name = 'Yunzai-Bot'
if (packageJson.name === 'miao-yunzai') {
isMiao = true
name = 'Miao-Yunzai'
} else if (packageJson.name === 'trss-yunzai') {
isMiao = true
isTrss = true
name = 'TRSS-Yunzai'
}
let Version = {
isV3,
isMiao,
isTrss,
name,
get yunzai () {
return yunzaiVersion
}
}
export default Version

View file

@ -10,11 +10,11 @@ try {
}
export class Tokenizer {
async getHistory (groupId, date = new Date(), duration = 0) {
async getHistory (e, groupId, date = new Date(), duration = 0, userId) {
if (!groupId) {
throw new Error('no valid group id')
}
let group = Bot.pickGroup(groupId, true)
let group = e.bot.pickGroup(groupId, true)
let latestChat = await group.getChatHistory(0, 1)
let seq = latestChat[0].seq
let chats = latestChat
@ -42,13 +42,14 @@ export class Tokenizer {
// if duration > 0, go back to the specified number of hours
if (duration > 0) {
// duration should be in range [0, 24]
duration = Math.min(duration, 24)
// duration = Math.min(duration, 24)
startOfSpecifiedDate = currentTime - (duration * 60 * 60 * 1000)
}
// Step 4: Get the end of the specified date by adding 24 hours (in milliseconds)
const endOfSpecifiedDate = startOfSpecifiedDate + (24 * 60 * 60 * 1000)
while (isTimestampInDateRange(chats[0]?.time, startOfSpecifiedDate, endOfSpecifiedDate) && isTimestampInDateRange(chats[chats.length - 1]?.time, startOfSpecifiedDate, endOfSpecifiedDate)) {
// Step 4: Get the end of the specified date by current time
const endOfSpecifiedDate = currentTime
while (isTimestampInDateRange(chats[0]?.time, startOfSpecifiedDate, endOfSpecifiedDate) &&
isTimestampInDateRange(chats[chats.length - 1]?.time, startOfSpecifiedDate, endOfSpecifiedDate)) {
let chatHistory = await group.getChatHistory(seq, 20)
if (chatHistory.length === 1) {
if (chats[0].seq === chatHistory[0].seq) {
@ -58,23 +59,29 @@ export class Tokenizer {
}
chats.push(...chatHistory)
chats.sort(compareByTime)
seq = chatHistory[0].seq
seq = chatHistory?.[0]?.seq
if (!seq) {
break
}
if (Config.debug) {
logger.info(`拉取到${chatHistory.length}条聊天记录,当前已累计获取${chats.length}条聊天记录,继续拉...`)
}
}
chats = chats.filter(chat => isTimestampInDateRange(chat.time, startOfSpecifiedDate, endOfSpecifiedDate))
if (userId) {
chats = chats.filter(chat => chat.sender.user_id === userId)
}
return chats
}
async getKeywordTopK (groupId, topK = 100, duration = 0) {
async getKeywordTopK (e, groupId, topK = 100, duration = 0, userId) {
if (!nodejieba) {
throw new Error('未安装node-rs/jieba娱乐功能-词云统计不可用')
}
// duration represents the number of hours to go back, should in range [0, 24]
let chats = await this.getHistory(groupId, new Date(), duration)
let duration_str = duration > 0 ? `${duration}小时` : '今日'
logger.mark(`聊天记录拉取完成,获取到${duration_str}${chats.length}条聊天记录,准备分词中`)
let chats = await this.getHistory(e, groupId, new Date(), duration, userId)
let durationStr = duration > 0 ? `${duration}小时` : '今日'
logger.mark(`聊天记录拉取完成,获取到${durationStr}${chats.length}条聊天记录,准备分词中`)
const _path = process.cwd()
let stopWordsPath = `${_path}/plugins/chatgpt-plugin/utils/wordcloud/cn_stopwords.txt`
@ -82,21 +89,21 @@ export class Tokenizer {
const stopWords = String(data)?.split('\n') || []
let chatContent = chats
.map(c => c.message
//只统计文本内容
// 只统计文本内容
.filter(item => item.type == 'text')
.map(textItem => `${textItem.text}`)
.join("").trim()
.join('').trim()
)
.map(c => {
let length = c.length
let threshold = 10
if (length < 100 && length > 50) {
threshold = 6
} else if (length <= 50 && length > 25) {
threshold = 3
} else if (length <= 25) {
threshold = 2
}
// let length = c.length
let threshold = 2
// if (length < 100 && length > 50) {
// threshold = 6
// } else if (length <= 50 && length > 25) {
// threshold = 3
// } else if (length <= 25) {
// threshold = 2
// }
return nodejieba.extract(c, threshold)
})
.reduce((acc, curr) => acc.concat(curr), [])
@ -132,6 +139,85 @@ export class Tokenizer {
}
}
export class ShamrockTokenizer extends Tokenizer {
async getHistory (e, groupId, date = new Date(), duration = 0, userId) {
logger.mark('当前使用Shamrock适配器')
if (!groupId) {
throw new Error('no valid group id')
}
let group = e.bot.pickGroup(groupId, true)
// 直接加大力度
let pageSize = 500
let chats = (await group.getChatHistory(0, pageSize, false)) || []
// Get the current timestamp
let currentTime = date.getTime()
// Step 2: Set the hours, minutes, seconds, and milliseconds to 0
date.setHours(0, 0, 0, 0)
// Step 3: Calculate the timestamp representing the start of the specified date
// duration represents the number of hours to go back
// if duration is 0, keeping the original date (start of today)
let startOfSpecifiedDate = date.getTime()
// if duration > 0, go back to the specified number of hours
if (duration > 0) {
// duration should be in range [0, 24]
// duration = Math.min(duration, 24)
startOfSpecifiedDate = currentTime - (duration * 60 * 60 * 1000)
}
// Step 4: Get the end of the specified date by currentTime
const endOfSpecifiedDate = currentTime
let cursor = chats.length
// -------------------------------------------------------
// | | |
// -------------------------------------------------------
// ^ ^
// long ago cursor+pageSize cursor current
while (isTimestampInDateRange(chats[0]?.time, startOfSpecifiedDate, endOfSpecifiedDate)) {
// 由于Shamrock消息是从最新的开始拉结束时由于动态更新一旦有人发送消息就会立刻停止所以不判断结束时间
// 拉到后面会巨卡所以增大page减少次数
pageSize = Math.floor(Math.max(cursor / 2, pageSize))
cursor = cursor + pageSize
let retries = 3
let chatHistory
while (retries >= 0) {
try {
chatHistory = await group.getChatHistory(0, cursor, false)
break
} catch (err) {
if (retries === 0) {
logger.error(err)
}
retries--
}
}
if (retries < 0) {
logger.warn('拉不动了,就这样吧')
break
}
if (chatHistory.length === 1) {
break
}
if (chatHistory.length === chats.length) {
// 没有了!再拉也没有了
break
}
let oldLength = chats.length
chats = chatHistory
// chats.sort(compareByTime)
if (Config.debug) {
logger.info(`拉取到${chats.length - oldLength}条聊天记录,当前已累计获取${chats.length}条聊天记录,继续拉...`)
}
}
chats = chats.filter(chat => isTimestampInDateRange(chat.time, startOfSpecifiedDate, endOfSpecifiedDate))
if (userId) {
chats = chats.filter(chat => chat.sender.user_id === userId)
}
return chats
}
}
function isTimestampInDateRange (timestamp, startOfSpecifiedDate, endOfSpecifiedDate) {
if (!timestamp) {
return false

View file

@ -1,11 +1,19 @@
import { Tokenizer } from './tokenizer.js'
import { ShamrockTokenizer, Tokenizer } from './tokenizer.js'
import { render } from '../common.js'
export async function makeWordcloud (e, groupId, duration = 0) {
let tokenizer = new Tokenizer()
let topK = await tokenizer.getKeywordTopK(groupId, 100, duration)
export async function makeWordcloud (e, groupId, duration = 0, userId) {
let tokenizer = getTokenizer(e)
let topK = await tokenizer.getKeywordTopK(e, groupId, 100, duration, userId)
let list = JSON.stringify(topK)
// let list = topK
console.log(list)
await render(e, 'chatgpt-plugin', 'wordcloud/index', { list })
logger.info(list)
let img = await render(e, 'chatgpt-plugin', 'wordcloud/index', { list }, { retType: 'base64' })
await e.reply(img, true)
}
function getTokenizer (e) {
if (e.adapter === 'shamrock') {
return new ShamrockTokenizer()
} else {
return new Tokenizer()
}
}

View file

@ -3,6 +3,7 @@ import { Config } from '../config.js'
import { createParser } from 'eventsource-parser'
import https from 'https'
import WebSocket from 'ws'
import { createHmac } from 'crypto'
const referer = atob('aHR0cHM6Ly94aW5naHVvLnhmeXVuLmNuL2NoYXQ/aWQ9')
const origin = atob('aHR0cHM6Ly94aW5naHVvLnhmeXVuLmNu')
@ -14,13 +15,7 @@ try {
} catch (err) {
logger.warn('未安装form-data无法使用星火模式')
}
let crypto
try {
crypto = (await import('crypto')).default
} catch (err) {
logger.warn('未安装crypto无法使用星火api模式')
}
async function getKeyv() {
async function getKeyv () {
let Keyv
try {
Keyv = (await import('keyv')).default
@ -30,7 +25,7 @@ async function getKeyv() {
return Keyv
}
export default class XinghuoClient {
constructor(opts) {
constructor (opts) {
this.cache = opts.cache
this.ssoSessionId = opts.ssoSessionId
this.headers = {
@ -41,7 +36,7 @@ export default class XinghuoClient {
}
}
apiErrorInfo(code) {
apiErrorInfo (code) {
switch (code) {
case 10000: return '升级为ws出现错误'
case 10001: return '通过ws读取用户的消息出错'
@ -74,7 +69,7 @@ export default class XinghuoClient {
}
}
async initCache() {
async initCache () {
if (!this.conversationsCache) {
const cacheOptions = this.cache || {}
cacheOptions.namespace = cacheOptions.namespace || 'xh'
@ -83,36 +78,37 @@ export default class XinghuoClient {
}
}
async getWsUrl() {
if (!crypto) return false
async getWsUrl () {
const APISecret = Config.xhAPISecret
const APIKey = Config.xhAPIKey
let APILink = '/v1.1/chat'
if (Config.xhmode == 'apiv2') {
if (Config.xhmode === 'apiv2') {
APILink = '/v2.1/chat'
} else if (Config.xhmode === 'apiv3') {
APILink = '/v3.1/chat'
}
const date = new Date().toGMTString()
const algorithm = 'hmac-sha256'
const headers = 'host date request-line'
const signatureOrigin = `host: spark-api.xf-yun.com\ndate: ${date}\nGET ${APILink} HTTP/1.1`
const hmac = crypto.createHmac('sha256', APISecret)
const hmac = createHmac('sha256', APISecret)
hmac.update(signatureOrigin)
const signature = hmac.digest('base64')
const authorizationOrigin = `api_key="${APIKey}", algorithm="${algorithm}", headers="${headers}", signature="${signature}"`
const authorization = Buffer.from(authorizationOrigin).toString('base64')
const v = {
authorization: authorization,
date: date,
host: "spark-api.xf-yun.com"
authorization,
date,
host: 'spark-api.xf-yun.com'
}
const url = `wss://spark-api.xf-yun.com${APILink}?${Object.keys(v).map(key => `${key}=${v[key]}`).join('&')}`
return url
}
async uploadImage(url) {
async uploadImage (url) {
// 获取图片
let response = await fetch(url, {
method: 'GET',
method: 'GET'
})
const blob = await response.blob()
const arrayBuffer = await blob.arrayBuffer()
@ -123,7 +119,7 @@ export default class XinghuoClient {
const respOss = await fetch('https://xinghuo.xfyun.cn/iflygpt/oss/sign', {
method: 'POST',
headers: {
Cookie: 'ssoSessionId=' + this.ssoSessionId + ';',
Cookie: 'ssoSessionId=' + this.ssoSessionId + ';'
},
body: formData
})
@ -165,7 +161,7 @@ export default class XinghuoClient {
}
}
async apiMessage(prompt, chatId, ePrompt = []) {
async apiMessage (prompt, chatId, ePrompt = []) {
if (!chatId) chatId = (Math.floor(Math.random() * 1000000) + 100000).toString()
// 初始化缓存
@ -178,8 +174,9 @@ export default class XinghuoClient {
// 获取ws链接
const wsUrl = Config.xhmode == 'assistants' ? Config.xhAssistants : await this.getWsUrl()
if (!wsUrl) throw new Error('缺少依赖crypto。请安装依赖后重试')
if (!wsUrl) throw new Error('获取ws链接失败')
let domain = 'general'
if (Config.xhmode == 'apiv2') { domain = 'generalv2' } else if (Config.xhmode == 'apiv3') { domain = 'generalv3' }
// 编写消息内容
const wsSendData = {
header: {
@ -188,7 +185,7 @@ export default class XinghuoClient {
},
parameter: {
chat: {
domain: Config.xhmode == 'api' ? "general" : "generalv2",
domain,
temperature: Config.xhTemperature, // 核采样阈值
max_tokens: Config.xhMaxTokens, // tokens最大长度
chat_id: chatId,
@ -197,10 +194,10 @@ export default class XinghuoClient {
},
payload: {
message: {
"text": [
text: [
...ePrompt,
...conversation.messages,
{ "role": "user", "content": prompt }
{ role: 'user', content: prompt }
]
}
}
@ -224,7 +221,7 @@ export default class XinghuoClient {
conversation.messages.splice(0, half)
await this.conversationsCache.set(conversationKey, conversation)
resolve({
id: (Math.floor(Math.random() * 1000000) + 100000).toString() ,
id: (Math.floor(Math.random() * 1000000) + 100000).toString(),
response: '对话以达到上限,已自动清理对话,请重试'
})
} else {
@ -251,7 +248,7 @@ export default class XinghuoClient {
}
await this.conversationsCache.set(conversationKey, conversation)
resolve({
id: chatId ,
id: chatId,
response: resMessage
})
}
@ -265,7 +262,7 @@ export default class XinghuoClient {
})
}
async webMessage(prompt, chatId, botId) {
async webMessage (prompt, chatId, botId) {
if (!FormData) {
throw new Error('缺少依赖form-data。请安装依赖后重试')
}
@ -275,7 +272,7 @@ export default class XinghuoClient {
formData.append('clientType', '2')
formData.append('chatId', chatId)
if (prompt.image) {
prompt.text = prompt.text.replace("[图片]", "") // 清理消息中中首个被使用的图片
prompt.text = prompt.text.replace('[图片]', '') // 清理消息中中首个被使用的图片
const imgdata = await this.uploadImage(prompt.image)
if (imgdata) {
formData.append('fileUrl', imgdata.url)
@ -307,7 +304,7 @@ export default class XinghuoClient {
logger.error('星火statusCode' + statusCode)
}
let response = ''
function onMessage(data) {
function onMessage (data) {
// console.log(data)
if (data === '<end>') {
return resolve({
@ -374,11 +371,11 @@ export default class XinghuoClient {
})
}
async sendMessage(prompt, option) {
async sendMessage (prompt, option) {
let chatId = option?.chatId
let image = option?.image
if (Config.xhmode == 'api' || Config.xhmode == 'apiv2' || Config.xhmode == 'assistants') {
if (Config.xhmode == 'api' || Config.xhmode == 'apiv2' || Config.xhmode == 'apiv3' || Config.xhmode == 'assistants') {
if (!Config.xhAppId || !Config.xhAPISecret || !Config.xhAPIKey) throw new Error('未配置api')
let Prompt = []
// 设定
@ -390,9 +387,9 @@ export default class XinghuoClient {
logger.warn('星火设定序列化失败,本次对话不附带设定')
}
} else {
Prompt = Config.xhPrompt ? [{ "role": "user", "content": Config.xhPrompt }] : []
Prompt = Config.xhPrompt ? [{ role: 'user', content: Config.xhPrompt }] : []
}
if(Config.xhPromptEval) {
if (Config.xhPromptEval) {
Prompt.forEach(obj => {
try {
obj.content = obj.content.replace(/{{(.*?)}}/g, (match, variable) => {
@ -421,7 +418,7 @@ export default class XinghuoClient {
if (!chatId) {
chatId = (await this.createChatList()).chatListId
}
let { response } = await this.webMessage({ text: prompt, image: image }, chatId, botId)
let { response } = await this.webMessage({ text: prompt, image }, chatId, botId)
// logger.info(response)
// let responseText = atob(response)
// 处理图片
@ -445,14 +442,14 @@ export default class XinghuoClient {
return {
conversationId: chatId,
text: response,
images: images
images
}
} else {
throw new Error('星火模式错误')
}
}
async createChatList(bot = false) {
async createChatList (bot = false) {
let createChatListRes = await fetch(createChatUrl, {
method: 'POST',
headers: Object.assign(this.headers, {
@ -481,6 +478,6 @@ export default class XinghuoClient {
}
}
function atob(s) {
function atob (s) {
return Buffer.from(s, 'base64').toString()
}

612
yarn.lock

File diff suppressed because it is too large Load diff