Merge branch 'ikechan8370:v2' into v2

This commit is contained in:
ifeif 2023-08-29 15:31:12 +08:00 committed by GitHub
commit d0b5585539
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 1265 additions and 98 deletions

View file

@ -70,25 +70,25 @@ export default class SydneyAIClient {
accept: 'application/json',
'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
'content-type': 'application/json',
'sec-ch-ua': '"Microsoft Edge";v="113", "Chromium";v="113", "Not-A.Brand";v="24"',
// 'sec-ch-ua': '"Microsoft Edge";v="113", "Chromium";v="113", "Not-A.Brand";v="24"',
// 'sec-ch-ua-arch': '"x86"',
// 'sec-ch-ua-bitness': '"64"',
// 'sec-ch-ua-full-version': '"112.0.1722.7"',
// 'sec-ch-ua-full-version-list': '"Chromium";v="112.0.5615.20", "Microsoft Edge";v="112.0.1722.7", "Not:A-Brand";v="99.0.0.0"',
'sec-ch-ua-mobile': '?0',
// 'sec-ch-ua-mobile': '?0',
// 'sec-ch-ua-model': '',
'sec-ch-ua-platform': '"macOS"',
// 'sec-ch-ua-platform': '"macOS"',
// 'sec-ch-ua-platform-version': '"15.0.0"',
'sec-fetch-dest': 'empty',
'sec-fetch-mode': 'cors',
'sec-fetch-site': 'same-origin',
'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',
// 'sec-fetch-dest': 'empty',
// 'sec-fetch-mode': 'cors',
// 'sec-fetch-site': 'same-origin',
// '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,',
'Referrer-Policy': 'origin-when-cross-origin',
// 'Referrer-Policy': 'origin-when-cross-origin',
// Workaround for request being blocked due to geolocation
'x-forwarded-for': '1.1.1.1'
// 'x-forwarded-for': '1.1.1.1'
}
}
if (this.opts.cookies || this.opts.userToken) {

373
utils/bard.js Normal file
View file

@ -0,0 +1,373 @@
// https://github.com/EvanZhouDev/bard-ai
class Bard {
static JSON = "json";
static MD = "markdown";
// ID derived from Cookie
SNlM0e;
// HTTPS Headers
#headers;
// Resolution status of initialization call
#initPromise;
#bardURL = "https://bard.google.com";
// Wether or not to log events to console
#verbose = false;
// Fetch function
#fetch = fetch;
constructor(cookie, config) {
// Register some settings
if (config?.verbose == true) this.#verbose = true;
if (config?.fetch) this.#fetch = config.fetch;
// 可变更访问地址,利用反向代理绕过区域限制
if (config?.bardURL) this.#bardURL = config.bardURL;
// If a Cookie is provided, initialize
if (cookie) {
this.#initPromise = this.#init(cookie);
} else {
throw new Error("Please provide a Cookie when initializing Bard.");
}
this.cookie = cookie;
}
// You can also choose to initialize manually
async #init(cookie) {
this.#verbose && console.log("🚀 Starting intialization");
// Assign headers
this.#headers = {
Host: this.#bardURL.match(/^https?:\/\/([^\/]+)\/?$/)[1],
"X-Same-Domain": "1",
"User-Agent":
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36",
"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
Origin: this.#bardURL,
Referer: this.#bardURL,
Cookie: (typeof cookie === "object") ? (Object.entries(cookie).map(([key, val]) => `${key}=${val};`).join("")) : ("__Secure-1PSID=" + cookie),
};
let responseText;
// Attempt to retrieve SNlM0e
try {
this.#verbose &&
console.log("🔒 Authenticating your Google account");
responseText = await this.#fetch(this.#bardURL, {
method: "GET",
headers: this.#headers,
credentials: "include",
})
.then((response) => response.text())
} catch (e) {
// Failure to get server
throw new Error(
"Could not fetch Google Bard. You may be disconnected from internet: " +
e
);
}
try {
const SNlM0e = responseText.match(/SNlM0e":"(.*?)"/)[1];
// Assign SNlM0e and return it
this.SNlM0e = SNlM0e;
this.#verbose && console.log("✅ Initialization finished\n");
return SNlM0e;
} catch {
throw new Error(
"Could not use your Cookie. Make sure that you copied correctly the Cookie with name __Secure-1PSID exactly. If you are sure your cookie is correct, you may also have reached your rate limit."
);
}
}
async #uploadImage(name, buffer) {
this.#verbose && console.log("🖼️ Starting image processing");
let size = buffer.byteLength;
let formBody = [
`${encodeURIComponent("File name")}=${encodeURIComponent([name])}`,
];
try {
this.#verbose &&
console.log("💻 Finding Google server destination");
let response = await this.#fetch(
"https://content-push.googleapis.com/upload/",
{
method: "POST",
headers: {
"X-Goog-Upload-Command": "start",
"X-Goog-Upload-Protocol": "resumable",
"X-Goog-Upload-Header-Content-Length": size,
"X-Tenant-Id": "bard-storage",
"Push-Id": "feeds/mcudyrk2a4khkz",
},
body: formBody,
credentials: "include",
}
);
const uploadUrl = response.headers.get("X-Goog-Upload-URL");
this.#verbose && console.log("📤 Sending your image");
response = await this.#fetch(uploadUrl, {
method: "POST",
headers: {
"X-Goog-Upload-Command": "upload, finalize",
"X-Goog-Upload-Offset": 0,
"X-Tenant-Id": "bard-storage",
},
body: buffer,
credentials: "include",
});
const imageFileLocation = await response.text();
this.#verbose && console.log("✅ Image finished working\n");
return imageFileLocation;
} catch (e) {
throw new Error(
"Could not fetch Google Bard. You may be disconnected from internet: " +
e
);
}
}
// Query Bard
async #query(message, config) {
let formatMarkdown = (text, images) => {
if (!images) return text;
for (let imageData of images) {
const formattedTag = `!${imageData.tag}(${imageData.url})`;
text = text.replace(
new RegExp(`(?!\\!)\\[${imageData.tag.slice(1, -1)}\\]`),
formattedTag
);
}
return text;
}
let { ids, imageBuffer } = config;
// Wait until after init
await this.#initPromise;
this.#verbose && console.log("🔎 Starting Bard Query");
// If user has not run init
if (!this.SNlM0e) {
throw new Error(
"Please initialize Bard first. If you haven't passed in your Cookie into the class, run Bard.init(cookie)."
);
}
this.#verbose && console.log("🏗️ Building Request");
// HTTPS parameters
const params = {
bl: "boq_assistant-bard-web-server_20230711.08_p0",
_reqID: ids?._reqID ?? "0",
rt: "c",
};
// If IDs are provided, but doesn't have every one of the expected IDs, error
const messageStruct = [
[message],
null,
[null, null, null],
];
if (imageBuffer) {
let imageLocation = await this.#uploadImage(
`bard-ai_upload`,
imageBuffer
);
messageStruct[0].push(0, null, [
[[imageLocation, 1], "bard-ai_upload"],
]);
}
if (ids) {
const { conversationID, responseID, choiceID } = ids;
messageStruct[2] = [conversationID, responseID, choiceID];
}
// HTTPs data
const data = {
"f.req": JSON.stringify([null, JSON.stringify(messageStruct)]),
at: this.SNlM0e,
};
// URL that we are submitting to
const url = new URL(
"/_/BardChatUi/data/assistant.lamda.BardFrontendService/StreamGenerate",
this.#bardURL
);
// Append parameters to the URL
for (const key in params) {
url.searchParams.append(key, params[key]);
}
// Encode the data
const formBody = Object.entries(data)
.map(
([property, value]) =>
`${encodeURIComponent(property)}=${encodeURIComponent(
value
)}`
)
.join("&");
this.#verbose && console.log("💭 Sending message to Bard");
// Send the fetch request
const chatData = await this.#fetch(url.toString(), {
method: "POST",
headers: this.#headers,
body: formBody,
credentials: "include",
})
.then((response) => {
return response.text();
})
.then((text) => {
return JSON.parse(text.split("\n")[3])[0][2];
})
.then((rawData) => JSON.parse(rawData));
this.#verbose && console.log("🧩 Parsing output");
// Get first Bard-recommended answer
const answer = chatData[4][0];
// Text of that answer
const text = answer[1][0];
// Get data about images in that answer
const images =
answer[4]?.map((x) => ({
tag: x[2],
url: x[3][0][0],
info: {
raw: x[0][0][0],
source: x[1][0][0],
alt: x[0][4],
website: x[1][1],
favicon: x[1][3],
},
})) ?? [];
this.#verbose && console.log("✅ All done!\n");
// Put everything together and return
return {
content: formatMarkdown(text, images),
images: images,
ids: {
conversationID: chatData[1][0],
responseID: chatData[1][1],
choiceID: answer[0],
_reqID: String(parseInt(ids?._reqID ?? 0) + 100000),
},
};
}
async #parseConfig(config) {
let result = {
useJSON: false,
imageBuffer: undefined, // Returns as {extension, filename}
ids: undefined,
};
// Verify that format is one of the two types
if (config?.format) {
switch (config.format) {
case Bard.JSON:
result.useJSON = true;
break;
case Bard.MD:
result.useJSON = false;
break;
default:
throw new Error(
"Format can obly be Bard.JSON for JSON output or Bard.MD for Markdown output."
);
}
}
// Verify that the image passed in is either a path to a jpeg, jpg, png, or webp, or that it is a Buffer
if (config?.image) {
if (
config.image instanceof ArrayBuffer
) {
result.imageBuffer = config.image;
} else if (
typeof config.image === "string" &&
/\.(jpeg|jpg|png|webp)$/.test(config.image)
) {
let fs;
try {
fs = await import("fs")
} catch {
throw new Error(
"Loading from an image file path is not supported in a browser environment.",
);
}
result.imageBuffer = fs.readFileSync(
config.image,
).buffer;
} else {
throw new Error(
"Provide your image as a file path to a .jpeg, .jpg, .png, or .webp, or a Buffer."
);
}
}
// Verify that all values in IDs exist
if (config?.ids) {
if (config.ids.conversationID && config.ids.responseID && config.ids.choiceID && config.ids._reqID) {
result.ids = config.ids;
} else {
throw new Error(
"Please provide the IDs exported exactly as given."
);
}
}
return result;
}
// Ask Bard a question!
async ask(message, config) {
let { useJSON, imageBuffer, ids } = await this.#parseConfig(config);
let response = await this.#query(message, { imageBuffer, ids });
return useJSON ? response : response.content;
}
createChat(ids) {
let bard = this;
class Chat {
ids = ids;
async ask(message, config) {
let { useJSON, imageBuffer } = await bard.#parseConfig(config);
let response = await bard.#query(message, {
imageBuffer,
ids: this.ids,
});
this.ids = response.ids;
return useJSON ? response : response.content;
}
export() {
return this.ids;
}
}
return new Chat();
}
}
export default Bard;

