对话、重新生成、评价完成
This commit is contained in:
@@ -9,7 +9,6 @@ import type {
|
||||
AiConversation,
|
||||
AiMessage,
|
||||
ChatRequest,
|
||||
ChatResponse,
|
||||
ResultDomain,
|
||||
StreamCallback
|
||||
} from '@/types';
|
||||
@@ -19,43 +18,102 @@ import type {
|
||||
*/
|
||||
export const chatApi = {
|
||||
/**
|
||||
* 流式对话(SSE)
|
||||
* 流式对话(SSE)- 使用fetch支持Authorization
|
||||
* @param request 对话请求
|
||||
* @param callback 流式回调
|
||||
* @returns Promise<ResultDomain<AiMessage>>
|
||||
*/
|
||||
async streamChat(request: ChatRequest, callback?: StreamCallback): Promise<ResultDomain<AiMessage>> {
|
||||
const token = localStorage.getItem('token');
|
||||
const tokenData = token ? JSON.parse(token) : null;
|
||||
return new Promise((resolve, reject) => {
|
||||
// 使用相对路径走Vite代理,避免跨域
|
||||
const eventSource = new EventSource(
|
||||
`${api.defaults.baseURL}/ai/chat/stream?` +
|
||||
`/api/ai/chat/stream?` +
|
||||
new URLSearchParams({
|
||||
agentId: request.agentId,
|
||||
conversationId: request.conversationId || '',
|
||||
query: request.query,
|
||||
knowledgeIds: request.knowledgeIds?.join(',') || ''
|
||||
knowledgeIds: request.knowledgeIds?.join(',') || '',
|
||||
token: tokenData?.value || ''
|
||||
})
|
||||
);
|
||||
|
||||
let fullMessage = '';
|
||||
// 通知外部EventSource已创建
|
||||
callback?.onStart?.(eventSource);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
let fullMessage = ''; // 累积完整消息内容
|
||||
|
||||
// 监听初始化事件(包含messageId和conversationId)
|
||||
eventSource.addEventListener('init', (event) => {
|
||||
try {
|
||||
const initData = JSON.parse(event.data);
|
||||
console.log('[初始化数据]', initData);
|
||||
// 通知外部保存messageId(用于停止生成)
|
||||
if (callback?.onInit) {
|
||||
callback.onInit(initData);
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('解析init事件失败:', event.data);
|
||||
}
|
||||
});
|
||||
|
||||
// 监听标准消息事件
|
||||
eventSource.addEventListener('message', (event) => {
|
||||
const data = event.data;
|
||||
fullMessage += data;
|
||||
callback?.onMessage?.(data);
|
||||
});
|
||||
|
||||
// 监听结束事件
|
||||
eventSource.addEventListener('end', (event) => {
|
||||
const metadata = JSON.parse(event.data);
|
||||
callback?.onMessageEnd?.(metadata);
|
||||
eventSource.close();
|
||||
|
||||
resolve({
|
||||
code: 200,
|
||||
success: true,
|
||||
login: true,
|
||||
auth: true,
|
||||
data: metadata as AiMessage,
|
||||
message: '对话成功'
|
||||
});
|
||||
});
|
||||
|
||||
// 监听所有Dify原始事件(workflow_started, node_started等)
|
||||
const difyEventTypes = [
|
||||
'dify_workflow_started',
|
||||
'dify_node_started',
|
||||
'dify_node_finished',
|
||||
'dify_workflow_finished',
|
||||
'dify_message',
|
||||
'dify_agent_message',
|
||||
'dify_message_end',
|
||||
'dify_message_file',
|
||||
'dify_agent_thought',
|
||||
'dify_ping'
|
||||
];
|
||||
|
||||
difyEventTypes.forEach(eventType => {
|
||||
eventSource.addEventListener(eventType, (event: any) => {
|
||||
try {
|
||||
const eventData = JSON.parse(event.data);
|
||||
console.log(`[Dify事件] ${eventType}:`, eventData);
|
||||
|
||||
// 调用自定义的Dify事件回调
|
||||
if (callback?.onDifyEvent) {
|
||||
const cleanEventType = eventType.replace('dify_', '');
|
||||
callback.onDifyEvent(cleanEventType, eventData);
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn(`解析Dify事件失败 ${eventType}:`, event.data);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 监听错误事件
|
||||
eventSource.addEventListener('error', (event: any) => {
|
||||
const error = new Error(event.data || '对话失败');
|
||||
callback?.onError?.(error);
|
||||
@@ -64,7 +122,7 @@ export const chatApi = {
|
||||
});
|
||||
|
||||
eventSource.onerror = (error) => {
|
||||
callback?.onError?.(error as Error);
|
||||
callback?.onError?.(error as unknown as Error);
|
||||
eventSource.close();
|
||||
reject(error);
|
||||
};
|
||||
@@ -82,7 +140,7 @@ export const chatApi = {
|
||||
},
|
||||
|
||||
/**
|
||||
* 停止对话生成
|
||||
* 停止对话生成(通过消息ID)
|
||||
* @param messageId 消息ID
|
||||
* @returns Promise<ResultDomain<boolean>>
|
||||
*/
|
||||
@@ -91,6 +149,20 @@ export const chatApi = {
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/**
|
||||
* 停止对话生成(通过Dify TaskID)
|
||||
* @param taskId Dify任务ID
|
||||
* @param agentId 智能体ID
|
||||
* @returns Promise<ResultDomain<boolean>>
|
||||
*/
|
||||
async stopChatByTaskId(taskId: string, agentId: string): Promise<ResultDomain<boolean>> {
|
||||
const response = await api.post<boolean>('/ai/chat/stop-by-taskid', {
|
||||
taskId,
|
||||
agentId
|
||||
});
|
||||
return response.data;
|
||||
},
|
||||
|
||||
/**
|
||||
* 创建新会话
|
||||
* @param agentId 智能体ID
|
||||
@@ -152,8 +224,8 @@ export const chatApi = {
|
||||
* @param conversationId 会话ID
|
||||
* @returns Promise<ResultDomain<AiMessage[]>>
|
||||
*/
|
||||
async listMessages(conversationId: string): Promise<ResultDomain<AiMessage[]>> {
|
||||
const response = await api.get<AiMessage[]>(`/ai/chat/conversation/${conversationId}/messages`);
|
||||
async listMessages(conversationId: string): Promise<ResultDomain<AiMessage>> {
|
||||
const response = await api.get<AiMessage>(`/ai/chat/conversation/${conversationId}/messages`);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
@@ -168,46 +240,112 @@ export const chatApi = {
|
||||
},
|
||||
|
||||
/**
|
||||
* 重新生成回答
|
||||
* 重新生成回答(SSE流式)
|
||||
* @param messageId 原消息ID
|
||||
* @param callback 流式回调(可选)
|
||||
* @param callback 流式回调
|
||||
* @returns Promise<ResultDomain<AiMessage>>
|
||||
*/
|
||||
async regenerateAnswer(messageId: string, callback?: StreamCallback): Promise<ResultDomain<AiMessage>> {
|
||||
if (callback) {
|
||||
// 使用流式方式重新生成
|
||||
return new Promise((resolve, reject) => {
|
||||
const eventSource = new EventSource(
|
||||
`${api.defaults.baseURL}/ai/chat/regenerate/${messageId}?stream=true`
|
||||
);
|
||||
const token = localStorage.getItem('token');
|
||||
const tokenData = token ? JSON.parse(token) : null;
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
// 使用相对路径走Vite代理,SSE流式推送
|
||||
const eventSource = new EventSource(
|
||||
`/api/ai/chat/regenerate/${messageId}?` +
|
||||
new URLSearchParams({
|
||||
token: tokenData?.value || ''
|
||||
})
|
||||
);
|
||||
|
||||
eventSource.addEventListener('message', (event) => {
|
||||
callback.onMessage?.(event.data);
|
||||
});
|
||||
// 通知外部EventSource已创建
|
||||
callback?.onStart?.(eventSource);
|
||||
|
||||
eventSource.addEventListener('end', (event) => {
|
||||
const metadata = JSON.parse(event.data);
|
||||
callback.onMessageEnd?.(metadata);
|
||||
eventSource.close();
|
||||
resolve({
|
||||
success: true,
|
||||
data: metadata as AiMessage,
|
||||
message: '重新生成成功'
|
||||
});
|
||||
});
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
let fullMessage = ''; // 累积完整消息内容
|
||||
|
||||
eventSource.addEventListener('error', (event: any) => {
|
||||
const error = new Error(event.data || '重新生成失败');
|
||||
callback.onError?.(error);
|
||||
eventSource.close();
|
||||
reject(error);
|
||||
// 监听初始化事件(包含messageId和conversationId)
|
||||
eventSource.addEventListener('init', (event) => {
|
||||
try {
|
||||
const initData = JSON.parse(event.data);
|
||||
console.log('[初始化数据-重新生成]', initData);
|
||||
// 通知外部保存messageId(用于停止生成)
|
||||
if (callback?.onInit) {
|
||||
callback.onInit(initData);
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('解析init事件失败:', event.data);
|
||||
}
|
||||
});
|
||||
|
||||
// 监听标准消息事件
|
||||
eventSource.addEventListener('message', (event) => {
|
||||
const data = event.data;
|
||||
fullMessage += data;
|
||||
callback?.onMessage?.(data);
|
||||
});
|
||||
|
||||
// 监听结束事件
|
||||
eventSource.addEventListener('end', (event) => {
|
||||
const metadata = JSON.parse(event.data);
|
||||
callback?.onMessageEnd?.(metadata);
|
||||
eventSource.close();
|
||||
|
||||
resolve({
|
||||
code: 200,
|
||||
success: true,
|
||||
login: true,
|
||||
auth: true,
|
||||
data: metadata as AiMessage,
|
||||
message: '重新生成成功'
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// 使用阻塞方式重新生成
|
||||
const response = await api.post<AiMessage>(`/ai/chat/regenerate/${messageId}`);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
// 监听所有Dify原始事件(workflow_started, node_started等)
|
||||
const difyEventTypes = [
|
||||
'dify_workflow_started',
|
||||
'dify_node_started',
|
||||
'dify_node_finished',
|
||||
'dify_workflow_finished',
|
||||
'dify_message',
|
||||
'dify_agent_message',
|
||||
'dify_message_end',
|
||||
'dify_message_file',
|
||||
'dify_agent_thought',
|
||||
'dify_ping'
|
||||
];
|
||||
|
||||
difyEventTypes.forEach(eventType => {
|
||||
eventSource.addEventListener(eventType, (event: any) => {
|
||||
try {
|
||||
const eventData = JSON.parse(event.data);
|
||||
console.log(`[Dify事件] ${eventType}:`, eventData);
|
||||
|
||||
// 调用自定义的Dify事件回调
|
||||
if (callback?.onDifyEvent) {
|
||||
const cleanEventType = eventType.replace('dify_', '');
|
||||
callback.onDifyEvent(cleanEventType, eventData);
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn(`解析Dify事件失败 ${eventType}:`, event.data);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 监听错误事件
|
||||
eventSource.addEventListener('error', (event: any) => {
|
||||
const error = new Error(event.data || '重新生成失败');
|
||||
callback?.onError?.(error);
|
||||
eventSource.close();
|
||||
reject(error);
|
||||
});
|
||||
|
||||
eventSource.onerror = (error) => {
|
||||
callback?.onError?.(error as unknown as Error);
|
||||
eventSource.close();
|
||||
reject(error);
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user