import other from '/@/utils/other'; import request from '/@/utils/request'; import { fetchEventSource } from '@microsoft/fetch-event-source'; import { Session } from '/@/utils/storage'; export interface IOrchestrationScope { id?: string; username: string; } export enum EOrchestrationType { WORK_FLOW = 'WORK_FLOW', SIMPLE = 'SIMPLE', } export interface IOrchestrationItem { id?: string; name?: string; type?: EOrchestrationType; description?: string; isPublic?: boolean; publicAddress?: string; apiAddress?: string; apiBaseUrl?: string; fullScreenUrl?: string; fixedUrl?: string; questionLimit?: number; whiteListEnable?: boolean; whiteList?: string; showSource?: boolean; modelId?: string; createBy?: string; createTime?: string; updateTime?: string; modelSetting?: { prompt?: string; system?: string; noReferencesPrompt?: string; }; dialogueNumber?: number; datasetIdList?: any[]; datasetSetting?: { searchMode?: string; similarity?: number; topN?: number; maxParagraphCharNumber?: number; noReferencesSetting?: { status?: string; designatedAnswer?: string; }; }; problemOptimizationPrompt?: string; problemOptimization?: boolean; prologue?: string; sttModelEnable?: boolean; sttModelId?: string; ttsModelEnable?: boolean; ttsType?: string; ttsModelId?: string; ttsModelParamsSetting?: {}; fileUploadSetting?: { audio?: boolean; image?: boolean; video?: boolean; document?: boolean; maxFiles?: number; fileLimit?: number; }; disclaimerValue?: string; } export interface IOrchestrationAPIKey { id?: string; allowCrossDomain?: boolean; application?: string; createTime?: string; crossDomainList?: string; isActive?: boolean; secretKey?: string; updateTime?: string; } export function fetchList(query?: Object) { return request({ url: '/knowledge/aiFlow/page', method: 'get', params: query, }); } export function addObj(obj?: Object) { return request({ url: '/knowledge/aiFlow', method: 'post', data: obj, }); } export function getObj(id?: string) { return request({ url: '/knowledge/aiFlow/' + id, method: 'get', }); } export function delObjs(ids?: Object) { return request({ url: '/knowledge/aiFlow', method: 'delete', data: ids, }); } export function putObj(obj?: Object) { return request({ url: '/knowledge/aiFlow', method: 'put', data: obj, }); } export function exportFlow(id: string, name: string) { return other.downBlobFile(`/knowledge/aiFlow/export/${id}`, {}, `${name}.dsl`); } export function copyFlow(id: string) { return request.post(`/knowledge/aiFlow/copy/${id}`); } export function importFlow(data: FormData) { return request.post(`/knowledge/aiFlow/import`, data); } export interface IOrchestrationAPIKey { id?: string; allowCrossDomain?: boolean; application?: string; createTime?: string; crossDomainList?: string; isActive?: boolean; secretKey?: string; updateTime?: string; } /** * @description : 编排 发起导入 * @return {any} */ export async function orchestrationImportContent(data: FormData) { return request.post(`/knowledge/orchestration/import/content`, data); } /** * @description : 编排 发起导出 * @return {any} */ export async function orchestrationExportContent(id: string, name: string) { return other.downBlobFile(`/knowledge/orchestration/export/content/${id}`, {}, name); } /** * @description : 复制 编排 * @param {string} originId * @param {IOrchestrationItem} data * @return {any} */ export async function orchestrationCopy(originId: string, data: IOrchestrationItem) { return request.post(`/knowledge/orchestration/copy/${originId}`, data); } /** * @description : 获取 编排 详情 * @param {string} id * @return {any} */ export async function fetchOrchestrationInfo(id: string) { return request.get(`/knowledge/orchestration/info/${id}`); } export async function fetchChartRecord(id: string, data: { startTime: string; endTime: string }) { return request.get(`/knowledge/orchestration/chart/record/${id}`, { params: data }); } export async function fetchOrchestrationAPIKeyList(data: { id: string }) { return request.get(`/knowledge/orchestration/apikey/${data.id}`); } export async function orchestrationAPIKeyUpdate(data: any) { return request.put(`/knowledge/orchestration/apikey/update`, data); } export async function orchestrationAPIKeyAdd(id: string) { return request.post(`/knowledge/orchestration/apikey/${id}/add`); } export async function orchestrationAPIKeyRemove(id: string) { return request.delete(`/knowledge/orchestration/apikey/${id}/delete`); } /** * @description : 获取模型的参数设置 * @param {string} orchestrationId * @param {string} modelId * @return {any} */ export async function fetchModelParamsForm(orchestrationId: string, modelId: string) { return request.get(`/knowledge/orchestration/${orchestrationId}/modelParamsForm/${modelId}`); } /** * @description : 播放测试文本 * @param {string} id * @param {any} data * @return {any} */ export function playDemoText(id: string, data: any) { return request.post(`/knowledge/orchestration/playDemoText/${id}`, data, { responseType: 'blob', }); } /** * @description : 文件上传 * @param {String} application_id * @param {String} chat_id * @param {any} data * @return {any} */ export function chatUploadFile(application_id: string, chat_id: String, data: any) { return request.post(`/knowledge/orchestration/uploadFile/${application_id}/${chat_id}`, data); } /** * @description : 上传录音文件 * @param {string} application_id * @param {any} data * @return {any} */ export function chatPostSpeechToText(application_id: string, data: any) { return request.post(`/knowledge/orchestration/chatPostSpeechToText/${application_id}`, data); } export interface FlowExecutionResult { nodes: any[]; executed: boolean; result: any; duration: number; error?: string; totalTokens?: number; } export interface FlowExecutionEvent { type: 'start' | 'progress' | 'complete' | 'error' | 'chat_message'; nodeId?: string; nodeName?: string; data?: any; progress?: number; error?: string; result?: FlowExecutionResult; content?: string; tokens?: number; // 添加 tokens 字段 duration?: number; // 添加 duration 字段 nodes?: Array; // 添加 nodes 字段 isStreaming?: boolean; } export interface FlowExecutionCallbacks { onStart?: () => void; onProgress?: (event: FlowExecutionEvent) => void; onComplete?: (result: FlowExecutionResult) => void; onError?: (error: string) => void; onChatMessage?: (content: string, isComplete: boolean, tokens?: number, duration?: number, nodes?: Array) => void; } export function executeFlow(data: { id: string; params: any; envs: any; stream?: boolean }) { return request.post(`/knowledge/aiFlow/execute`, data, { timeout: 300000 // 设置超时时间为300秒 (300000毫秒) }); } /** * 使用SSE执行工作流,提供实时执行状态更新 * @param data 执行参数 * @param callbacks 回调函数 * @returns Promise */ export async function executeFlowSSE( data: { id: string; params: any; envs: any; stream?: boolean }, callbacks?: FlowExecutionCallbacks ): Promise { const token = Session.getToken(); const tenant = Session.getTenant(); return new Promise((resolve, reject) => { let controller: AbortController | null = new AbortController(); let result: FlowExecutionResult | null = null; const cleanup = () => { if (controller) { controller.abort(); controller = null; } }; // 解析SSE返回的数据 const parseSSEResponse = (eventData: string) => { try { const parsed = JSON.parse(eventData); // 处理聊天格式的数据: {"data":{"content":"...", "tokens": 123, "duration": 22986, "nodes": [...]}} if (parsed.data && parsed.data.content !== undefined) { return { type: 'chat_message', content: parsed.data.content, tokens: parsed.data.tokens, // 添加 tokens 字段 duration: parsed.data.duration, // 添加 duration 字段 nodes: parsed.data.nodes, // 添加 nodes 字段 isStreaming: true } as FlowExecutionEvent; } // 处理标准的FlowExecutionEvent格式 return parsed as FlowExecutionEvent; } catch (e) { return null; } }; const fetchOptions = { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}`, 'TENANT-ID': tenant, }, body: JSON.stringify(data), signal: controller.signal, async onopen(response: Response) { if (response.ok && response.headers.get('content-type')?.includes('text/event-stream')) { callbacks?.onStart?.(); return; } throw new Error(`Failed to connect: ${response.status} ${response.statusText}`); }, onmessage(event: { data: string }) { const parsed = parseSSEResponse(event.data); if (!parsed) return; switch (parsed.type) { case 'start': callbacks?.onStart?.(); break; case 'progress': callbacks?.onProgress?.(parsed); break; case 'chat_message': // 处理聊天消息流 if (parsed.content !== undefined) { // 检查是否收到完成标记 if (parsed.content === '[DONE]') { // 标记聊天消息完成并关闭连接,传递 tokens、duration 和 nodes 信息 callbacks?.onChatMessage?.('', true, parsed.tokens, parsed.duration, parsed.nodes); cleanup(); // 如果没有正式的结果,创建一个默认结果 if (!result) { result = { nodes: parsed.nodes || [], executed: true, result: {}, duration: parsed.duration || 0, totalTokens: parsed.tokens || 0 }; callbacks?.onComplete?.(result); resolve(result); } return; } callbacks?.onChatMessage?.(parsed.content, false, parsed.tokens, parsed.duration, parsed.nodes); } break; case 'complete': if (parsed.result) { result = parsed.result; callbacks?.onComplete?.(parsed.result); resolve(parsed.result); } break; case 'error': const errorMsg = parsed.error || 'Unknown error occurred'; callbacks?.onError?.(errorMsg); reject(new Error(errorMsg)); break; } }, onclose() { // 连接关闭时,如果有未完成的聊天消息,标记为完成 if (callbacks?.onChatMessage) { callbacks.onChatMessage('', true); } cleanup(); }, onerror(error: Error) { cleanup(); const errorMsg = error.message || 'Connection error'; callbacks?.onError?.(errorMsg); // 抛出错误以停止自动重试 throw error; }, }; // 启动SSE连接 fetchEventSource(`${request.defaults.baseURL}${other.adaptationUrl('/knowledge/aiFlow/execute')}`, fetchOptions) .catch((error) => { cleanup(); if (error.name === 'AbortError') { reject(new Error('Request was cancelled')); } else { reject(error); } }); // 返回清理函数以便外部可以取消请求 return cleanup; }); } /** * 取消SSE工作流执行 * @param executionId 执行ID */ export async function cancelFlowExecution(executionId: string) { return request.post(`/knowledge/aiFlow/cancel/${executionId}`); } /** * 专为聊天格式设计的SSE工作流执行函数 * 处理 {"data":{"content":"..."}} 格式的流式响应 * @param data 执行参数 * @param callbacks 回调函数 * @returns Promise<{chatMessage: string, result: any}> */ export async function executeFlowSSEWithChat( data: { id: string; conversationId: string; params: any; envs: any; stream?: boolean }, callbacks?: FlowExecutionCallbacks ): Promise<{chatMessage: string, result: any}> { const token = Session.getToken(); const tenant = Session.getTenant(); return new Promise<{chatMessage: string, result: any}>((resolve, reject) => { let controller: AbortController | null = new AbortController(); let chatMessageContent = ''; let hasReceivedData = false; const cleanup = () => { if (controller) { controller.abort(); controller = null; } }; const fetchOptions = { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}`, 'TENANT-ID': tenant, }, body: JSON.stringify(data), signal: controller.signal, async onopen(response: Response) { if (response.ok && response.headers.get('content-type')?.includes('text/event-stream')) { callbacks?.onStart?.(); return; } throw new Error(`Failed to connect: ${response.status} ${response.statusText}`); }, onmessage(event: { data: string }) { try { const parsed = JSON.parse(event.data); // 处理聊天格式的数据: {"data":{"content":"...", "tokens": 123, "duration": 22986}} if (parsed.data && parsed.data.content !== undefined) { hasReceivedData = true; // 检查是否收到完成标记 if (parsed.data.content === '[DONE]') { const result = { chatMessage: chatMessageContent, result: { nodes: parsed.data.nodes || [], executed: true, result: {}, duration: parsed.data.duration || 0, totalTokens: parsed.data.tokens || 0 } }; callbacks?.onChatMessage?.('', true, parsed.data.tokens, parsed.data.duration, parsed.data.nodes); // 标记聊天消息完成,传递 tokens、duration 和 nodes callbacks?.onComplete?.(result.result); cleanup(); resolve(result); return; } chatMessageContent += parsed.data.content; callbacks?.onChatMessage?.(parsed.data.content, false, parsed.data.tokens, parsed.data.duration, parsed.data.nodes); return; } // 处理其他类型的事件 if (parsed.type) { switch (parsed.type) { case 'start': callbacks?.onStart?.(); break; case 'progress': callbacks?.onProgress?.(parsed); break; case 'complete': const result = { chatMessage: chatMessageContent, result: parsed.result || {} }; callbacks?.onChatMessage?.('', true); // 标记聊天消息完成 callbacks?.onComplete?.(parsed.result); resolve(result); break; case 'error': const errorMsg = parsed.error || 'Unknown error occurred'; callbacks?.onError?.(errorMsg); reject(new Error(errorMsg)); break; } } } catch (e) { // 忽略无法解析的数据 } }, onclose() { // 连接关闭时,如果有数据但没有收到完成事件,自动完成 if (hasReceivedData) { const result = { chatMessage: chatMessageContent, result: {} }; callbacks?.onChatMessage?.('', true); resolve(result); } cleanup(); }, onerror(error: Error) { cleanup(); const errorMsg = error.message || 'Connection error'; callbacks?.onError?.(errorMsg); // 抛出错误以停止自动重试 throw error; }, }; // 启动SSE连接 fetchEventSource(`${request.defaults.baseURL}${other.adaptationUrl('/knowledge/aiFlow/execute')}`, fetchOptions) .catch((error) => { cleanup(); if (error.name === 'AbortError') { reject(new Error('Request was cancelled')); } else { reject(error); } }); }); }