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)');
let streamedAnswer = '';
const { data: cozeData, error: cozeError } = await supabase.functions.invoke('coze-langchain', { let streamedUISchema: any = null;
body: { let streamedSessionId = '';
text: messageToSend, let streamedAgentType: GenUIAgentType = 'manager';
session_id: conversationId || undefined,
await handleStreamResponse(
'coze-langchain',
{ text: messageToSend, session_id: conversationId || undefined },
// onContent: 增量文本到达时实时更新聊天框
(content) => {
streamedAnswer += content;
setMessages(prev => prev.map((msg, idx) =>
idx === prev.length - 1
? { ...msg, content: streamedAnswer }
: msg
));
}, },
}); // onMeta: 不使用
undefined,
if (cozeError) { // onDone: 流结束,拿到结构化数据
throw cozeError; (doneData: any) => {
} streamedAnswer = doneData.answer || streamedAnswer;
streamedUISchema = doneData.ui_schema || null;
// 健壮地解析响应 - 处理可能的字符串化 JSON streamedSessionId = doneData.session_id || '';
let parsedData = cozeData; streamedAgentType = (doneData.agent_type as GenUIAgentType) || 'manager';
if (typeof cozeData === 'string') {
try {
// 如果返回的是字符串,尝试解析为 JSON
parsedData = JSON.parse(cozeData);
console.log('[AdminAI] Parsed string response to JSON');
} catch {
// 如果解析失败,尝试从字符串中提取 answer
const answerMatch = cozeData.match(/"answer"\s*:\s*"([^"]+)"/);
parsedData = {
answer: answerMatch ? answerMatch[1] : cozeData,
};
console.log('[AdminAI] Extracted answer from string response');
} }
} );
// 提取 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