Commit 3c520c23 authored by AI-甘富林's avatar AI-甘富林

ai对话流式输出修复

parent e6c277d6
...@@ -609,14 +609,18 @@ export const AdminAIAssistant: React.FC<AdminAIAssistantProps> = ({ ...@@ -609,14 +609,18 @@ export const AdminAIAssistant: React.FC<AdminAIAssistantProps> = ({
try { try {
const json = JSON.parse(trimmed.slice(6)); const json = JSON.parse(trimmed.slice(6));
if (json.type === 'content' && json.data) { if (json.type === 'text' && typeof json.content === 'string') {
onContent(json.content);
} else if (json.type === 'content' && json.data) {
// 兼容旧格式
onContent(json.data); onContent(json.data);
} else if (json.type === 'meta' && json.data) { } else if (json.type === 'meta' && json.data) {
onMeta?.(json.data); onMeta?.(json.data);
} else if (json.type === 'done') { } else if (json.type === 'done') {
onDone?.(json.data); // 新格式:done 帧直接包含所有字段
onDone?.(json);
} else if (json.type === 'error') { } else if (json.type === 'error') {
throw new Error(json.data); throw new Error(json.message || 'Stream error');
} }
} catch (e) { } catch (e) {
if (e instanceof SyntaxError) return; if (e instanceof SyntaxError) return;
...@@ -740,69 +744,60 @@ export const AdminAIAssistant: React.FC<AdminAIAssistantProps> = ({ ...@@ -740,69 +744,60 @@ export const AdminAIAssistant: React.FC<AdminAIAssistantProps> = ({
return; return;
} }
// Coze 模式:也通过统一的 coze-langchain 调用(非流式) // Coze 模式:流式调用 coze-langchain,实时显示文字 + 最终渲染 ui_schema
// 这样可以正确解析 JSON 响应,提取 answer 和 ui_schema console.log('[AdminAI] Using Coze mode (streaming unified API)');
console.log('[AdminAI] Using Coze mode (unified API)');
const { data: cozeData, error: cozeError } = await supabase.functions.invoke('coze-langchain', { let streamedAnswer = '';
body: { let streamedUISchema: any = null;
text: messageToSend, let streamedSessionId = '';
session_id: conversationId || undefined, let streamedAgentType: GenUIAgentType = 'manager';
},
});
if (cozeError) { await handleStreamResponse(
throw cozeError; 'coze-langchain',
} { text: messageToSend, session_id: conversationId || undefined },
// onContent: 增量文本到达时实时更新聊天框
// 健壮地解析响应 - 处理可能的字符串化 JSON (content) => {
let parsedData = cozeData; streamedAnswer += content;
if (typeof cozeData === 'string') { setMessages(prev => prev.map((msg, idx) =>
try { idx === prev.length - 1
// 如果返回的是字符串,尝试解析为 JSON ? { ...msg, content: streamedAnswer }
parsedData = JSON.parse(cozeData); : msg
console.log('[AdminAI] Parsed string response to JSON'); ));
} catch { },
// 如果解析失败,尝试从字符串中提取 answer // onMeta: 不使用
const answerMatch = cozeData.match(/"answer"\s*:\s*"([^"]+)"/); undefined,
parsedData = { // onDone: 流结束,拿到结构化数据
answer: answerMatch ? answerMatch[1] : cozeData, (doneData: any) => {
}; streamedAnswer = doneData.answer || streamedAnswer;
console.log('[AdminAI] Extracted answer from string response'); streamedUISchema = doneData.ui_schema || null;
} streamedSessionId = doneData.session_id || '';
streamedAgentType = (doneData.agent_type as GenUIAgentType) || 'manager';
} }
);
// 提取 answer 和 ui_schema // 最终更新消息内容
const cozeAnswer = parsedData?.answer || ''; setMessages(prev => prev.map((msg, idx) =>
const cozeUISchema = parsedData?.ui_schema; idx === prev.length - 1
const cozeAgentType = parsedData?.agent_type || 'manager'; ? { ...msg, content: streamedAnswer || '已更新工作台视图' }
: msg
));
console.log(`[AdminAI] Coze response - agent: ${cozeAgentType}, has ui_schema: ${!!cozeUISchema}, answer length: ${cozeAnswer.length}`); console.log(`[AdminAI] Stream complete - agent: ${streamedAgentType}, has ui_schema: ${!!streamedUISchema}, answer length: ${streamedAnswer.length}`);
// 自动导航到对应的工作台 Tab // 自动导航到对应的工作台 Tab
const targetTab = AGENT_TO_TAB_MAP[cozeAgentType as GenUIAgentType]; const targetTab = AGENT_TO_TAB_MAP[streamedAgentType];
if (targetTab && onNavigate) { if (targetTab && onNavigate) {
console.log(`[AdminAI] Auto-navigating to ${targetTab} for agent ${cozeAgentType}`); console.log(`[AdminAI] Auto-navigating to ${targetTab} for agent ${streamedAgentType}`);
onNavigate(targetTab); onNavigate(targetTab);
} }
// 推送 UI Schema 到对应的工作台 // 推送 UI Schema 到对应的工作台
if (cozeUISchema) { if (streamedUISchema) {
pushToWorkbench(cozeAgentType as GenUIAgentType, cozeUISchema as UISchema); pushToWorkbench(streamedAgentType, streamedUISchema as UISchema);
} }
// 更新助手消息 - 只显示文字回复 if (streamedSessionId) {
setMessages(prev => prev.map((msg, idx) => setConversationId(streamedSessionId);
idx === prev.length - 1
? {
...msg,
content: cozeAnswer || '已更新工作台视图',
}
: msg
));
if (parsedData?.session_id) {
setConversationId(parsedData.session_id);
} }
// 保存到数据库 // 保存到数据库
...@@ -810,13 +805,13 @@ export const AdminAIAssistant: React.FC<AdminAIAssistantProps> = ({ ...@@ -810,13 +805,13 @@ export const AdminAIAssistant: React.FC<AdminAIAssistantProps> = ({
await supabase.from('admin_chat_messages').insert([{ await supabase.from('admin_chat_messages').insert([{
user_id: user.id, user_id: user.id,
role: 'assistant', role: 'assistant',
content: cozeAnswer || '', content: streamedAnswer || '',
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),
}]); }]);
} }
// 显示使用的 Agent 信息 // 显示使用的 Agent 信息
toast.success(`${getAgentName(cozeAgentType as GenUIAgentType)} 已响应`, { toast.success(`${getAgentName(streamedAgentType)} 已响应`, {
duration: 2000, duration: 2000,
}); });
} catch (error) { } catch (error) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment