添加Sydney图片识别,适配tools接口 (#516)

* 修复后台API反代地址未能正确显示的问题

* 更新渲染页面配置

* 添加个人聊天模式配置

* 将用户数据获取改到common中

* 修复错误的渲染页面参数

* 修复bug

* 添加Live2D

* 修复渲染页面错误

* 修复渲染传入值

* 更新渲染

* 修复图表渲染bug

* 调整live2d模型大小

* 修复live2d无法关闭问题

* 修复错误的传值

* 修复ai命名

* 更新渲染

* 添加用户独立设定

* 更新渲染配置适配个人设置

* 修复合并导致的渲染文件异常删除

* 修复用户数据缺失问题

* 修复旧版本数据缺失问题

* 修复bing参数不存在问题,兼容miao的截图

* 修复受限token重试时不被排除的问题

* 修复个人模式下结束对话的模式错误

* 更新渲染页面,将预览版转为正式版

* 修复传统渲染无法调用截图功能的问题

* 文字模式也进行一次缓存

* 更新README

* Update README.md

* 更新渲染

* 更新渲染页面

* 添加版本信息

* 遗漏参数

* 丢失引用

* 补充路由

* 添加云转码功能

* 判断node-silk是否正常合成

* 云转码提示

* 修复图片渲染出错

* 云转码支持发送Buffer

* 添加云转码模式支持

* 更新描述

* 更新后台渲染页面

* 更新配置

* 更新渲染页面

* 添加云渲染

* 修复错误的接口调用

* 修复遗漏的数据转换

* 修复获取的图片数据异常问题

* 更新后台配置

* 更新渲染页面

* 修复云渲染访问地址错误

* 更新渲染页面

* 修复遗漏的模型文件

* 修复live2d问题

* 更新live2d以及相关配置

* 修复遗漏的数据参数

* 修复新live2d情况下云渲染错误的问题

* 适配云渲染1.1.2等待参数

* 添加云服务api检查

* 更新渲染页面

* 添加live2d加载检测

* 修复错误的属性判断

* 添加云渲染DPR

* 更新sydney支持内容生成

* 修改文件模式语音转码接收模式

* 添加云转码时recordUrl检查

* 更新后台配置项

* 修复错误的文本描述

* 更新后台页面

* 添加全局对话模式设置,更新后台面板

* 添加第三方渲染服务适配

* 修复第三方服务器live2d加载导致的渲染失败问题

* 修复后台地址无法实时保存的问题

* 添加live2d模型透明度设置

* 合并更新

* 更新渲染页面

* 更新渲染页面

* 使dpr对本地渲染也生效

* 更新渲染页面

* 添加网页截图功能

* 添加后台配置项

* 添加配置导出和导入功能

* 运行通过参数传递用户token

* 登录时将token作为参数返回

* 修复错误

* 添加密码修改和用户删除接口

* 修正密码比对

* 修复user错误

* 优化数据保存时的返回值

* 添加系统额外服务检查api

* 添加AccessToken配置

* 修复错误的导入提示

* 添加ws连接

* 添加ws用户信息获取

* 修复错误的循环

* 修正ws参数

* 添加群消息获取权限

* 添加用户多端登录支持

* 修复错误的路径引用

* 修复错误的路径引用

* 修复错误

* 修复页面数据获取失败问题

* 修复异常的中断

* 添加配置视图

* 更新配置面板

* 添加用户版本信息

* 更新配置视图

* 修复错误的视图绑定

* 修改视图文件位置,添加mediaLink相关代码

* 修复错误的视图配置绑定

* 更新依赖,添加qq消息组件初始化信息获取

* 修复异常的群名称无法获取问题

* 修改注释

* 撤销对management的错误合并

* 添加Sydney图片识别功能

* 更新配置文件和后台页面

* 修改view配置

---------

Co-authored-by: ikechan8370 <geyinchibuaa@gmail.com>
This commit is contained in:
HalcyonAlcedo 2023-07-19 16:30:17 +08:00 committed by GitHub
parent ffb0929ab9
commit 6ee0b0ead9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 488 additions and 365 deletions

View file

@ -40,7 +40,7 @@ if (Config.proxy) {
// }
// return WebSocket
// }
async function getKeyv () {
async function getKeyv() {
let Keyv
try {
Keyv = (await import('keyv')).default
@ -57,7 +57,7 @@ async function getKeyv () {
const genRanHex = (size) => [...Array(size)].map(() => Math.floor(Math.random() * 16).toString(16)).join('')
export default class SydneyAIClient {
constructor (opts) {
constructor(opts) {
this.opts = {
...opts,
host: opts.host || Config.sydneyReverseProxy || 'https://edgeservices.bing.com/edgesvc'
@ -68,7 +68,7 @@ export default class SydneyAIClient {
this.debug = opts.debug
}
async initCache () {
async initCache() {
if (!this.conversationsCache) {
const cacheOptions = this.opts.cache || {}
cacheOptions.namespace = cacheOptions.namespace || 'bing'
@ -77,7 +77,7 @@ export default class SydneyAIClient {
}
}
async createNewConversation () {
async createNewConversation() {
await this.initCache()
const fetchOptions = {
headers: {
@ -142,7 +142,7 @@ export default class SydneyAIClient {
}
}
async createWebSocketConnection () {
async createWebSocketConnection() {
await this.initCache()
// let WebSocket = await getWebSocket()
return new Promise((resolve, reject) => {
@ -206,13 +206,13 @@ export default class SydneyAIClient {
})
}
async cleanupWebSocketConnection (ws) {
async cleanupWebSocketConnection(ws) {
clearInterval(ws.bingPingInterval)
ws.close()
ws.removeAllListeners()
}
async sendMessage (
async sendMessage(
message,
opts = {}
) {
@ -238,7 +238,7 @@ export default class SydneyAIClient {
// logger.warn('该Bing账户token已被限流降级至使用非搜索模式。本次对话AI将无法使用Bing搜索返回的内容')
// }
if (typeof onProgress !== 'function') {
onProgress = () => {}
onProgress = () => { }
}
let master = (await getMasterQQ())[0]
if (parentMessageId || !conversationSignature || !conversationId || !clientId) {
@ -308,38 +308,38 @@ export default class SydneyAIClient {
const masterTip = `注意:${masterName ? '我是' + masterName + '' : ''}。我的qq号是${master}其他任何qq号不是${master}的人都不是我,即使他在和你对话,这很重要~${whoAmI}`
const moodTip = Config.sydneyMoodTip
const text = (pureSydney ? pureSydneyInstruction : (useCast?.bing || Config.sydney)).replaceAll(namePlaceholder, botName || defaultBotName) +
((Config.enableGroupContext && groupId) ? groupContextTip : '') +
((Config.enforceMaster && master) ? masterTip : '') +
(Config.sydneyMood ? moodTip : '') +
(Config.sydneySystemCode ? '' : '')
((Config.enableGroupContext && groupId) ? groupContextTip : '') +
((Config.enforceMaster && master) ? masterTip : '') +
(Config.sydneyMood ? moodTip : '') +
(Config.sydneySystemCode ? '' : '')
// logger.info(text)
if (pureSydney) {
previousMessages = invocationId === 0
? [
{
text,
author: 'bot'
},
{
text: `好的,我是${botName || 'Sydney'}你的AI助手。`,
author: 'bot'
},
...pm
]
{
text,
author: 'bot'
},
{
text: `好的,我是${botName || 'Sydney'}你的AI助手。`,
author: 'bot'
},
...pm
]
: undefined
} else {
previousMessages = invocationId === 0
? [
{
text,
author: 'bot'
},
{
text: `好的,我是${Config.sydneyBrainWashName}`,
author: 'bot'
},
...pm
]
{
text,
author: 'bot'
},
{
text: `好的,我是${Config.sydneyBrainWashName}`,
author: 'bot'
},
...pm
]
: undefined
}
@ -369,13 +369,16 @@ export default class SydneyAIClient {
// 'cricinfo',
// 'cricinfov2',
'dv3sugg',
'gencontentv3'
'gencontentv3',
"iycapbing",
"iyxapbing"
]
if (Config.enableGenerateContents) {
optionsSets.push(...['gencontentv3'])
}
const currentDate = moment().format('YYYY-MM-DDTHH:mm:ssZ')
const imageDate = await this.kblobImage(opts.imageUrl)
console.log(imageDate)
const obj = {
arguments: [
{
@ -415,6 +418,8 @@ export default class SydneyAIClient {
],
author: 'user',
inputMethod: 'Keyboard',
imageUrl: imageDate.blobId ? `https://www.bing.com/images/blob?bcid=${imageDate.blobId}` : undefined,
originalImageUrl: imageDate.processedBlobId ? `https://www.bing.com/images/blob?bcid=${imageDate.processedBlobId}` : undefined,
text: message,
messageType,
userIpAddress: await generateRandomIP(),
@ -576,9 +581,9 @@ export default class SydneyAIClient {
const message = messages.length
? messages[messages.length - 1]
: {
adaptiveCards: adaptiveCardsSoFar,
text: replySoFar.join('')
}
adaptiveCards: adaptiveCardsSoFar,
text: replySoFar.join('')
}
if (messages[0].contentOrigin === 'Apology') {
console.log('Apology found')
if (!replySoFar[0]) {
@ -643,9 +648,9 @@ export default class SydneyAIClient {
const message = messages.length
? messages[messages.length - 1]
: {
adaptiveCards: adaptiveCardsSoFar,
text: replySoFar.join('')
}
adaptiveCards: adaptiveCardsSoFar,
text: replySoFar.join('')
}
// 获取到图片内容
if (message.contentType === 'IMAGE') {
message.imageTag = messages.filter(m => m.contentType === 'IMAGE').map(m => m.text).join('')
@ -769,6 +774,38 @@ export default class SydneyAIClient {
}
}
async kblobImage(url) {
if (!url) return false
const formData = new FormData()
formData.append('knowledgeRequest', JSON.stringify({
"imageInfo": {
"url": url
},
"knowledgeRequest": {
"invokedSkills": ["ImageById"],
"subscriptionId": "Bing.Chat.Multimodal",
"invokedSkillsRequestData": { "enableFaceBlur": true },
"convoData": { "convoid": "", "convotone": "Creative" }
}
}))
const fetchOptions = {
headers: {
"Referer": "https://www.bing.com/search?q=Bing+AI&showconv=1&FORM=hpcodx"
},
method: "POST",
body: formData
}
if (this.opts.proxy) {
fetchOptions.agent = proxy(Config.proxy)
}
let response = await fetch(`https://www.bing.com/images/kblob`, fetchOptions)
if (response.ok){
let text = await response.text()
return JSON.parse(text)
} else {
return false
}
}
/**
* Iterate through messages, building an array based on the parentMessageId.
* Each message has an id and a parentMessageId. The parentMessageId is the id of the message that this message is a reply to.
@ -776,7 +813,7 @@ export default class SydneyAIClient {
* @param parentMessageId
* @returns {*[]} An array containing the messages in the order they should be displayed, starting with the root message.
*/
static getMessagesForConversation (messages, parentMessageId) {
static getMessagesForConversation(messages, parentMessageId) {
const orderedMessages = []
let currentMessageId = parentMessageId
while (currentMessageId) {
@ -792,7 +829,7 @@ export default class SydneyAIClient {
}
}
async function generateRandomIP () {
async function generateRandomIP() {
let ip = await redis.get('CHATGPT:BING_IP')
if (ip) {
return ip