123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302 |
- import {
- ChatRequest,
- ChatResponse,
- ErrorResponse,
- LmConfigListParams,
- LmConfigAddReq,
- LmConfigEditReq,
- LmConfigStatusReq,
- LmConfigDeleteParams,
- LmConfigGetParams
- } from '/@/api/assist/type'
- import { get, post, del, put } from '/@/utils/request'
- import getOrigin from '/@/utils/origin'
- import { getToken } from "/@/utils/auth";
- export default {
- model: {
- // 大语言模型配置列表
- getList: (params?: LmConfigListParams) => get('/system/lmconfig/list', params),
- // 获取大语言模型配置信息
- detail: (params: LmConfigGetParams) => get('/system/lmconfig/get', params),
- // 添加大语言模型配置
- add: (data: LmConfigAddReq) => post('/system/lmconfig/add', data),
- // 修改大语言模型配置
- edit: (data: LmConfigEditReq) => put('/system/lmconfig/edit', data),
- // 删除大语言模型配置
- del: (params: LmConfigDeleteParams) => del('/system/lmconfig/delete', params),
- // 设置大语言模型配置状态
- setStatus: (data: LmConfigStatusReq) => put('/system/lmconfig/status', data),
- },
- // SSE聊天方法
- chat: (
- data:
- {
- chatRequest: ChatRequest,
- // eslint-disable-next-line no-unused-vars
- onReceive: (resp: ChatResponse) => void,
- // eslint-disable-next-line no-unused-vars
- onComplete?: (error: Error|undefined)=> void
- },
- ) => {
- const {chatRequest, onReceive,onComplete} = data
- //FIXME 需要抹掉
- chatRequest.modelMcpId = 1 as unknown as number[]
- chatRequest["UserId"] = 10
- // 构建SSE URL
- const baseURL = getOrigin();
- const url = `${baseURL}/ai/chat`;
- // 使用fetch API实现SSE POST请求(EventSource不支持POST和自定义headers)
- const controller = new AbortController();
- // 使用fetch API实现SSE POST请求
- const startSSE = async () => {
- try {
- const headers: Record<string, string> = {
- 'Content-Type': 'application/json',
- 'Accept': 'text/event-stream',
- 'Cache-Control': 'no-cache',
- };
- // 添加认证token
- const token = getToken();
- if (token) {
- headers['Authorization'] = `Bearer ${token}`;
- }
- const response = await fetch(url, {
- method: 'POST',
- headers,
- body: JSON.stringify(chatRequest),
- signal: controller.signal,
- }).catch((e:Error)=> e);
- if (response instanceof Error) {
- throw new Error('无法连接到服务器');
- }
- if (!response.ok) {
- throw new Error(`HTTP error! status: ${response.status}`);
- }
- const reader = response.body?.getReader();
- const decoder = new TextDecoder();
- if (!reader) {
- throw new Error('Response body is not readable');
- }
- // 读取SSE流
- let currentEvent = '';
- let buffer = '';
- while (true) {
- const { done, value } = await reader.read();
- if (done) {
- break;
- }
- buffer += decoder.decode(value, { stream: true });
- // 按双换行符分割事件块
- const eventBlocks = buffer.split('\n\n');
- // 保留最后一个可能不完整的事件块
- buffer = eventBlocks.pop() || '';
- for (const eventBlock of eventBlocks) {
- if (!eventBlock.trim()) continue;
- const lines = eventBlock.split('\n');
- let eventType = '';
- let dataLines: string[] = [];
- // 解析事件块中的每一行
- for (const line of lines) {
- const trimmedLine = line.trim();
- if (trimmedLine.startsWith('event:')) {
- eventType = trimmedLine.substring(6).trim();
- } else if (trimmedLine.startsWith('data:')) {
- // 提取data后的内容,保留原始格式(包括可能的空格)
- const dataContent = line.substring(line.indexOf('data:') + 5);
- dataLines.push(dataContent);
- }
- }
- // 如果有事件类型,更新当前事件
- if (eventType) {
- currentEvent = eventType;
- }
- // 如果有数据行,处理数据
- if (dataLines.length > 0) {
- // 将多行data合并,用换行符连接
- const data = dataLines.join('\n');
- // 根据事件类型处理数据
- switch (currentEvent) {
- case 'message': {
- const messageResponse: ChatResponse = {
- type: 'message',
- message: data
- };
- onReceive(messageResponse);
- break;
- }
- case 'toolcall': {
- const tools = JSON.parse(data);
- const toolcallResponse: ChatResponse = {
- type: 'toolcall',
- request: {
- name: tools["name"],
- data: tools["arguments"]
- }
- };
- onReceive(toolcallResponse);
- break;
- }
- case 'toolres': {
- const tools = JSON.parse(data);
- const toolresResponse: ChatResponse = {
- type: 'toolres',
- response: {
- name: tools["name"],
- data: tools["response"]
- },
- };
- onReceive(toolresResponse);
- break;
- }
- case 'error': {
- const errorResponse: ErrorResponse = {
- type: 'error',
- error: data
- }
- onReceive(errorResponse)
- break
- }
- case 'meta': {
- break
- }
- default: {
- // 如果没有明确的事件类型,默认作为消息处理
- const defaultResponse: ChatResponse = {
- type: 'message',
- message: data
- };
- onReceive(defaultResponse);
- break;
- }
- }
- }
- }
- // 处理buffer中剩余的可能完整的单行事件
- const remainingLines = buffer.split('\n');
- const completeLines = remainingLines.slice(0, -1);
- buffer = remainingLines[remainingLines.length - 1] || '';
- for (const line of completeLines) {
- const trimmedLine = line.trim();
- if (trimmedLine === '') {
- continue;
- }
- if (trimmedLine.startsWith('event:')) {
- currentEvent = trimmedLine.substring(6).trim();
- continue;
- }
- if (trimmedLine.startsWith('data:')) {
- const data = line.substring(line.indexOf('data:') + 5);
- // 根据事件类型处理数据
- switch (currentEvent) {
- case 'message': {
- const messageResponse: ChatResponse = {
- type: 'message',
- message: data
- };
- onReceive(messageResponse);
- break;
- }
- case 'toolcall': {
- try {
- const tools = JSON.parse(data);
- const toolcallResponse: ChatResponse = {
- type: 'toolcall',
- request: {
- name: tools["name"],
- data: tools["arguments"]
- }
- };
- onReceive(toolcallResponse);
- } catch (error) {
- console.error('解析toolcall数据失败:', error, '原始数据:', data);
- }
- break;
- }
- case 'toolres': {
- try {
- const tools = JSON.parse(data);
- const toolresResponse: ChatResponse = {
- type: 'toolres',
- response: {
- name: tools["name"],
- data: tools["response"]
- },
- };
- onReceive(toolresResponse);
- } catch (error) {
- console.error('解析toolres数据失败:', error, '原始数据:', data);
- }
- break;
- }
- default: {
- // 如果没有明确的事件类型,默认作为消息处理
- const defaultResponse: ChatResponse = {
- type: 'message',
- message: data
- };
- onReceive(defaultResponse);
- break;
- }
- }
- }
- }
- }
- onComplete?.(undefined)
- } catch (error: any) {
- if (error.name !== 'AbortError') {
- console.error('SSE连接错误:', error);
- }
- onComplete?.(error)
- }
- };
- // 启动SSE连接
- startSSE();
- // 返回关闭连接的函数
- return () => {
- controller.abort();
- };
- },
- }
|