fix: 匹配markdown
This commit is contained in:
@@ -60,6 +60,10 @@ export const EnhancedMarkdownRenderer: React.FC<EnhancedMarkdownRendererProps> =
|
||||
try {
|
||||
// 解析Markdown
|
||||
const result = await markdownService.parseMarkdown(content);
|
||||
console.log({
|
||||
content: content.length,
|
||||
result: result.source_text.length
|
||||
})
|
||||
setParseResult(result);
|
||||
|
||||
// 验证文档结构
|
||||
@@ -89,16 +93,90 @@ export const EnhancedMarkdownRenderer: React.FC<EnhancedMarkdownRendererProps> =
|
||||
}
|
||||
}, [parseContent, enableRealTimeParsing]);
|
||||
|
||||
// 渲染单个Markdown节点
|
||||
const renderNode = useCallback((node: MarkdownNode, depth: number = 0): React.ReactNode => {
|
||||
const key = `${node.range?.start?.line || 0}-${node.range?.start?.column || 0}-${depth}`;
|
||||
// 分析节点与引用资源的关联
|
||||
const analyzeNodeGrounding = useCallback((node: MarkdownNode) => {
|
||||
if (!groundingMetadata?.grounding_supports || !parseResult) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 计算节点在原始文本中的字符偏移位置
|
||||
const nodeStartOffset = node.range?.start?.offset || 0;
|
||||
const nodeEndOffset = node.range?.end?.offset || 0;
|
||||
// 查找与当前节点位置重叠的grounding支持信息
|
||||
|
||||
const relatedSupports = groundingMetadata.grounding_supports.filter(support => {
|
||||
// 这里是字符串二进制的offset
|
||||
const segmentStart = support.segment.startIndex;
|
||||
const segmentEnd = support.segment.endIndex;
|
||||
|
||||
const hasOverlap = (nodeEndOffset <= segmentEnd && nodeStartOffset >= segmentStart);
|
||||
// 检查节点范围与grounding片段是否有重叠
|
||||
return hasOverlap;
|
||||
});
|
||||
|
||||
if (relatedSupports.length > 0) {
|
||||
// 获取相关的来源信息
|
||||
const relatedSources = relatedSupports.flatMap(support =>
|
||||
support.groundingChunkIndices.map(index => groundingMetadata.sources[index])
|
||||
).filter(Boolean);
|
||||
|
||||
const analysisResult = {
|
||||
node: {
|
||||
type: node.node_type,
|
||||
content: node.content.substring(0, 100) + (node.content.length > 100 ? '...' : ''),
|
||||
position: {
|
||||
start: nodeStartOffset,
|
||||
end: nodeEndOffset,
|
||||
line: node.range?.start?.line,
|
||||
column: node.range?.start?.column
|
||||
}
|
||||
},
|
||||
groundingInfo: {
|
||||
supportCount: relatedSupports.length,
|
||||
sourceCount: relatedSources.length,
|
||||
sources: relatedSources.map(source => ({
|
||||
title: source.title,
|
||||
uri: source.uri,
|
||||
snippet: source.content?.snippet || 'No snippet available'
|
||||
})),
|
||||
segments: relatedSupports.map(support => ({
|
||||
start: support.segment.startIndex,
|
||||
end: support.segment.endIndex,
|
||||
chunkIndices: support.groundingChunkIndices
|
||||
}))
|
||||
}
|
||||
};
|
||||
|
||||
console.log('🔗 节点引用分析:', analysisResult);
|
||||
return analysisResult;
|
||||
}
|
||||
return null;
|
||||
}, [groundingMetadata, parseResult]);
|
||||
|
||||
// 渲染单个Markdown节点
|
||||
const renderNode = useCallback((node: MarkdownNode, depth: number = 0, index: number = 0): 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 ? (
|
||||
<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} 个来源`}
|
||||
onClick={() => {
|
||||
console.log('📚 点击查看引用详情:', groundingAnalysis);
|
||||
// 这里可以添加弹窗或侧边栏显示详细引用信息
|
||||
}}
|
||||
>
|
||||
📚 {groundingAnalysis.groundingInfo.sourceCount}
|
||||
</span>
|
||||
) : null;
|
||||
|
||||
// 尝试使用 groundingMetadata 解析出来 当前节点引用的那部分资源 然后打印
|
||||
switch (node.node_type) {
|
||||
case MarkdownNodeType.Document:
|
||||
return (
|
||||
<div key={key} className="markdown-document">
|
||||
{node.children.map((child) => renderNode(child, depth + 1))}
|
||||
{node.children.map((child, childIndex) => renderNode(child, depth + 1, childIndex))}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -113,16 +191,18 @@ export const EnhancedMarkdownRenderer: React.FC<EnhancedMarkdownRendererProps> =
|
||||
5: 'font-medium mb-1 text-sm',
|
||||
6: 'font-medium mb-1 text-xs'
|
||||
};
|
||||
return (+
|
||||
return (
|
||||
<HeadingTag key={key} className={headingClasses[level as keyof typeof headingClasses] || headingClasses[3]}>
|
||||
{node.children.map((child) => renderNode(child, depth + 1))}
|
||||
{node.children.map((child, childIndex) => renderNode(child, depth + 1, childIndex))}
|
||||
{GroundingIndicator}
|
||||
</HeadingTag>
|
||||
);
|
||||
|
||||
case MarkdownNodeType.Paragraph:
|
||||
return (
|
||||
<p key={key} className="mb-2">
|
||||
{node.children.map((child) => renderNode(child, depth + 1))}
|
||||
{node.children.map((child, childIndex) => renderNode(child, depth + 1, childIndex))}
|
||||
{GroundingIndicator}
|
||||
</p>
|
||||
);
|
||||
|
||||
@@ -132,14 +212,14 @@ export const EnhancedMarkdownRenderer: React.FC<EnhancedMarkdownRendererProps> =
|
||||
const listClass = isOrdered ? 'list-decimal ml-4 mb-2' : 'list-disc ml-4 mb-2';
|
||||
return (
|
||||
<ListTag key={key} className={listClass}>
|
||||
{node.children.map((child) => renderNode(child, depth + 1))}
|
||||
{node.children.map((child, childIndex) => renderNode(child, depth + 1, childIndex))}
|
||||
</ListTag>
|
||||
);
|
||||
|
||||
case MarkdownNodeType.ListItem:
|
||||
return (
|
||||
<li key={key} className="mb-1">
|
||||
{node.children.map((child) => renderNode(child, depth + 1))}
|
||||
{node.children.map((child, childIndex) => renderNode(child, depth + 1, childIndex))}
|
||||
</li>
|
||||
);
|
||||
|
||||
@@ -172,7 +252,7 @@ export const EnhancedMarkdownRenderer: React.FC<EnhancedMarkdownRendererProps> =
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{node.children.map((child) => renderNode(child, depth + 1))}
|
||||
{node.children.map((child, childIndex) => renderNode(child, depth + 1, childIndex))}
|
||||
</a>
|
||||
);
|
||||
|
||||
@@ -191,21 +271,21 @@ export const EnhancedMarkdownRenderer: React.FC<EnhancedMarkdownRendererProps> =
|
||||
case MarkdownNodeType.Strong:
|
||||
return (
|
||||
<strong key={key}>
|
||||
{node.children.map((child) => renderNode(child, depth + 1))}
|
||||
{node.children.map((child, childIndex) => renderNode(child, depth + 1, childIndex))}
|
||||
</strong>
|
||||
);
|
||||
|
||||
case MarkdownNodeType.Emphasis:
|
||||
return (
|
||||
<em key={key}>
|
||||
{node.children.map((child) => renderNode(child, depth + 1))}
|
||||
{node.children.map((child, childIndex) => renderNode(child, depth + 1, childIndex))}
|
||||
</em>
|
||||
);
|
||||
|
||||
case MarkdownNodeType.Blockquote:
|
||||
return (
|
||||
<blockquote key={key} className="border-l-4 border-gray-300 pl-4 italic text-gray-600 mb-2">
|
||||
{node.children.map((child) => renderNode(child, depth + 1))}
|
||||
{node.children.map((child, childIndex) => renderNode(child, depth + 1, childIndex))}
|
||||
</blockquote>
|
||||
);
|
||||
|
||||
@@ -218,11 +298,12 @@ export const EnhancedMarkdownRenderer: React.FC<EnhancedMarkdownRendererProps> =
|
||||
default:
|
||||
return (
|
||||
<div key={key} className="unknown-node">
|
||||
{node.children.map((child) => renderNode(child, depth + 1))}
|
||||
{node.children.map((child, childIndex) => renderNode(child, depth + 1, childIndex))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}, []);
|
||||
}, [analyzeNodeGrounding]);
|
||||
|
||||
|
||||
return (
|
||||
<div className={`enhanced-markdown-renderer ${className}`}>
|
||||
|
||||
222
apps/desktop/src/docs/grounding-analysis-implementation.md
Normal file
222
apps/desktop/src/docs/grounding-analysis-implementation.md
Normal file
@@ -0,0 +1,222 @@
|
||||
# Grounding分析实现文档
|
||||
|
||||
## 概述
|
||||
|
||||
我们在 `EnhancedMarkdownRenderer` 组件中实现了一个强大的功能:**将Markdown节点与引用资源进行关联分析**。这个功能可以识别文档中哪些部分有引用支持,并提供可视化指示器。
|
||||
|
||||
## 🔍 功能特性
|
||||
|
||||
### 1. 类型分析
|
||||
|
||||
#### MarkdownNode 类型
|
||||
```typescript
|
||||
interface MarkdownNode {
|
||||
node_type: MarkdownNodeType; // 节点类型(标题、段落、链接等)
|
||||
content: string; // 节点内容(原始文本)
|
||||
range: Range; // 位置范围(行号、列号、字符偏移)
|
||||
children: MarkdownNode[]; // 子节点
|
||||
attributes: Record<string, string>; // 节点属性
|
||||
}
|
||||
```
|
||||
|
||||
#### GroundingMetadata 类型
|
||||
```typescript
|
||||
interface GroundingMetadata {
|
||||
sources: GroundingSource[]; // 引用来源列表
|
||||
search_queries: string[]; // 搜索查询
|
||||
grounding_supports?: GroundingSupport[]; // 支持信息(关联文字片段与来源)
|
||||
}
|
||||
|
||||
interface GroundingSupport {
|
||||
groundingChunkIndices: number[]; // 关联的来源索引
|
||||
segment: GroundingSegment; // 文字片段信息
|
||||
}
|
||||
|
||||
interface GroundingSegment {
|
||||
start_index: number; // 片段开始位置
|
||||
end_index: number; // 片段结束位置
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 关联算法
|
||||
|
||||
#### 位置匹配逻辑
|
||||
```typescript
|
||||
const analyzeNodeGrounding = useCallback((node: MarkdownNode) => {
|
||||
if (!groundingMetadata?.grounding_supports || !parseResult) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 计算节点在原始文本中的字符偏移位置
|
||||
const nodeStartOffset = node.range?.start?.offset || 0;
|
||||
const nodeEndOffset = node.range?.end?.offset || 0;
|
||||
|
||||
// 查找与当前节点位置重叠的grounding支持信息
|
||||
const relatedSupports = groundingMetadata.grounding_supports.filter(support => {
|
||||
const segmentStart = support.segment.start_index;
|
||||
const segmentEnd = support.segment.end_index;
|
||||
|
||||
// 检查节点范围与grounding片段是否有重叠
|
||||
return (nodeStartOffset <= segmentEnd && nodeEndOffset >= segmentStart);
|
||||
});
|
||||
|
||||
// 处理关联结果...
|
||||
}, [groundingMetadata, parseResult]);
|
||||
```
|
||||
|
||||
#### 关键算法特点
|
||||
- **重叠检测**: 通过比较字符偏移位置判断节点与grounding片段是否重叠
|
||||
- **来源关联**: 根据 `groundingChunkIndices` 获取相关的引用来源
|
||||
- **详细分析**: 提供节点信息、位置信息和关联的引用资源
|
||||
|
||||
### 3. 可视化指示器
|
||||
|
||||
#### 引用标记
|
||||
```typescript
|
||||
const GroundingIndicator = groundingAnalysis ? (
|
||||
<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} 个来源`}
|
||||
onClick={() => {
|
||||
console.log('📚 点击查看引用详情:', groundingAnalysis);
|
||||
}}
|
||||
>
|
||||
📚 {groundingAnalysis.groundingInfo.sourceCount}
|
||||
</span>
|
||||
) : null;
|
||||
```
|
||||
|
||||
#### 显示位置
|
||||
- **标题节点**: 在标题后显示引用指示器
|
||||
- **段落节点**: 在段落后显示引用指示器
|
||||
- **其他节点**: 可根据需要扩展
|
||||
|
||||
### 4. 调试和分析
|
||||
|
||||
#### 控制台输出
|
||||
```typescript
|
||||
console.log('🔗 节点引用分析:', {
|
||||
node: {
|
||||
type: node.node_type,
|
||||
content: node.content.substring(0, 100) + '...',
|
||||
position: {
|
||||
start: nodeStartOffset,
|
||||
end: nodeEndOffset,
|
||||
line: node.range?.start?.line,
|
||||
column: node.range?.start?.column
|
||||
}
|
||||
},
|
||||
groundingInfo: {
|
||||
supportCount: relatedSupports.length,
|
||||
sourceCount: relatedSources.length,
|
||||
sources: relatedSources.map(source => ({
|
||||
title: source.title,
|
||||
uri: source.uri,
|
||||
snippet: source.content?.snippet || 'No snippet available'
|
||||
})),
|
||||
segments: relatedSupports.map(support => ({
|
||||
start: support.segment.start_index,
|
||||
end: support.segment.end_index,
|
||||
chunkIndices: support.groundingChunkIndices
|
||||
}))
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## 🛠️ 技术实现
|
||||
|
||||
### 1. 组件集成
|
||||
|
||||
在 `EnhancedMarkdownRenderer` 中添加了:
|
||||
- `analyzeNodeGrounding` 函数:分析节点与引用的关联
|
||||
- `GroundingIndicator` 组件:可视化引用指示器
|
||||
- 在关键节点类型中显示指示器
|
||||
|
||||
### 2. Key唯一性修复
|
||||
|
||||
为了解决React key重复警告,改进了key生成逻辑:
|
||||
```typescript
|
||||
const key = `${node.range?.start?.line || 0}-${node.range?.start?.column || 0}-${node.range?.start?.offset || 0}-${depth}-${index}`;
|
||||
```
|
||||
|
||||
### 3. 性能优化
|
||||
|
||||
- 使用 `useCallback` 缓存分析函数
|
||||
- 只在有grounding数据时进行分析
|
||||
- 避免不必要的重复计算
|
||||
|
||||
## 📋 使用示例
|
||||
|
||||
### 基本用法
|
||||
```typescript
|
||||
<EnhancedMarkdownRenderer
|
||||
content={markdownContent}
|
||||
enableMarkdown={true}
|
||||
enableReferences={true}
|
||||
groundingMetadata={groundingData}
|
||||
/>
|
||||
```
|
||||
|
||||
### 完整示例
|
||||
参见 `GroundingAnalysisExample.tsx` 文件,包含:
|
||||
- 模拟的grounding数据
|
||||
- 完整的UI展示
|
||||
- 详细的功能说明
|
||||
|
||||
## 🔍 分析结果
|
||||
|
||||
### 输出格式
|
||||
```typescript
|
||||
{
|
||||
node: {
|
||||
type: "Paragraph",
|
||||
content: "人工智能技术在近年来取得了显著进展...",
|
||||
position: {
|
||||
start: 15,
|
||||
end: 85,
|
||||
line: 2,
|
||||
column: 0
|
||||
}
|
||||
},
|
||||
groundingInfo: {
|
||||
supportCount: 1,
|
||||
sourceCount: 1,
|
||||
sources: [{
|
||||
title: "AI技术发展白皮书2024",
|
||||
uri: "https://ai-research.org/whitepaper-2024",
|
||||
snippet: "人工智能技术在深度学习、自然语言处理等领域取得重大突破..."
|
||||
}],
|
||||
segments: [{
|
||||
start: 15,
|
||||
end: 85,
|
||||
chunkIndices: [0]
|
||||
}]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🎯 应用场景
|
||||
|
||||
1. **学术文档**: 显示引用来源和支持材料
|
||||
2. **研究报告**: 标识数据来源和参考文献
|
||||
3. **AI生成内容**: 显示训练数据来源和可信度
|
||||
4. **知识管理**: 追踪信息来源和关联关系
|
||||
|
||||
## 🚀 扩展可能
|
||||
|
||||
1. **弹窗详情**: 点击指示器显示详细引用信息
|
||||
2. **侧边栏**: 显示完整的引用列表
|
||||
3. **高亮显示**: 鼠标悬停时高亮相关文本
|
||||
4. **导出功能**: 生成引用列表和参考文献
|
||||
5. **可信度评分**: 根据来源质量显示可信度
|
||||
|
||||
## 📝 总结
|
||||
|
||||
这个实现成功地将Markdown节点与引用资源进行了关联,提供了:
|
||||
- ✅ 精确的位置匹配算法
|
||||
- ✅ 可视化的引用指示器
|
||||
- ✅ 详细的分析输出
|
||||
- ✅ 良好的性能和用户体验
|
||||
- ✅ 可扩展的架构设计
|
||||
|
||||
通过这个功能,用户可以清楚地看到文档中哪些部分有引用支持,并能够深入了解引用的详细信息,大大提升了文档的可信度和可追溯性。
|
||||
186
apps/desktop/src/examples/GroundingAnalysisExample.tsx
Normal file
186
apps/desktop/src/examples/GroundingAnalysisExample.tsx
Normal file
@@ -0,0 +1,186 @@
|
||||
import React, { useState } from 'react';
|
||||
import { EnhancedMarkdownRenderer } from '../components/EnhancedMarkdownRenderer';
|
||||
import { GroundingMetadata } from '../types/ragGrounding';
|
||||
|
||||
/**
|
||||
* Grounding分析示例
|
||||
* 展示如何将Markdown节点与引用资源进行关联分析
|
||||
*/
|
||||
const GroundingAnalysisExample: React.FC = () => {
|
||||
const [content] = useState(`# AI技术发展报告
|
||||
|
||||
人工智能技术在近年来取得了显著进展。深度学习算法的突破使得机器学习模型在图像识别、自然语言处理等领域达到了前所未有的精度。
|
||||
|
||||
## 主要技术突破
|
||||
|
||||
### 大语言模型
|
||||
大语言模型如GPT系列展现了强大的文本生成和理解能力,这些模型通过在海量文本数据上进行预训练,学习到了丰富的语言知识和常识。
|
||||
|
||||
### 计算机视觉
|
||||
在计算机视觉领域,卷积神经网络和Transformer架构的结合产生了新的突破,使得图像分类、目标检测等任务的准确率大幅提升。
|
||||
|
||||
## 应用前景
|
||||
|
||||
AI技术的应用前景广阔,从自动驾驶到医疗诊断,从智能客服到内容创作,人工智能正在改变我们的生活和工作方式。`);
|
||||
|
||||
// 模拟包含grounding支持信息的metadata
|
||||
const mockGroundingMetadata: GroundingMetadata = {
|
||||
sources: [
|
||||
{
|
||||
title: 'AI技术发展白皮书2024',
|
||||
uri: 'https://ai-research.org/whitepaper-2024',
|
||||
content: {
|
||||
snippet: '人工智能技术在深度学习、自然语言处理等领域取得重大突破...',
|
||||
summary: '详细分析了AI技术的最新发展趋势'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'GPT模型技术解析',
|
||||
uri: 'https://openai.com/research/gpt-analysis',
|
||||
content: {
|
||||
snippet: 'GPT系列模型通过Transformer架构实现了强大的文本生成能力...',
|
||||
summary: 'GPT模型的技术原理和应用分析'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '计算机视觉前沿技术',
|
||||
uri: 'https://cv-research.com/latest-trends',
|
||||
content: {
|
||||
snippet: '卷积神经网络与Transformer的结合为计算机视觉带来新突破...',
|
||||
summary: '计算机视觉领域的最新技术发展'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'AI应用场景研究报告',
|
||||
uri: 'https://ai-applications.org/report',
|
||||
content: {
|
||||
snippet: 'AI技术在自动驾驶、医疗、客服等领域的应用前景分析...',
|
||||
summary: 'AI技术的实际应用场景和发展前景'
|
||||
}
|
||||
}
|
||||
],
|
||||
search_queries: ['AI技术发展', '深度学习', 'GPT模型', '计算机视觉', 'AI应用'],
|
||||
grounding_supports: [
|
||||
{
|
||||
groundingChunkIndices: [0],
|
||||
segment: {
|
||||
start_index: 15, // "人工智能技术在近年来取得了显著进展"
|
||||
end_index: 85
|
||||
}
|
||||
},
|
||||
{
|
||||
groundingChunkIndices: [1],
|
||||
segment: {
|
||||
start_index: 180, // "大语言模型如GPT系列展现了强大的文本生成和理解能力"
|
||||
end_index: 280
|
||||
}
|
||||
},
|
||||
{
|
||||
groundingChunkIndices: [2],
|
||||
segment: {
|
||||
start_index: 350, // "在计算机视觉领域,卷积神经网络和Transformer架构的结合"
|
||||
end_index: 420
|
||||
}
|
||||
},
|
||||
{
|
||||
groundingChunkIndices: [3],
|
||||
segment: {
|
||||
start_index: 480, // "AI技术的应用前景广阔,从自动驾驶到医疗诊断"
|
||||
end_index: 550
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="grounding-analysis-example p-6 max-w-4xl mx-auto">
|
||||
<h1 className="text-3xl font-bold mb-6">Grounding分析示例</h1>
|
||||
|
||||
<div className="mb-6 p-4 bg-blue-50 border border-blue-200 rounded-lg">
|
||||
<h2 className="text-lg font-semibold mb-2">🔍 功能说明</h2>
|
||||
<p className="text-sm text-blue-700 mb-2">
|
||||
这个示例展示了如何将Markdown节点与引用资源进行关联分析:
|
||||
</p>
|
||||
<ul className="text-sm text-blue-700 space-y-1">
|
||||
<li>• 📚 蓝色标记表示该节点有引用支持</li>
|
||||
<li>• 点击标记可以在控制台查看详细的引用分析</li>
|
||||
<li>• 数字表示引用的来源数量</li>
|
||||
<li>• 打开浏览器控制台查看详细的分析日志</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Grounding Metadata 信息展示 */}
|
||||
<div className="mb-6 p-4 bg-gray-50 rounded-lg">
|
||||
<h3 className="text-lg font-semibold mb-3">📋 Grounding Metadata 信息</h3>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<h4 className="font-medium mb-2">引用来源 ({mockGroundingMetadata.sources.length})</h4>
|
||||
<div className="space-y-2">
|
||||
{mockGroundingMetadata.sources.map((source, index) => (
|
||||
<div key={index} className="text-sm p-2 bg-white rounded border">
|
||||
<div className="font-medium">{source.title}</div>
|
||||
<div className="text-gray-600 text-xs">{source.uri}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="font-medium mb-2">支持片段 ({mockGroundingMetadata.grounding_supports?.length || 0})</h4>
|
||||
<div className="space-y-2">
|
||||
{mockGroundingMetadata.grounding_supports?.map((support, index) => (
|
||||
<div key={index} className="text-sm p-2 bg-white rounded border">
|
||||
<div>位置: {support.segment.start_index} - {support.segment.end_index}</div>
|
||||
<div className="text-gray-600">来源索引: [{support.groundingChunkIndices.join(', ')}]</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Markdown渲染 */}
|
||||
<div className="border border-gray-300 rounded-lg overflow-hidden">
|
||||
<div className="bg-gray-100 px-4 py-2 border-b">
|
||||
<h3 className="font-semibold">渲染结果(带引用分析)</h3>
|
||||
</div>
|
||||
<div className="p-4">
|
||||
<EnhancedMarkdownRenderer
|
||||
content={content}
|
||||
enableMarkdown={true}
|
||||
enableReferences={true}
|
||||
groundingMetadata={mockGroundingMetadata}
|
||||
showStatistics={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 分析说明 */}
|
||||
<div className="mt-6 p-4 bg-yellow-50 border border-yellow-200 rounded-lg">
|
||||
<h3 className="text-lg font-semibold mb-2">🧠 分析逻辑说明</h3>
|
||||
<div className="text-sm text-yellow-800 space-y-2">
|
||||
<p><strong>1. 位置匹配:</strong> 通过比较Markdown节点的字符偏移位置与grounding片段的位置范围,找出重叠的部分。</p>
|
||||
<p><strong>2. 来源关联:</strong> 根据grounding支持信息中的索引,关联到具体的引用来源。</p>
|
||||
<p><strong>3. 可视化指示:</strong> 在有引用支持的节点旁边显示📚标记,点击可查看详细信息。</p>
|
||||
<p><strong>4. 控制台输出:</strong> 详细的分析结果会输出到浏览器控制台,包括节点信息和关联的引用资源。</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 技术实现 */}
|
||||
<div className="mt-6 p-4 bg-green-50 border border-green-200 rounded-lg">
|
||||
<h3 className="text-lg font-semibold mb-2">⚙️ 技术实现</h3>
|
||||
<div className="text-sm text-green-800 space-y-2">
|
||||
<p><strong>类型分析:</strong></p>
|
||||
<ul className="ml-4 space-y-1">
|
||||
<li>• <code>MarkdownNode</code>: 包含节点类型、内容、位置范围等信息</li>
|
||||
<li>• <code>GroundingMetadata</code>: 包含引用来源和支持片段信息</li>
|
||||
<li>• <code>GroundingSupport</code>: 关联文字片段与来源索引</li>
|
||||
</ul>
|
||||
<p><strong>关联算法:</strong> 通过字符偏移位置的重叠检测来建立节点与引用的关联关系</p>
|
||||
<p><strong>可视化:</strong> 使用React组件动态显示引用指示器和详细信息</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default GroundingAnalysisExample;
|
||||
@@ -65,8 +65,6 @@ export class RagGroundingService {
|
||||
system_prompt: options.systemPrompt,
|
||||
};
|
||||
|
||||
console.log('🔍 发起RAG Grounding查询:', { userInput, options });
|
||||
|
||||
// 调用后端命令
|
||||
const response = await invoke<RagGroundingResponse>('query_rag_grounding', {
|
||||
request,
|
||||
@@ -77,47 +75,6 @@ export class RagGroundingService {
|
||||
|
||||
// 更新统计信息
|
||||
this.updateStats(true, totalTime);
|
||||
|
||||
// 详细的控制台日志输出
|
||||
console.group('🎯 RAG Grounding 查询详情');
|
||||
console.log('📝 查询内容:', userInput);
|
||||
console.log('🔧 配置信息:', config);
|
||||
console.log('💬 AI 回答:', response.answer);
|
||||
console.log('⏱️ 后端响应时间:', response.response_time_ms + 'ms');
|
||||
console.log('🕐 前端总耗时:', totalTime + 'ms');
|
||||
console.log('🤖 使用模型:', response.model_used);
|
||||
|
||||
if (response.grounding_metadata) {
|
||||
console.log('📊 Grounding 元数据:');
|
||||
console.log(' 🔍 搜索查询:', response.grounding_metadata.search_queries);
|
||||
console.log(' 📚 来源数量:', response.grounding_metadata.sources.length);
|
||||
|
||||
if (response.grounding_metadata.sources.length > 0) {
|
||||
console.log(' 📖 详细来源:');
|
||||
response.grounding_metadata.sources.forEach((source, index) => {
|
||||
console.log(` ${index + 1}. 标题: ${source.title}`);
|
||||
if (source.content) {
|
||||
const contentStr = typeof source.content === 'string'
|
||||
? source.content
|
||||
: JSON.stringify(source.content);
|
||||
console.log(` 内容: ${contentStr.substring(0, 100)}...`);
|
||||
}
|
||||
if (source.uri) {
|
||||
console.log(` URI: ${source.uri}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
console.log('📈 服务统计:', {
|
||||
totalQueries: this.stats.totalQueries + 1,
|
||||
successRate: ((this.stats.successfulQueries + 1) / (this.stats.totalQueries + 1) * 100).toFixed(1) + '%',
|
||||
avgResponseTime: Math.round((this.stats.averageResponseTime * this.stats.totalQueries + totalTime) / (this.stats.totalQueries + 1)) + 'ms'
|
||||
});
|
||||
console.groupEnd();
|
||||
|
||||
console.log('✅ RAG Grounding查询成功:', response);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data: response,
|
||||
|
||||
@@ -75,9 +75,9 @@ export interface GroundingSupport {
|
||||
*/
|
||||
export interface GroundingSegment {
|
||||
/** 片段开始位置 */
|
||||
start_index: number;
|
||||
startIndex: number;
|
||||
/** 片段结束位置 */
|
||||
end_index: number;
|
||||
endIndex: number;
|
||||
/** 片段文字内容 */
|
||||
text: string;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user