fix: markdown render
This commit is contained in:
parent
98254ddc09
commit
31d97834dc
|
|
@ -73,6 +73,19 @@ export const EnhancedChatMessageV2: React.FC<EnhancedChatMessageV2Props> = ({
|
|||
const groundingMetadata = message.metadata?.grounding_metadata;
|
||||
const sources = message.metadata?.sources || [];
|
||||
|
||||
// 调试信息
|
||||
console.log('🔍 EnhancedChatMessageV2 Debug:', {
|
||||
messageId: message.id,
|
||||
messageType: message.type,
|
||||
contentLength: message.content.length,
|
||||
hasMetadata: !!message.metadata,
|
||||
hasGroundingMetadata: !!groundingMetadata,
|
||||
groundingSupportsCount: groundingMetadata?.grounding_supports?.length || 0,
|
||||
sourcesCount: sources.length,
|
||||
enableReferences,
|
||||
groundingMetadata
|
||||
});
|
||||
|
||||
// 复制消息内容
|
||||
const handleCopy = useCallback(async () => {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -1,20 +1,7 @@
|
|||
import React, { useMemo, useState } from 'react';
|
||||
import React from 'react';
|
||||
import ReactMarkdown from 'react-markdown';
|
||||
import remarkGfm from 'remark-gfm';
|
||||
import { GroundingMetadata, GroundingSupport, GroundingSource } from '../types/ragGrounding';
|
||||
import { ReferenceFootnote } from './ReferenceFootnote';
|
||||
|
||||
/**
|
||||
* 文本片段与引用信息
|
||||
*/
|
||||
interface TextSegmentWithReference {
|
||||
text: string;
|
||||
startIndex: number;
|
||||
endIndex: number;
|
||||
groundingSupport?: GroundingSupport;
|
||||
sources?: GroundingSource[];
|
||||
referenceIndex?: number;
|
||||
}
|
||||
import { GroundingMetadata } from '../types/ragGrounding';
|
||||
|
||||
/**
|
||||
* 增强Markdown渲染器属性接口
|
||||
|
|
@ -30,108 +17,39 @@ interface EnhancedMarkdownRendererProps {
|
|||
enableMarkdown?: boolean;
|
||||
/** 自定义样式类名 */
|
||||
className?: string;
|
||||
/** 引用点击回调 */
|
||||
onReferenceClick?: (sources: GroundingSource[], index: number) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* 增强Markdown渲染器组件
|
||||
* 支持角标引用和grounding高亮
|
||||
* 暂时简化版本,专注于正确渲染Markdown内容
|
||||
*/
|
||||
export const EnhancedMarkdownRenderer: React.FC<EnhancedMarkdownRendererProps> = ({
|
||||
content,
|
||||
groundingMetadata,
|
||||
enableReferences = true,
|
||||
enableMarkdown = true,
|
||||
className = '',
|
||||
onReferenceClick
|
||||
className = ''
|
||||
}) => {
|
||||
const [selectedReference, setSelectedReference] = useState<number | null>(null);
|
||||
|
||||
// 解析文本片段和引用信息
|
||||
const textSegments = useMemo(() => {
|
||||
if (!groundingMetadata?.grounding_supports?.length) {
|
||||
return [{ text: content, startIndex: 0, endIndex: content.length }];
|
||||
}
|
||||
|
||||
const segments: TextSegmentWithReference[] = [];
|
||||
const supports = [...groundingMetadata.grounding_supports].sort(
|
||||
(a, b) => a.start_index - b.start_index
|
||||
);
|
||||
|
||||
let currentIndex = 0;
|
||||
let referenceCounter = 1;
|
||||
|
||||
supports.forEach((support) => {
|
||||
// 添加支持前的文本
|
||||
if (currentIndex < support.start_index) {
|
||||
segments.push({
|
||||
text: content.slice(currentIndex, support.start_index),
|
||||
startIndex: currentIndex,
|
||||
endIndex: support.start_index
|
||||
});
|
||||
}
|
||||
|
||||
// 获取相关来源
|
||||
const sources = groundingMetadata.sources?.filter(source =>
|
||||
support.grounding_chunk_indices?.includes(source.chunk_index || 0)
|
||||
) || [];
|
||||
|
||||
// 添加支持的文本片段
|
||||
segments.push({
|
||||
text: content.slice(support.start_index, support.end_index),
|
||||
startIndex: support.start_index,
|
||||
endIndex: support.end_index,
|
||||
groundingSupport: support,
|
||||
sources,
|
||||
referenceIndex: sources.length > 0 ? referenceCounter++ : undefined
|
||||
});
|
||||
|
||||
currentIndex = support.end_index;
|
||||
});
|
||||
|
||||
// 添加剩余文本
|
||||
if (currentIndex < content.length) {
|
||||
segments.push({
|
||||
text: content.slice(currentIndex),
|
||||
startIndex: currentIndex,
|
||||
endIndex: content.length
|
||||
});
|
||||
}
|
||||
|
||||
return segments;
|
||||
}, [content, groundingMetadata]);
|
||||
|
||||
// 处理引用点击
|
||||
const handleReferenceClick = (sources: GroundingSource[], index: number) => {
|
||||
setSelectedReference(selectedReference === index ? null : index);
|
||||
onReferenceClick?.(sources, index);
|
||||
};
|
||||
|
||||
// 渲染文本片段
|
||||
const renderSegment = (segment: TextSegmentWithReference, index: number) => {
|
||||
const hasReference = segment.referenceIndex && segment.sources?.length;
|
||||
const isHighlighted = hasReference && selectedReference === segment.referenceIndex;
|
||||
// 调试信息
|
||||
console.log('📝 EnhancedMarkdownRenderer Debug:', {content, groundingMetadata});
|
||||
|
||||
// 暂时禁用角标功能,直接渲染Markdown以避免重复渲染问题
|
||||
// TODO: 未来需要实现更复杂的Markdown + 角标集成方案
|
||||
return (
|
||||
<span
|
||||
key={index}
|
||||
className={`
|
||||
${hasReference ? 'relative text-highlight' : ''}
|
||||
${isHighlighted ? 'bg-blue-100 rounded px-1' : ''}
|
||||
`}
|
||||
>
|
||||
<div className={`enhanced-markdown-renderer ${className}`}>
|
||||
{enableMarkdown ? (
|
||||
<div className="prose prose-sm max-w-none leading-relaxed">
|
||||
<ReactMarkdown
|
||||
remarkPlugins={[remarkGfm]}
|
||||
components={{
|
||||
p: ({ children }) => <>{children}</>,
|
||||
h1: ({ children }) => <strong className="text-lg font-bold">{children}</strong>,
|
||||
h2: ({ children }) => <strong className="text-base font-semibold">{children}</strong>,
|
||||
h3: ({ children }) => <strong className="font-medium">{children}</strong>,
|
||||
ul: ({ children }) => <div className="ml-4">{children}</div>,
|
||||
ol: ({ children }) => <div className="ml-4">{children}</div>,
|
||||
li: ({ children }) => <div className="flex items-start"><span className="mr-2">•</span><span>{children}</span></div>,
|
||||
p: ({ children }) => <p className="mb-2">{children}</p>,
|
||||
h1: ({ children }) => <h1 className="text-lg font-bold mb-2">{children}</h1>,
|
||||
h2: ({ children }) => <h2 className="text-base font-semibold mb-2">{children}</h2>,
|
||||
h3: ({ children }) => <h3 className="font-medium mb-1">{children}</h3>,
|
||||
ul: ({ children }) => <ul className="list-disc ml-4 mb-2">{children}</ul>,
|
||||
ol: ({ children }) => <ol className="list-decimal ml-4 mb-2">{children}</ol>,
|
||||
li: ({ children }) => <li className="mb-1">{children}</li>,
|
||||
strong: ({ children }) => <strong>{children}</strong>,
|
||||
em: ({ children }) => <em>{children}</em>,
|
||||
code: ({ children }) => (
|
||||
|
|
@ -140,36 +58,43 @@ export const EnhancedMarkdownRenderer: React.FC<EnhancedMarkdownRendererProps> =
|
|||
</code>
|
||||
),
|
||||
blockquote: ({ children }) => (
|
||||
<blockquote className="border-l-4 border-gray-300 pl-4 italic text-gray-600">
|
||||
<blockquote className="border-l-4 border-gray-300 pl-4 italic text-gray-600 mb-2">
|
||||
{children}
|
||||
</blockquote>
|
||||
),
|
||||
}}
|
||||
>
|
||||
{segment.text}
|
||||
{content}
|
||||
</ReactMarkdown>
|
||||
) : (
|
||||
segment.text
|
||||
)}
|
||||
|
||||
{/* 角标引用 */}
|
||||
{enableReferences && hasReference && (
|
||||
<ReferenceFootnote
|
||||
index={segment.referenceIndex!}
|
||||
sources={segment.sources!}
|
||||
className="ml-1 align-super"
|
||||
onClick={(sources) => handleReferenceClick(sources, segment.referenceIndex!)}
|
||||
/>
|
||||
)}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`enhanced-markdown-renderer ${className}`}>
|
||||
<div className="prose prose-sm max-w-none leading-relaxed">
|
||||
{textSegments.map(renderSegment)}
|
||||
</div>
|
||||
) : (
|
||||
<div className="leading-relaxed whitespace-pre-wrap">{content}</div>
|
||||
)}
|
||||
|
||||
{/* 显示引用来源信息(如果有的话) */}
|
||||
{enableReferences && groundingMetadata?.sources && groundingMetadata.sources.length > 0 && (
|
||||
<div className="mt-4 pt-3 border-t border-gray-200">
|
||||
<div className="text-xs text-gray-500 mb-2">
|
||||
基于 {groundingMetadata.sources.length} 个来源的信息
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-1">
|
||||
{groundingMetadata.sources.slice(0, 5).map((source, index) => (
|
||||
<span
|
||||
key={index}
|
||||
className="inline-flex items-center px-2 py-1 text-xs bg-blue-50 text-blue-700 rounded-full"
|
||||
title={source.title || `来源 ${index + 1}`}
|
||||
>
|
||||
{index + 1}
|
||||
</span>
|
||||
))}
|
||||
{groundingMetadata.sources.length > 5 && (
|
||||
<span className="text-xs text-gray-400">
|
||||
+{groundingMetadata.sources.length - 5} 更多
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue