Merge pull request #68 from JefferyHcool/ui/markdown_perf

feat(MarkdownViewer):增强 Markdown 解析和渲染能力
This commit is contained in:
Jianwu Huang
2025-05-03 02:25:54 +08:00
committed by GitHub
4 changed files with 93 additions and 11 deletions

View File

@@ -30,19 +30,23 @@
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"github-markdown-css": "^5.8.1",
"katex": "^0.16.21",
"katex": "^0.16.22",
"lottie-react": "^2.4.1",
"lucide-react": "^0.487.0",
"markdown-navbar": "^1.4.3",
"next-themes": "^0.4.6",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react-hook-form": "^7.55.0",
"react-hot-toast": "^2.5.2",
"react-markdown": "^10.1.0",
"react-markdown": "^8.0.7",
"react-medium-image-zoom": "^5.2.14",
"react-resizable-panels": "^2.1.8",
"react-router-dom": "^7.5.1",
"react-syntax-highlighter": "^15.6.1",
"remark-gfm": "1.0.0",
"rehype-katex": "^6.0.2",
"remark-gfm": "3.0.1",
"remark-math": "^5.1.1",
"sonner": "^2.0.3",
"tailwind-merge": "^3.1.0",
"tailwindcss": "^4.1.3",

View File

@@ -2,16 +2,27 @@ import { useState } from 'react'
import ReactMarkdown from 'react-markdown'
import { Button } from '@/components/ui/button.tsx'
import { Copy, Download, FileText, ArrowRight } from 'lucide-react'
import { toast } from 'sonner' // 你可以换成自己的通知组件
import { toast } from 'react-hot-toast' // 你可以换成自己的通知组件
import Error from '@/components/Lottie/error.tsx'
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'
import { solarizedlight as codeStyle } from 'react-syntax-highlighter/dist/cjs/styles/prism'
import { atomDark as codeStyle } from 'react-syntax-highlighter/dist/esm/styles/prism'
import Zoom from 'react-medium-image-zoom'
import 'react-medium-image-zoom/dist/styles.css'
import 'github-markdown-css/github-markdown-light.css'
import { FC } from 'react'
import Loading from '@/components/Lottie/Loading.tsx'
import Idle from '@/components/Lottie/Idle.tsx'
import { useTaskStore } from '@/store/taskStore'
import StepBar from '@/pages/HomePage/components/StepBar.tsx'
import gfm from 'remark-gfm'
import remarkMath from 'remark-math'
import 'katex/dist/katex.min.css'
import rehypeKatex from 'rehype-katex'
import 'katex/dist/katex.min.css'
interface MarkdownViewerProps {
content: string
status: 'idle' | 'loading' | 'success' | 'failed'
@@ -31,6 +42,8 @@ const MarkdownViewer: FC<MarkdownViewerProps> = ({ content, status }) => {
const currentTask = useTaskStore(state => state.getCurrentTask())
const taskStatus = currentTask?.status || 'PENDING'
const retryTask = useTaskStore.getState().retryTask
let firstHeadingRendered = false
const handleCopy = async () => {
try {
await navigator.clipboard.writeText(content)
@@ -124,7 +137,58 @@ const MarkdownViewer: FC<MarkdownViewerProps> = ({ content, status }) => {
<div className="markdown-body flex-1 bg-white">
{' '}
<ReactMarkdown
remarkPlugins={[gfm,remarkMath]}
rehypePlugins={[rehypeKatex]}
components={{
img: ({ node, ...props }) => (
<Zoom>
<img
{...props}
className="rounded-lg shadow-md max-w-full cursor-pointer mx-auto my-4 max-h-[300px] "
alt={props.alt || ''}
/>
</Zoom>
),
strong({ node, children, ...props }){
return <strong className="text-lg font-bold my-4 text-blue-600" {...props}>{children}</strong>
},
li({ node, children, ...props }) {
const rawText = String(children)
// 检测是否是“加粗的编号开头项”,比如 "**2. 算法摄影的兴起**"
const isFakeHeading = /^(\*\*.+\*\*)$/.test(rawText.trim())
if (isFakeHeading) {
return (
<p className="text-lg font-bold my-4 text-gray-800 text-left">
{children}
</p>
)
}
return <li {...props}>{children}</li>
},
h1({ node, children, ...props }) {
return (
<h1
className="text-3xl text-center font-bold my-6 text-blue-600"
{...props}
>
{children}
</h1>
)
},
h2({ node, children, ...props }) {
return (
<h2
className="text-2xl font-bold my-4 text-blue-600"
{...props}
>
{children}
</h2>
)
},
code({ node, inline, className, children, ...props }) {
const match = /language-(\w+)/.exec(className || '')
const codeContent = String(children).replace(/\n$/, '')
@@ -133,15 +197,17 @@ const MarkdownViewer: FC<MarkdownViewerProps> = ({ content, status }) => {
return (
<div className="group relative">
<SyntaxHighlighter
style={codeStyle}
language={match[1]}
PreTag="div"
{...props}
style={codeStyle}
language={match[1]}
PreTag="div"
{...props}
>
{codeContent}
</SyntaxHighlighter>
<button
onClick={() => {
console.log('点击负责')
navigator.clipboard.writeText(codeContent)
toast.success('代码已复制')
}}

View File

@@ -16,6 +16,14 @@ BASE_PROMPT = '''
输出说明:
- 仅返回最终的 **Markdown 内容**。
- **不要**将输出包裹在代码块中(例如:```` ```markdown ```````` ``` ````)。
请注意,在生成 Markdown 时避免将编号标题如“1. **内容**”)写成有序列表的格式,以免解析错误。
- 如果要加粗并保留编号,应使用 `1\. **内容**`(加反斜杠),防止被误解析为有序列表。
- 或者使用 `## 1. 内容` 的形式作为标题。
请确保以下格式 **不会出现误渲染**
❌ `1. **xxx**`
✅ `1\. **xxx**` 或 `## 1. xxx`
视频分段(格式:开始时间 - 内容):
@@ -27,10 +35,14 @@ BASE_PROMPT = '''
根据上面的分段转录内容,生成结构化的笔记,遵循以下原则:
1. **完整信息**:记录尽可能多的相关细节,确保内容全面。
2. **清晰结构**:用合适的标题级别(`##``###`)整理内容,概述每个部分的要点。(如果额外重要的任务有格式需求可以不遵守)
2. **清晰结构**:用合适的标题级别(`##``###`)整理内容,概述每个部分的要点。主标题用`#`来标识(如果额外重要的任务有格式需求可以不遵守)
3. **去除无关内容**:省略广告、填充词、问候语和不相关的言论。
4. **保留关键细节**:保留重要事实、示例、结论和建议。(如果额外重要的任务有格式需求可以不遵守)
5. **可读布局**:必要时使用项目符号,并保持段落简短,增强可读性。(如果额外重要的任务有格式需求可以不遵守)
6. 视频中提及的数学公式必须保留,并以 LaTeX 语法形式呈现,适合 Markdown 渲染。
请始终遵循此规则。
额外重要的任务如下(每一个都必须严格完成):

View File

@@ -42,7 +42,7 @@ class VideoRequest(BaseModel):
task_id: Optional[str] = None
format: Optional[list] = []
style: str = None
extras: Optional[str]
extras: Optional[str]=None
video_understanding: Optional[bool] = False
video_interval: Optional[int] = 0
grid_size: Optional[list] = []