This commit is contained in:
吴红兵
2025-12-02 10:37:49 +08:00
commit 1f645dad3e
1183 changed files with 147673 additions and 0 deletions

575
src/api/knowledge/aiFlow.ts Normal file
View File

@@ -0,0 +1,575 @@
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);
}
});
});
}