init
This commit is contained in:
575
src/api/knowledge/aiFlow.ts
Normal file
575
src/api/knowledge/aiFlow.ts
Normal 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);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user