fix: AI 面板回复支持 Markdown 渲染

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
MikiVL 2026-05-05 03:15:09 +08:00
parent dff9f90bf2
commit bf66b269d4
3 changed files with 1155 additions and 5 deletions

1141
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -60,6 +60,7 @@
"pdfjs-dist": "^5.7.284", "pdfjs-dist": "^5.7.284",
"react": "^19.2.5", "react": "^19.2.5",
"react-dom": "^19.2.5", "react-dom": "^19.2.5",
"react-markdown": "^10.1.0",
"tailwind-merge": "^3.5.0", "tailwind-merge": "^3.5.0",
"zustand": "^5.0.12" "zustand": "^5.0.12"
}, },

View File

@ -1,5 +1,6 @@
import { useState, useRef, useEffect, useCallback } from 'react' import { useState, useRef, useEffect, useCallback } from 'react'
import { X, Send, Sparkles, Square, FileText, GripHorizontal } from 'lucide-react' import { X, Send, Sparkles, Square, FileText, GripHorizontal } from 'lucide-react'
import ReactMarkdown from 'react-markdown'
import { useAppStore } from '../../stores/appStore' import { useAppStore } from '../../stores/appStore'
import { streamAI } from '../../lib/ai' import { streamAI } from '../../lib/ai'
import { extractTextFromJSON } from '../../lib/utils' import { extractTextFromJSON } from '../../lib/utils'
@ -233,7 +234,7 @@ export function AiPanel() {
{messages.map((msg, i) => ( {messages.map((msg, i) => (
<div key={i} className={`flex ${msg.role === 'user' ? 'justify-end' : 'justify-start'}`}> <div key={i} className={`flex ${msg.role === 'user' ? 'justify-end' : 'justify-start'}`}>
<div <div
className="max-w-[85%] rounded-2xl px-3 py-2 text-sm leading-relaxed whitespace-pre-wrap break-words" className="max-w-[85%] rounded-2xl px-3 py-2 text-sm leading-relaxed break-words"
style={{ style={{
background: msg.role === 'user' ? 'var(--accent)' : 'var(--bg-muted)', background: msg.role === 'user' ? 'var(--accent)' : 'var(--bg-muted)',
color: msg.role === 'user' ? '#fff' : 'var(--text)', color: msg.role === 'user' ? '#fff' : 'var(--text)',
@ -241,7 +242,20 @@ export function AiPanel() {
borderBottomLeftRadius: msg.role === 'assistant' ? 4 : undefined, borderBottomLeftRadius: msg.role === 'assistant' ? 4 : undefined,
}} }}
> >
{msg.content} {msg.role === 'assistant' ? (
<div className="prose prose-sm max-w-none">
<ReactMarkdown
components={{
p: ({children}) => <p className="mb-1 last:mb-0">{children}</p>,
ul: ({children}) => <ul className="list-disc pl-4 mb-1">{children}</ul>,
ol: ({children}) => <ol className="list-decimal pl-4 mb-1">{children}</ol>,
li: ({children}) => <li className="mb-0.5">{children}</li>,
code: ({children}) => <code className="px-1 rounded text-xs" style={{background:'var(--bg-muted)'}}>{children}</code>,
strong: ({children}) => <strong style={{color:'var(--text)'}}>{children}</strong>,
}}
>{msg.content}</ReactMarkdown>
</div>
) : msg.content}
{streaming && i === messages.length - 1 && msg.role === 'assistant' && ( {streaming && i === messages.length - 1 && msg.role === 'assistant' && (
<span className="ai-cursor" /> <span className="ai-cursor" />
)} )}