UNPKG

doomiaichat

Version:

Doomisoft OpenAI

125 lines (122 loc) 5.74 kB
/** * 接入AI平台的中间层 */ import axios from 'axios'; import { request } from "./declare"; import GptBase from "./gptbase" import { Readable } from 'stream'; // import { ChatReponse } from './declare'; export default class AIMiddlePlatform extends GptBase { protected apikey: string; protected agent: { endpoint: string, agentid: string }; /** * * @param apikey 调用AI中台 的key * @param agent 智能体信息 */ constructor(apikey: string, agent: { endpoint: string, agentid: string }) { super(); this.apikey = apikey; this.agent = agent; } /** * 非流式传输聊天请求 * @param chatText * @param callChatOption * @param axiosOption */ public async chatRequest(chatText: string | any, callChatOption: any, axiosOption: any = {}): Promise<any> { if (!chatText) { // this.emit('chaterror', { successed: false, error: 'no text in chat' }); return { successed: false, error: 'no text in chat' }; } const question = typeof chatText === 'object' ? chatText.text ?? chatText.content : chatText; axiosOption = Object.assign({}, axiosOption || { timeout: 60000 }) const opts: any = { headers: { 'Content-Type': 'application/json', 'authorization': `Bearer ${this.apikey}` }, method: 'post', url: `${this.agent.endpoint}/api/v1/agents/${this.agent.agentid}/completions`, data: { question, session_id: callChatOption.session_id, optional: callChatOption.optional, stream: false }, ...axiosOption } const response = await request(opts); if (!response.successed || response.data.code) return { successed: false, error: 'failed' }; const {answer:message,session_id} = response.data.data; // this.emit('chatdone', { successed: true, segment: message, text: message, finish_reason: 'stop', index: 0, session_id }) return { successed: true, message:[{message:{content:message}}],session_id }; } /** * 流式传输聊天请求 * @param chatText * @param callChatOption * @param attach * @param axiosOption * @returns */ override async chatRequestInStream(chatText: string | any, callChatOption: any, attach?: any, axiosOption?: any): Promise<any> { if (!chatText) this.emit('chaterror', { successed: false, error: 'no text in chat' }); // console.log('Question===>', chatText) const question = typeof chatText === 'object' ? chatText.text??chatText.content : chatText; axiosOption = Object.assign({}, axiosOption || { timeout: 60000 }) let requestid = Math.ceil(Math.random() * (new Date().getTime() * Math.random()) / 1000); try { const opts: any = { headers: { 'Content-Type': 'application/json', 'authorization': `Bearer ${this.apikey}` }, method: 'post', url: `${this.agent.endpoint}/api/v1/agents/${this.agent.agentid}/completions`, data: { question, session_id: callChatOption.session_id, stream: true, optional: callChatOption.optional, }, responseType: 'stream', ...axiosOption } const response = await axios(opts); const readableStream = Readable.from(response.data); let index = 0, session_id,fullanswer='',errorKeeped=[],chunks:any=[]; for await (const chunk of readableStream) { ///可能接收到的数据不完整,导致JSON.parse失败 let answerData = null, jsonStr = ''; try{ jsonStr = chunk.toString().split('data:') if (jsonStr.length) jsonStr = jsonStr[jsonStr.length-1]+'' answerData = JSON.parse(errorKeeped.join('') + jsonStr); }catch(e){ ////如果发生了JSON解析错误,则当前的数据不完整,留着拼凑下一回数据 // console.log('json parse error===>', errorKeeped.join('') + jsonStr) errorKeeped.push(jsonStr) // console.log('After Push===>', errorKeeped.join('') ) continue; } errorKeeped = []; const { answer, running_status, reference } = answerData.data; if (running_status === true) continue; const segment = answer ? answer.replace(fullanswer,''):'' fullanswer = answer ?? fullanswer; if (!session_id) session_id = answerData.data.session_id; if (reference && reference.chunks && reference.chunks.length) chunks = chunks.concat(reference.chunks) const finished = answerData.data === true; let output = { successed: true, requestid, segment: segment, chunks, text: fullanswer, finish_reason: finished ? 'stop' : null, index: index++, session_id }; if (attach) output = Object.assign({}, output, attach); this.emit(finished ? 'chatdone' : 'chattext', output) } return { successed: true, requestid } } catch (error) { // this.emit('requesterror', { successed: false, requestid, error: 'call axios faied ' + error }); // return { successed: false, requestid } } } }