Commit 0c7e7655 authored by AI-甘富林's avatar AI-甘富林

ai对话流式输出修复

parent f5f3d637
...@@ -26,6 +26,8 @@ import { routeAndCallGenUI, getAgentName, type GenUIAgentType } from '@/services ...@@ -26,6 +26,8 @@ import { routeAndCallGenUI, getAgentName, type GenUIAgentType } from '@/services
import { pushToWorkbench, AGENT_TO_TAB_MAP } from '@/services/workbenchEventBus'; import { pushToWorkbench, AGENT_TO_TAB_MAP } from '@/services/workbenchEventBus';
import { Switch } from '@/components/ui/switch'; import { Switch } from '@/components/ui/switch';
import { Label } from '@/components/ui/label'; import { Label } from '@/components/ui/label';
import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
interface Message { interface Message {
role: 'user' | 'assistant'; role: 'user' | 'assistant';
...@@ -55,6 +57,21 @@ export interface PageState { ...@@ -55,6 +57,21 @@ export interface PageState {
highlightIds?: string[]; highlightIds?: string[];
} }
/** 消息体 Markdown 渲染 — 代码块、表格、列表等格式 */
function MarkdownRenderer({ content, isUser }: { content: string; isUser?: boolean }) {
return (
<div className={cn(
"text-sm break-words overflow-wrap-anywhere",
// 助手消息启用 prose 排版样式,用户消息保持简洁
!isUser && "prose prose-sm dark:prose-invert max-w-none"
)}>
<ReactMarkdown remarkPlugins={[remarkGfm]}>
{content}
</ReactMarkdown>
</div>
);
}
// 创建一个简单的事件总线用于页面状态通信 // 创建一个简单的事件总线用于页面状态通信
const pageStateListeners: Set<(state: PageState & { tab?: string }) => void> = new Set(); const pageStateListeners: Set<(state: PageState & { tab?: string }) => void> = new Set();
...@@ -768,7 +785,8 @@ export const AdminAIAssistant: React.FC<AdminAIAssistantProps> = ({ ...@@ -768,7 +785,8 @@ export const AdminAIAssistant: React.FC<AdminAIAssistantProps> = ({
undefined, undefined,
// onDone: 流结束,拿到结构化数据 // onDone: 流结束,拿到结构化数据
(doneData: any) => { (doneData: any) => {
streamedAnswer = doneData.answer || streamedAnswer; // 优先使用流式累积的完整文本(含代码块),doneData.answer 可能被 parseAIResponse 截断
streamedAnswer = streamedAnswer || doneData.answer;
streamedUISchema = doneData.ui_schema || null; streamedUISchema = doneData.ui_schema || null;
streamedSessionId = doneData.session_id || ''; streamedSessionId = doneData.session_id || '';
streamedAgentType = (doneData.agent_type as GenUIAgentType) || 'manager'; streamedAgentType = (doneData.agent_type as GenUIAgentType) || 'manager';
...@@ -1313,7 +1331,7 @@ export const AdminAIAssistant: React.FC<AdminAIAssistantProps> = ({ ...@@ -1313,7 +1331,7 @@ export const AdminAIAssistant: React.FC<AdminAIAssistantProps> = ({
: 'max-w-[85%] bg-muted/60 text-foreground border border-border/40' : 'max-w-[85%] bg-muted/60 text-foreground border border-border/40'
)} )}
> >
<p className="text-sm whitespace-pre-wrap break-words overflow-wrap-anywhere">{msg.content}</p> <MarkdownRenderer content={msg.content} isUser={msg.role === 'user'} />
{msg.ui_schema && msg.role === 'assistant' && ( {msg.ui_schema && msg.role === 'assistant' && (
<div className="mt-2 pt-2 border-t border-border/50"> <div className="mt-2 pt-2 border-t border-border/50">
...@@ -1485,7 +1503,7 @@ export const AdminAIAssistant: React.FC<AdminAIAssistantProps> = ({ ...@@ -1485,7 +1503,7 @@ export const AdminAIAssistant: React.FC<AdminAIAssistantProps> = ({
: 'max-w-[85%] bg-muted/60 text-foreground border border-border/40' : 'max-w-[85%] bg-muted/60 text-foreground border border-border/40'
)} )}
> >
<p className="text-sm whitespace-pre-wrap break-words overflow-wrap-anywhere">{msg.content}</p> <MarkdownRenderer content={msg.content} isUser={msg.role === 'user'} />
{msg.actions && msg.actions.length > 0 && ( {msg.actions && msg.actions.length > 0 && (
<div className="mt-2 pt-2 border-t border-border/50"> <div className="mt-2 pt-2 border-t border-border/50">
...@@ -1680,7 +1698,7 @@ export const AdminAIAssistant: React.FC<AdminAIAssistantProps> = ({ ...@@ -1680,7 +1698,7 @@ export const AdminAIAssistant: React.FC<AdminAIAssistantProps> = ({
: 'max-w-[85%] bg-muted/60 text-foreground border border-border/40' : 'max-w-[85%] bg-muted/60 text-foreground border border-border/40'
)} )}
> >
<p className="text-sm whitespace-pre-wrap break-words overflow-wrap-anywhere">{msg.content}</p> <MarkdownRenderer content={msg.content} isUser={msg.role === 'user'} />
{/* Gen UI Dynamic Rendering */} {/* Gen UI Dynamic Rendering */}
{msg.ui_schema && msg.role === 'assistant' && ( {msg.ui_schema && msg.role === 'assistant' && (
...@@ -1919,7 +1937,7 @@ export const AdminAIAssistant: React.FC<AdminAIAssistantProps> = ({ ...@@ -1919,7 +1937,7 @@ export const AdminAIAssistant: React.FC<AdminAIAssistantProps> = ({
: 'max-w-[85%] bg-muted/60 text-foreground border border-border/40' : 'max-w-[85%] bg-muted/60 text-foreground border border-border/40'
)} )}
> >
<p className="text-sm whitespace-pre-wrap break-words overflow-wrap-anywhere">{msg.content}</p> <MarkdownRenderer content={msg.content} isUser={msg.role === 'user'} />
{/* Gen UI Dynamic Rendering */} {/* Gen UI Dynamic Rendering */}
{msg.ui_schema && msg.role === 'assistant' && ( {msg.ui_schema && msg.role === 'assistant' && (
......
...@@ -154,5 +154,5 @@ export default { ...@@ -154,5 +154,5 @@ export default {
}, },
}, },
}, },
plugins: [require("tailwindcss-animate")], plugins: [require("tailwindcss-animate"), require("@tailwindcss/typography")],
} satisfies Config; } satisfies Config;
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