doomiaichat
Version:
Doomisoft OpenAI
125 lines (122 loc) • 5.74 kB
text/typescript
/**
* 接入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 }
}
}
}