View file

@ -717,6 +717,7 @@ export async function getUserData (user) {
chat: [],
mode: '',
cast: {
azure: '',
api: '', // API设定
bing: '', // 必应设定
bing_resource: '', // 必应扩展资料

View file

@ -50,6 +50,17 @@ const defaultConfig = {
plus: false,
useGPT4: false,
xinghuoToken: '',
xhmode: 'web',
xhAppId: '',
xhAPISecret: '',
xhAPIKey: '',
xhAssistants: '',
xhTemperature: 0.5,
xhMaxTokens: 1024,
xhPromptSerialize: false,
xhPrompt: '',
xhRetRegExp: '',
xhRetReplace: '',
promptPrefixOverride: 'Your answer shouldn\'t be too verbose. Prefer to answer in Chinese.',
assistantLabel: 'ChatGPT',
// thinkingTips: true,
@ -113,6 +124,9 @@ const defaultConfig = {
slackClaudeEnableGlobalPreset: true,
slackClaudeGlobalPreset: '',
slackClaudeSpecifiedChannel: '',
bardPsid: '',
bardReverseProxy: '',
bardForceUseReverse: false,
cloudTranscode: 'https://silk.201666.xyz',
cloudRender: false,
cloudMode: 'url',

View file

@ -2,6 +2,8 @@ import fetch from 'node-fetch'
import { Config } from '../config.js'
import { createParser } from 'eventsource-parser'
import https from 'https'
import WebSocket from 'ws'
import { config } from 'process'
const referer = atob('aHR0cHM6Ly94aW5naHVvLnhmeXVuLmNuL2NoYXQ/aWQ9')
const origin = atob('aHR0cHM6Ly94aW5naHVvLnhmeXVuLmNu')
@ -13,8 +15,24 @@ try {
} catch (err) {
logger.warn('未安装form-data无法使用星火模式')
}
let crypto
try {
crypto = (await import('crypto')).default
} catch (err) {
logger.warn('未安装crypto无法使用星火api模式')
}
async function getKeyv() {
let Keyv
try {
Keyv = (await import('keyv')).default
} catch (error) {
throw new Error('keyv依赖未安装请使用pnpm install keyv安装')
}
return Keyv
}
export default class XinghuoClient {
constructor (opts) {
constructor(opts) {
this.cache = opts.cache
this.ssoSessionId = opts.ssoSessionId
this.headers = {
Referer: referer,
@ -24,19 +42,249 @@ export default class XinghuoClient {
}
}
async sendMessage (prompt, chatId) {
apiErrorInfo(code) {
switch (code) {
case 10000: return '升级为ws出现错误'
case 10001: return '通过ws读取用户的消息出错'
case 10002: return '通过ws向用户发送消息 错'
case 10003: return '用户的消息格式有错误'
case 10004: return '用户数据的schema错误'
case 10005: return '用户参数值有错误'
case 10006: return '用户并发错误:当前用户已连接,同一用户不能多处同时连接。'
case 10007: return '用户流量受限:服务正在处理用户当前的问题,需等待处理完成后再发送新的请求。(必须要等大模型完全回复之后,才能发送下一个问题)'
case 10008: return '服务容量不足,联系工作人员'
case 10009: return '和引擎建立连接失败'
case 10010: return '接收引擎数据的错误'
case 10011: return '发送数据给引擎的错误'
case 10012: return '引擎内部错误'
case 10013: return '输入内容审核不通过,涉嫌违规,请重新调整输入内容'
case 10014: return '输出内容涉及敏感信息,审核不通过,后续结果无法展示给用户'
case 10015: return 'appid在黑名单中'
case 10016: return 'appid授权类的错误。比如未开通此功能未开通对应版本token不足并发超过授权 等等'
case 10017: return '清除历史失败'
case 10019: return '表示本次会话内容有涉及违规信息的倾向;建议开发者收到此错误码后给用户一个输入涉及违规的提示'
case 10110: return '服务忙,请稍后再试'
case 10163: return '请求引擎的参数异常 引擎的schema 检查不通过'
case 10222: return '引擎网络异常'
case 10907: return 'token数量超过上限。对话历史+问题的字数太多,需要精简输入'
case 11200: return '授权错误该appId没有相关功能的授权 或者 业务量超过限制'
case 11201: return '授权错误:日流控超限。超过当日最大访问量的限制'
case 11202: return '授权错误:秒级流控超限。秒级并发超过授权路数限制'
case 11203: return '授权错误:并发流控超限。并发路数超过授权路数限制'
default: return '无效错误代码'
}
}
promptBypassPreset(prompt) {
switch (prompt) {
case '你是谁':
return '你是谁,叫什么'
case '你是谁啊':
return '你是谁啊,叫什么'
default:
return prompt
}
}
async initCache() {
if (!this.conversationsCache) {
const cacheOptions = this.cache || {}
cacheOptions.namespace = cacheOptions.namespace || 'xh'
let Keyv = await getKeyv()
this.conversationsCache = new Keyv(cacheOptions)
}
}
async getWsUrl() {
if (!crypto) return false
const APISecret = Config.xhAPISecret
const APIKey = Config.xhAPIKey
let APILink = '/v1.1/chat'
if (Config.xhmode == 'apiv2') {
APILink = '/v2.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)
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"
}
const url = `wss://spark-api.xf-yun.com${APILink}?${Object.keys(v).map(key => `${key}=${v[key]}`).join('&')}`
return url
}
async uploadImage(url) {
// 获取图片
let response = await fetch(url, {
method: 'GET',
})
const blob = await response.blob()
const arrayBuffer = await blob.arrayBuffer()
const buffer = Buffer.from(arrayBuffer)
// 上传oss
const formData = new FormData()
formData.append('file', buffer, 'image.png')
const respOss = await fetch('https://xinghuo.xfyun.cn/iflygpt/oss/sign', {
method: 'POST',
headers: {
Cookie: 'ssoSessionId=' + this.ssoSessionId + ';',
},
body: formData
})
if (respOss.ok) {
const ossData = await respOss.json()
// 上传接口
const sparkdeskUrl = `${ossData.data.url}&authorization=${Buffer.from(ossData.data.authorization).toString('base64')}&date=${ossData.data.date}&host=${ossData.data.host}`
const respSparkdes = await fetch(sparkdeskUrl, {
method: 'POST',
headers: {
Cookie: 'ssoSessionId=' + this.ssoSessionId + ';',
authorization: Buffer.from(ossData.data.authorization).toString('base64')
},
body: buffer
})
if (respSparkdes.ok) {
const sparkdesData = await respSparkdes.json()
return {
url: sparkdesData.data.link,
file: buffer
}
} else {
try {
const sparkdesData = await respSparkdes.json()
logger.error('星火图片Sparkdes发送失败' + sparkdesData.desc)
} catch (error) {
logger.error('星火图片Sparkdes发送失败')
}
return false
}
} else {
try {
const ossData = await respOss.json()
logger.error('星火图片OSS上传失败' + ossData.desc)
} catch (error) {
logger.error('星火图片OSS上传失败')
}
return false
}
}
async apiMessage(prompt, chatId, ePrompt = []) {
if (!chatId) chatId = (Math.floor(Math.random() * 1000000) + 100000).toString()
// 初始化缓存
await this.initCache()
const conversationKey = `ChatXH_${chatId}`
const conversation = (await this.conversationsCache.get(conversationKey)) || {
messages: [],
createdAt: Date.now()
}
// 获取ws链接
const wsUrl = Config.xhmode == 'assistants' ? Config.xhAssistants : await this.getWsUrl()
if (!wsUrl) throw new Error('缺少依赖crypto。请安装依赖后重试')
// 编写消息内容
const wsSendData = {
header: {
app_id: Config.xhAppId,
uid: chatId
},
parameter: {
chat: {
domain: Config.xhmode == 'api' ? "general" : "generalv2",
temperature: Config.xhTemperature, // 核采样阈值
max_tokens: Config.xhMaxTokens, // tokens最大长度
chat_id: chatId
}
},
payload: {
message: {
"text": [
...ePrompt,
...conversation.messages,
{ "role": "user", "content": prompt }
]
}
}
}
if (Config.debug) {
logger.info(wsSendData.payload.message.text)
}
return new Promise((resolve, reject) => {
const socket = new WebSocket(wsUrl)
let resMessage = ''
socket.on('open', () => {
socket.send(JSON.stringify(wsSendData))
})
socket.on('message', async (message) => {
try {
const messageData = JSON.parse(message)
if (messageData.header.code != 0) {
reject(`接口发生错误Error Code ${messageData.header.code} ,${this.apiErrorInfo(messageData.header.code)}`)
}
if (messageData.header.status == 0 || messageData.header.status == 1) {
resMessage += messageData.payload.choices.text[0].content
}
if (messageData.header.status == 2) {
resMessage += messageData.payload.choices.text[0].content
conversation.messages.push({
role: 'user',
content: prompt
})
conversation.messages.push({
role: 'assistant',
content: resMessage
})
// 超过规定token去除一半曾经的对话记录
if (messageData.payload.usage.text.total_tokens >= Config.xhMaxTokens) {
const half = Math.floor(conversation.messages.length / 2)
conversation.messages.splice(0, half)
}
await this.conversationsCache.set(conversationKey, conversation)
resolve(resMessage)
}
} catch (error) {
reject(new Error(error))
}
})
socket.on('error', (error) => {
reject(error)
})
})
}
async webMessage(prompt, chatId, botId) {
if (!FormData) {
throw new Error('缺少依赖form-data。请安装依赖后重试')
}
if (!chatId) {
chatId = (await this.createChatList()).chatListId
}
let requestP = new Promise((resolve, reject) => {
return new Promise(async (resolve, reject) => {
let formData = new FormData()
formData.setBoundary('----WebKitFormBoundarycATE2QFHDn9ffeWF')
formData.append('clientType', '2')
formData.append('chatId', chatId)
formData.append('text', prompt)
if (prompt.image) {
prompt.text = prompt.text.replace("[图片]", "") // 清理消息中中首个被使用的图片
const imgdata = await this.uploadImage(prompt.image)
if (imgdata) {
formData.append('fileUrl', imgdata.url)
formData.append('file', imgdata.file, 'image.png')
}
}
formData.append('text', prompt.text)
if (botId) {
formData.append('isBot', '1')
formData.append('botId', botId)
}
let randomNumber = Math.floor(Math.random() * 1000)
let fd = '439' + randomNumber.toString().padStart(3, '0')
formData.append('fd', fd)
@ -57,7 +305,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({
@ -65,8 +313,18 @@ export default class XinghuoClient {
response
})
}
if (data.charAt(0) === '{') {
try {
response = JSON.parse(data).value
if (Config.debug) {
logger.info(response)
}
} catch (err) {
reject(err)
}
}
try {
if (data) {
if (data && data !== '[error]') {
response += atob(data.trim())
if (Config.debug) {
logger.info(response)
@ -112,22 +370,81 @@ export default class XinghuoClient {
// req.write(formData.stringify())
req.end()
})
const { response } = await requestP
// logger.info(response)
// let responseText = atob(response)
return {
conversationId: chatId,
text: response
}
async sendMessage(prompt, chatId, image) {
// 对星火预设的问题进行重写,避免收到预设回答
prompt = this.promptBypassPreset(prompt)
if (Config.xhmode == 'api' || Config.xhmode == 'apiv2' || Config.xhmode == 'assistants') {
if (!Config.xhAppId || !Config.xhAPISecret || !Config.xhAPIKey) throw new Error('未配置api')
let Prompt = []
// 设定
if (Config.xhPromptSerialize) {
try {
Prompt = JSON.parse(Config.xhPrompt)
} catch (error) {
Prompt = []
logger.warn('星火设定序列化失败,本次对话不附带设定')
}
} else {
Prompt = Config.xhPrompt ? [{ "role": "user", "content": Config.xhPrompt }] : []
}
let response = await this.apiMessage(prompt, chatId, Prompt)
if (Config.xhRetRegExp) {
response = response.replace(new RegExp(Config.xhRetRegExp, 'g'), Config.xhRetReplace)
}
return {
conversationId: chatId,
text: response
}
} else if (Config.xhmode == 'web') {
let botId = false
if (chatId && typeof chatId === 'object') {
chatId = chatId.chatid
botId = chatId.botid
}
if (!chatId) {
chatId = (await this.createChatList()).chatListId
}
let { response } = await this.webMessage({ text: prompt, image: image }, chatId, botId)
// logger.info(response)
// let responseText = atob(response)
// 处理图片
let images
if (response.includes('multi_image_url')) {
images = [{
tag: '',
url: JSON.parse(/{([^}]*)}/g.exec(response)[0]).url
}]
response = '我已经完成作品,欢迎您提出宝贵的意见和建议,帮助我快速进步~~'
}
if (botId) {
chatId = {
chatid: chatId,
botid: botId
}
}
if (Config.xhRetRegExp) {
response = response.replace(new RegExp(Config.xhRetRegExp, 'g'), Config.xhRetReplace)
}
return {
conversationId: chatId,
text: response,
images: images
}
} else {
throw new Error('星火模式错误')
}
}
async createChatList () {
async createChatList(bot = false) {
let createChatListRes = await fetch(createChatUrl, {
method: 'POST',
headers: Object.assign(this.headers, {
'Content-Type': 'application/json'
'Content-Type': 'application/json',
Botweb: bot ? 1 : 0
}),
body: '{}'
body: bot ? `{"BotWeb": 1, "botId": "${bot}"}` : '{}'
})
if (createChatListRes.status !== 200) {
let errorRes = await createChatListRes.text()
@ -139,8 +456,8 @@ export default class XinghuoClient {
if (createChatListRes.data?.id) {
logger.info('星火对话创建成功:' + createChatListRes.data.id)
} else {
logger.error('星火对话创建成功: ' + JSON.stringify(createChatListRes))
throw new Error('星火对话创建成功:' + JSON.stringify(createChatListRes))
logger.error('星火对话创建失败: ' + JSON.stringify(createChatListRes))
throw new Error('星火对话创建失败:' + JSON.stringify(createChatListRes))
}
return {
chatListId: createChatListRes.data?.id,
@ -149,6 +466,6 @@ export default class XinghuoClient {
}
}
function atob (s) {
function atob(s) {
return Buffer.from(s, 'base64').toString()
}