fix: 优化markdown解析器
This commit is contained in:
@@ -37,7 +37,6 @@ interface EnhancedMarkdownRendererProps {
|
||||
export const EnhancedMarkdownRenderer: React.FC<EnhancedMarkdownRendererProps> = ({
|
||||
content,
|
||||
groundingMetadata,
|
||||
enableReferences = true,
|
||||
enableMarkdown = true,
|
||||
className = '',
|
||||
showStatistics = false,
|
||||
@@ -47,8 +46,7 @@ export const EnhancedMarkdownRenderer: React.FC<EnhancedMarkdownRendererProps> =
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [validation, setValidation] = useState<ValidationResult | null>(null);
|
||||
const [selectedGrounding, setSelectedGrounding] = useState<any>(null);
|
||||
const [showGroundingModal, setShowGroundingModal] = useState(false);
|
||||
const [expandedGrounding, setExpandedGrounding] = useState<any>(null);
|
||||
const [previewSource, setPreviewSource] = useState<any>(null);
|
||||
|
||||
// 解析Markdown内容
|
||||
@@ -98,17 +96,16 @@ export const EnhancedMarkdownRenderer: React.FC<EnhancedMarkdownRendererProps> =
|
||||
}
|
||||
}, [parseContent, enableRealTimeParsing]);
|
||||
|
||||
// 显示grounding详情
|
||||
const showGroundingDetails = useCallback((groundingAnalysis: any) => {
|
||||
setSelectedGrounding(groundingAnalysis);
|
||||
setShowGroundingModal(true);
|
||||
}, []);
|
||||
|
||||
// 关闭grounding详情
|
||||
const closeGroundingDetails = useCallback(() => {
|
||||
setShowGroundingModal(false);
|
||||
setSelectedGrounding(null);
|
||||
}, []);
|
||||
// 切换grounding详情展开状态
|
||||
const toggleGroundingDetails = useCallback((groundingAnalysis: any) => {
|
||||
if (expandedGrounding && expandedGrounding === groundingAnalysis) {
|
||||
// 如果当前已展开相同的内容,则收起
|
||||
setExpandedGrounding(null);
|
||||
} else {
|
||||
// 展开新的内容
|
||||
setExpandedGrounding(groundingAnalysis);
|
||||
}
|
||||
}, [expandedGrounding]);
|
||||
|
||||
// 查看大图
|
||||
const handleViewLarge = useCallback((source: any) => {
|
||||
@@ -216,22 +213,36 @@ export const EnhancedMarkdownRenderer: React.FC<EnhancedMarkdownRendererProps> =
|
||||
}, [groundingMetadata, parseResult]);
|
||||
|
||||
// 渲染单个Markdown节点
|
||||
const renderNode = useCallback((node: MarkdownNode, depth: number = 0, index: number = 0): React.ReactNode => {
|
||||
const renderNode = useCallback((node: MarkdownNode, depth: number = 0, index: number = 0, showGroundingIndicator: boolean = true): React.ReactNode => {
|
||||
const key = `${node.range?.start?.line || 0}-${node.range?.start?.column || 0}-${node.range?.start?.offset || 0}-${depth}-${index}`;
|
||||
// 分析当前节点的引用关联
|
||||
const groundingAnalysis = analyzeNodeGrounding(node);
|
||||
// 创建引用指示器组件
|
||||
const GroundingIndicator = groundingAnalysis ? (
|
||||
const isExpanded = expandedGrounding === groundingAnalysis;
|
||||
const GroundingIndicator = (groundingAnalysis && showGroundingIndicator) ? (
|
||||
<span
|
||||
className="inline-flex items-center ml-1 px-1 py-0.5 text-xs bg-blue-100 text-blue-700 rounded cursor-help"
|
||||
title={`引用了 ${groundingAnalysis.groundingInfo.sourceCount} 个来源`}
|
||||
className={`inline-flex items-center ml-1 px-2 py-1 text-xs rounded cursor-pointer transition-all duration-200 ${
|
||||
isExpanded
|
||||
? 'bg-blue-500 text-white shadow-md'
|
||||
: 'bg-blue-100 text-blue-700 hover:bg-blue-200'
|
||||
}`}
|
||||
title={`${isExpanded ? '收起' : '查看'} ${groundingAnalysis.groundingInfo.sourceCount} 个相关素材`}
|
||||
onClick={() => {
|
||||
console.log('📚 点击查看引用详情:', groundingAnalysis);
|
||||
// 显示详细的引用信息,包括图片
|
||||
showGroundingDetails(groundingAnalysis);
|
||||
// 切换详细的引用信息展示
|
||||
toggleGroundingDetails(groundingAnalysis);
|
||||
}}
|
||||
>
|
||||
{groundingAnalysis.groundingInfo.sourceCount}
|
||||
<span className="mr-1">🖼️</span>
|
||||
<span>{groundingAnalysis.groundingInfo.sourceCount}</span>
|
||||
<svg
|
||||
className={`w-3 h-3 ml-1 transition-transform duration-200 ${isExpanded ? 'rotate-180' : ''}`}
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
|
||||
</svg>
|
||||
</span>
|
||||
) : null;
|
||||
|
||||
@@ -332,7 +343,7 @@ export const EnhancedMarkdownRenderer: React.FC<EnhancedMarkdownRendererProps> =
|
||||
case MarkdownNodeType.Strong:
|
||||
return (
|
||||
<strong key={key}>
|
||||
{node.children.map((child, childIndex) => renderNode(child, depth + 1, childIndex))}
|
||||
{node.children.map((child, childIndex) => renderNode(child, depth + 1, childIndex, false))}
|
||||
</strong>
|
||||
);
|
||||
|
||||
@@ -424,78 +435,46 @@ export const EnhancedMarkdownRenderer: React.FC<EnhancedMarkdownRendererProps> =
|
||||
</div>
|
||||
</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} 个来源的信息
|
||||
{/* Grounding详情内联展开 */}
|
||||
{expandedGrounding && (
|
||||
<div className="mt-6 border-t border-gray-200 pt-4 animate-in slide-in-from-top-2 duration-300">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<h3 className="text-base font-semibold text-gray-900 flex items-center">
|
||||
<span className="mr-2">🖼️</span>
|
||||
相关素材详情 ({expandedGrounding.groundingInfo?.sourceCount || 0})
|
||||
</h3>
|
||||
<button
|
||||
onClick={() => setExpandedGrounding(null)}
|
||||
className="text-gray-400 hover:text-gray-600 transition-colors p-2 rounded-full hover:bg-gray-100"
|
||||
title="收起"
|
||||
>
|
||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 15l7-7 7 7" />
|
||||
</svg>
|
||||
</button>
|
||||
</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 cursor-pointer hover:bg-blue-100"
|
||||
title={source.title || `来源 ${index + 1}`}
|
||||
onClick={() => showGroundingDetails({
|
||||
groundingInfo: {
|
||||
sourceCount: 1,
|
||||
sources: [source]
|
||||
}
|
||||
})}
|
||||
>
|
||||
{index + 1}
|
||||
</span>
|
||||
))}
|
||||
{groundingMetadata.sources.length > 5 && (
|
||||
<span className="text-xs text-gray-400">
|
||||
+{groundingMetadata.sources.length - 5} 更多
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Grounding详情模态框 */}
|
||||
{showGroundingModal && selectedGrounding && (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50">
|
||||
<div className="bg-white rounded-lg shadow-xl max-w-4xl max-h-[90vh] overflow-hidden">
|
||||
{/* 模态框头部 */}
|
||||
<div className="flex items-center justify-between p-4 border-b border-gray-200">
|
||||
<h3 className="text-lg font-semibold text-gray-900">相关素材详情</h3>
|
||||
<button
|
||||
onClick={closeGroundingDetails}
|
||||
className="text-gray-400 hover:text-gray-600 transition-colors"
|
||||
>
|
||||
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* 模态框内容 */}
|
||||
<div className="p-4 overflow-y-auto max-h-[calc(90vh-8rem)]">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
{selectedGrounding.groundingInfo?.sources?.map((source: any, index: number) => (
|
||||
<div key={index} className="relative">
|
||||
<div className="bg-gradient-to-br from-gray-50 to-gray-100 rounded-xl p-6 shadow-inner">
|
||||
{expandedGrounding.groundingInfo?.sources && expandedGrounding.groundingInfo.sources.length > 0 ? (
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
{expandedGrounding.groundingInfo.sources.map((source: any, index: number) => (
|
||||
<div key={index} className="relative transform hover:scale-105 transition-transform duration-200">
|
||||
<ImageCard
|
||||
source={source}
|
||||
showDetails={true}
|
||||
onViewLarge={handleViewLarge}
|
||||
className="shadow-lg border border-gray-200 hover:shadow-xl transition-shadow"
|
||||
className="shadow-lg border border-gray-200 hover:shadow-xl transition-all duration-300 bg-white"
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* 如果没有图片,显示提示信息 */}
|
||||
{(!selectedGrounding.groundingInfo?.sources || selectedGrounding.groundingInfo.sources.length === 0) && (
|
||||
<div className="text-center py-8 text-gray-500">
|
||||
<div className="text-4xl mb-2">🖼️</div>
|
||||
<p>暂无相关图片素材</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<div className="text-center py-12 text-gray-500">
|
||||
<div className="text-6xl mb-4 opacity-50">🖼️</div>
|
||||
<p className="text-base font-medium mb-2">暂无相关图片素材</p>
|
||||
<p className="text-sm text-gray-400">该内容段落没有关联的图片资源</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user