Files
school-developer/src/api/knowledge/aiFlow.ts
吴红兵 1f645dad3e init
2025-12-02 10:37:49 +08:00

575 lines
15 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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<any>; // 添加 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<any>) => 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<FlowExecutionResult>
*/
export async function executeFlowSSE(
data: { id: string; params: any; envs: any; stream?: boolean },
callbacks?: FlowExecutionCallbacks
): Promise<FlowExecutionResult> {
const token = Session.getToken();
const tenant = Session.getTenant();
return new Promise<FlowExecutionResult>((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);
}
});
});
}