Showing
11 changed files
with
80 additions
and
11 deletions
| @@ -598,6 +598,7 @@ class ReportAgent: | @@ -598,6 +598,7 @@ class ReportAgent: | ||
| 598 | emit('stage', {'stage': 'storage_ready', 'run_dir': str(run_dir)}) | 598 | emit('stage', {'stage': 'storage_ready', 'run_dir': str(run_dir)}) |
| 599 | 599 | ||
| 600 | # ==================== GraphRAG 初始化 ==================== | 600 | # ==================== GraphRAG 初始化 ==================== |
| 601 | + # 根据配置开关决定是否启用图谱构建/查询(需 .env 设置 GRAPHRAG_ENABLED=True) | ||
| 601 | graphrag_enabled = getattr(self.config, 'GRAPHRAG_ENABLED', False) | 602 | graphrag_enabled = getattr(self.config, 'GRAPHRAG_ENABLED', False) |
| 602 | knowledge_graph = None | 603 | knowledge_graph = None |
| 603 | graphrag_query_node = None | 604 | graphrag_query_node = None |
| @@ -607,6 +608,7 @@ class ReportAgent: | @@ -607,6 +608,7 @@ class ReportAgent: | ||
| 607 | emit('stage', {'stage': 'graphrag_building', 'message': '正在构建知识图谱'}) | 608 | emit('stage', {'stage': 'graphrag_building', 'message': '正在构建知识图谱'}) |
| 608 | 609 | ||
| 609 | try: | 610 | try: |
| 611 | + # 将 state_*.json + forum.log 转为结构化图谱,并立即落盘 graphrag.json | ||
| 610 | knowledge_graph = self._build_knowledge_graph( | 612 | knowledge_graph = self._build_knowledge_graph( |
| 611 | query, normalized_reports, forum_logs, run_dir | 613 | query, normalized_reports, forum_logs, run_dir |
| 612 | ) | 614 | ) |
| @@ -687,6 +689,7 @@ class ReportAgent: | @@ -687,6 +689,7 @@ class ReportAgent: | ||
| 687 | 'emphasis': emphasis_value | 689 | 'emphasis': emphasis_value |
| 688 | } | 690 | } |
| 689 | 691 | ||
| 692 | + # 先让 GraphRAG 节点多轮查询,再把结果附加到章节上下文 | ||
| 690 | graph_results = graphrag_query_node.run( | 693 | graph_results = graphrag_query_node.run( |
| 691 | section_info, | 694 | section_info, |
| 692 | { | 695 | { |
| @@ -699,7 +702,7 @@ class ReportAgent: | @@ -699,7 +702,7 @@ class ReportAgent: | ||
| 699 | ) | 702 | ) |
| 700 | 703 | ||
| 701 | if graph_results and graph_results.get('total_nodes', 0) > 0: | 704 | if graph_results and graph_results.get('total_nodes', 0) > 0: |
| 702 | - # 将图谱结果注入生成上下文 | 705 | + # 将图谱结果注入生成上下文,后续章节 LLM 自动使用增强提示词 |
| 703 | chapter_context['graph_results'] = graph_results | 706 | chapter_context['graph_results'] = graph_results |
| 704 | chapter_context['graph_enhancement_prompt'] = format_graph_results_for_prompt(graph_results) | 707 | chapter_context['graph_enhancement_prompt'] = format_graph_results_for_prompt(graph_results) |
| 705 | logger.info(f"章节 {section.title} GraphRAG 查询完成: {graph_results.get('total_nodes', 0)} 节点") | 708 | logger.info(f"章节 {section.title} GraphRAG 查询完成: {graph_results.get('total_nodes', 0)} 节点") |
| @@ -2,6 +2,11 @@ | @@ -2,6 +2,11 @@ | ||
| 2 | GraphRAG 知识图谱模块 | 2 | GraphRAG 知识图谱模块 |
| 3 | 3 | ||
| 4 | 提供基于结构化数据的知识图谱构建、存储与查询功能。 | 4 | 提供基于结构化数据的知识图谱构建、存储与查询功能。 |
| 5 | +典型用法: | ||
| 6 | +1) 使用 `StateParser`/`ForumParser` 解析三引擎 state JSON 与 forum.log; | ||
| 7 | +2) 调用 `GraphBuilder.build` 生成纯结构化的图对象; | ||
| 8 | +3) 通过 `GraphStorage.save/load` 持久化或读取图数据; | ||
| 9 | +4) 以 `QueryEngine` 在章节侧执行多轮图查询。 | ||
| 5 | """ | 10 | """ |
| 6 | 11 | ||
| 7 | from .state_parser import StateParser, ParsedState, ParsedSection, SearchRecord | 12 | from .state_parser import StateParser, ParsedState, ParsedSection, SearchRecord |
| @@ -2,6 +2,8 @@ | @@ -2,6 +2,8 @@ | ||
| 2 | Forum 日志解析器 | 2 | Forum 日志解析器 |
| 3 | 3 | ||
| 4 | 解析 forum.log 文件,提取结构化的讨论记录用于构建知识图谱。 | 4 | 解析 forum.log 文件,提取结构化的讨论记录用于构建知识图谱。 |
| 5 | +日志与 GraphRAG 的关系:仅将主持人/三引擎发言转为结构化节点, | ||
| 6 | +用于补充 Host 总结或跨引擎观点。 | ||
| 5 | """ | 7 | """ |
| 6 | 8 | ||
| 7 | from dataclasses import dataclass | 9 | from dataclasses import dataclass |
| @@ -41,6 +43,7 @@ class ForumParser: | @@ -41,6 +43,7 @@ class ForumParser: | ||
| 41 | 43 | ||
| 42 | 解析 forum.log,提取结构化的讨论记录。 | 44 | 解析 forum.log,提取结构化的讨论记录。 |
| 43 | 日志格式: [HH:MM:SS] [SPEAKER] content | 45 | 日志格式: [HH:MM:SS] [SPEAKER] content |
| 46 | + SPEAKER 需属于 VALID_SPEAKERS;非规范行会被忽略,确保图谱不被噪音污染。 | ||
| 44 | """ | 47 | """ |
| 45 | 48 | ||
| 46 | # 匹配日志行的正则表达式 | 49 | # 匹配日志行的正则表达式 |
| @@ -19,6 +19,10 @@ class GraphBuilder: | @@ -19,6 +19,10 @@ class GraphBuilder: | ||
| 19 | 基于已有的结构化数据(State JSON、Forum 日志)构建图谱, | 19 | 基于已有的结构化数据(State JSON、Forum 日志)构建图谱, |
| 20 | 无需 LLM 进行实体/关系提取。 | 20 | 无需 LLM 进行实体/关系提取。 |
| 21 | 21 | ||
| 22 | + ReportAgent 在 _build_knowledge_graph 中调用本构建器,将 load_input_files | ||
| 23 | + 提前解析好的 ParsedState / ForumEntry 转为 Graph 对象,再交由 GraphStorage | ||
| 24 | + 落盘并供 GraphRAGQueryNode 查询。 | ||
| 25 | + | ||
| 22 | 节点类型(5种): | 26 | 节点类型(5种): |
| 23 | - topic: 用户查询主题 | 27 | - topic: 用户查询主题 |
| 24 | - engine: 四个引擎来源 (insight/media/query/host) | 28 | - engine: 四个引擎来源 (insight/media/query/host) |
| @@ -108,7 +112,7 @@ class GraphBuilder: | @@ -108,7 +112,7 @@ class GraphBuilder: | ||
| 108 | if not search.query: | 112 | if not search.query: |
| 109 | continue | 113 | continue |
| 110 | 114 | ||
| 111 | - # 搜索词去重 | 115 | + # 搜索词去重(同一段落相同查询仅保留首条,避免图谱冗余) |
| 112 | query_key = search.query.strip().lower() | 116 | query_key = search.query.strip().lower() |
| 113 | if query_key in seen_queries: | 117 | if query_key in seen_queries: |
| 114 | continue | 118 | continue |
| @@ -107,7 +107,12 @@ class Edge: | @@ -107,7 +107,12 @@ class Edge: | ||
| 107 | 107 | ||
| 108 | 108 | ||
| 109 | class Graph: | 109 | class Graph: |
| 110 | - """知识图谱""" | 110 | + """ |
| 111 | + 知识图谱 | ||
| 112 | + | ||
| 113 | + 仅负责存储节点/边与邻接表,不依赖外部数据库,便于在章节侧内存查询。 | ||
| 114 | + 邻接表 _adjacency 用于 QueryEngine 按深度扩展邻居节点。 | ||
| 115 | + """ | ||
| 111 | 116 | ||
| 112 | def __init__(self): | 117 | def __init__(self): |
| 113 | self._nodes: Dict[str, Node] = {} | 118 | self._nodes: Dict[str, Node] = {} |
| @@ -290,7 +295,13 @@ class Graph: | @@ -290,7 +295,13 @@ class Graph: | ||
| 290 | 295 | ||
| 291 | 296 | ||
| 292 | class GraphStorage: | 297 | class GraphStorage: |
| 293 | - """图谱存储管理器""" | 298 | + """ |
| 299 | + 图谱存储管理器 | ||
| 300 | + | ||
| 301 | + 将 Graph 对象序列化为 JSON(graphrag.json),路径与 ChapterStorage 输出目录一致, | ||
| 302 | + 便于 Web/Report 引擎共享。支持按报告ID查找、列举最新图谱,供 Flask API 或 | ||
| 303 | + GraphRAGQueryNode 直接读取。 | ||
| 304 | + """ | ||
| 294 | 305 | ||
| 295 | FILENAME = "graphrag.json" | 306 | FILENAME = "graphrag.json" |
| 296 | 307 | ||
| @@ -394,6 +405,11 @@ class GraphStorage: | @@ -394,6 +405,11 @@ class GraphStorage: | ||
| 394 | 405 | ||
| 395 | Returns: | 406 | Returns: |
| 396 | 图谱文件路径,未找到返回 None | 407 | 图谱文件路径,未找到返回 None |
| 408 | + | ||
| 409 | + 工作方式: | ||
| 410 | + 1) 优先匹配目录名是否含 report_id(兼容 _/- 差异); | ||
| 411 | + 2) 否则读取 graphrag.json 内 task_id/report_id 做兜底匹配; | ||
| 412 | + 适配 Agent 运行目录命名不一致的场景。 | ||
| 397 | """ | 413 | """ |
| 398 | # 在章节目录中搜索(与 ChapterStorage 保持一致) | 414 | # 在章节目录中搜索(与 ChapterStorage 保持一致) |
| 399 | chapters_dir = self.chapters_dir | 415 | chapters_dir = self.chapters_dir |
| @@ -442,6 +458,8 @@ class GraphStorage: | @@ -442,6 +458,8 @@ class GraphStorage: | ||
| 442 | 458 | ||
| 443 | Returns: | 459 | Returns: |
| 444 | 最新图谱文件路径,未找到返回 None | 460 | 最新图谱文件路径,未找到返回 None |
| 461 | + | ||
| 462 | + 根据文件修改时间排序,用于前端“最近一次生成”快速预览。 | ||
| 445 | """ | 463 | """ |
| 446 | chapters_dir = self.chapters_dir | 464 | chapters_dir = self.chapters_dir |
| 447 | if not chapters_dir.exists(): | 465 | if not chapters_dir.exists(): |
| @@ -121,6 +121,9 @@ def format_graph_results_for_prompt(graph_results: dict) -> str: | @@ -121,6 +121,9 @@ def format_graph_results_for_prompt(graph_results: dict) -> str: | ||
| 121 | 121 | ||
| 122 | Returns: | 122 | Returns: |
| 123 | 格式化的字符串 | 123 | 格式化的字符串 |
| 124 | + | ||
| 125 | + 供 ReportAgent 在章节生成前注入 `graph_enhancement_prompt`, | ||
| 126 | + 将多轮查询结果以结构化文本交给章节 LLM,避免直接传递大 JSON。 | ||
| 124 | """ | 127 | """ |
| 125 | if not graph_results: | 128 | if not graph_results: |
| 126 | return "" | 129 | return "" |
| @@ -12,7 +12,15 @@ from .graph_storage import Graph, Node | @@ -12,7 +12,15 @@ from .graph_storage import Graph, Node | ||
| 12 | 12 | ||
| 13 | @dataclass | 13 | @dataclass |
| 14 | class QueryParams: | 14 | class QueryParams: |
| 15 | - """查询参数""" | 15 | + """ |
| 16 | + 查询参数 | ||
| 17 | + | ||
| 18 | + 由 GraphRAGQueryNode 或 Flask API 注入,控制查询范围: | ||
| 19 | + - keywords: 关键词列表,可为空(空时默认返回各引擎 section 摘要); | ||
| 20 | + - node_types: 限定节点类型;None 表示全量; | ||
| 21 | + - engine_filter: 仅保留指定引擎来源; | ||
| 22 | + - depth: 匹配节点向外扩展的层级。 | ||
| 23 | + """ | ||
| 16 | keywords: List[str] = field(default_factory=list) | 24 | keywords: List[str] = field(default_factory=list) |
| 17 | node_types: Optional[List[str]] = None # None 表示全部类型 | 25 | node_types: Optional[List[str]] = None # None 表示全部类型 |
| 18 | engine_filter: Optional[List[str]] = None # 限定引擎来源 | 26 | engine_filter: Optional[List[str]] = None # 限定引擎来源 |
| @@ -3,6 +3,10 @@ State JSON 解析器 | @@ -3,6 +3,10 @@ State JSON 解析器 | ||
| 3 | 3 | ||
| 4 | 解析 Insight/Media/Query 三引擎的 State JSON 文件, | 4 | 解析 Insight/Media/Query 三引擎的 State JSON 文件, |
| 5 | 提取结构化数据用于构建知识图谱。 | 5 | 提取结构化数据用于构建知识图谱。 |
| 6 | + | ||
| 7 | +默认假设 state_* 文件结构与三引擎输出一致: | ||
| 8 | +- 顶层包含 query/report_title/paragraphs; | ||
| 9 | +- 段落内的 research.search_history 记录搜索关键词、URL与摘要。 | ||
| 6 | """ | 10 | """ |
| 7 | 11 | ||
| 8 | from dataclasses import dataclass, field | 12 | from dataclasses import dataclass, field |
| @@ -45,6 +49,8 @@ class StateParser: | @@ -45,6 +49,8 @@ class StateParser: | ||
| 45 | State JSON 解析器 | 49 | State JSON 解析器 |
| 46 | 50 | ||
| 47 | 解析三引擎的 State JSON,提取用于构建知识图谱的结构化数据。 | 51 | 解析三引擎的 State JSON,提取用于构建知识图谱的结构化数据。 |
| 52 | + 适用于 load_input_files 阶段:先查找与 MD 同目录的 state_*.json, | ||
| 53 | + 若存在则转为 ParsedState 供 GraphBuilder 直接消费。 | ||
| 48 | """ | 54 | """ |
| 49 | 55 | ||
| 50 | def parse(self, engine_name: str, state_json: Dict[str, Any]) -> ParsedState: | 56 | def parse(self, engine_name: str, state_json: Dict[str, Any]) -> ParsedState: |
| @@ -84,7 +90,7 @@ class StateParser: | @@ -84,7 +90,7 @@ class StateParser: | ||
| 84 | timestamp=search.get('timestamp', '') | 90 | timestamp=search.get('timestamp', '') |
| 85 | )) | 91 | )) |
| 86 | 92 | ||
| 87 | - # 获取摘要,优先使用 latest_summary | 93 | + # 获取摘要,优先使用 latest_summary;若缺失则回退到段落正文 |
| 88 | summary = research.get('latest_summary', '') | 94 | summary = research.get('latest_summary', '') |
| 89 | if not summary: | 95 | if not summary: |
| 90 | summary = para.get('content', '') | 96 | summary = para.get('content', '') |
| @@ -124,6 +130,7 @@ class StateParser: | @@ -124,6 +130,7 @@ class StateParser: | ||
| 124 | 根据 Markdown 报告路径查找对应的 State JSON 文件 | 130 | 根据 Markdown 报告路径查找对应的 State JSON 文件 |
| 125 | 131 | ||
| 126 | State JSON 通常与 MD 文件在同一目录下,命名格式为 state_*.json | 132 | State JSON 通常与 MD 文件在同一目录下,命名格式为 state_*.json |
| 133 | + 用于 GraphRAG:在 load_input_files 时自动匹配最新或同名 state 文件。 | ||
| 127 | 134 | ||
| 128 | Args: | 135 | Args: |
| 129 | md_path: Markdown 文件路径 | 136 | md_path: Markdown 文件路径 |
| @@ -133,7 +133,7 @@ class GraphRAGQueryNode(BaseNode): | @@ -133,7 +133,7 @@ class GraphRAGQueryNode(BaseNode): | ||
| 133 | for round_idx in range(max_queries): | 133 | for round_idx in range(max_queries): |
| 134 | self.log_info(f"查询轮次 {round_idx + 1}/{max_queries}") | 134 | self.log_info(f"查询轮次 {round_idx + 1}/{max_queries}") |
| 135 | 135 | ||
| 136 | - # 1. 构建决策提示词 | 136 | + # 1. 构建决策提示词:将章节目标+图谱概览+查询历史一起交给 LLM |
| 137 | prompt = self._build_decision_prompt( | 137 | prompt = self._build_decision_prompt( |
| 138 | section, context, query_engine, history | 138 | section, context, query_engine, history |
| 139 | ) | 139 | ) |
| @@ -145,12 +145,12 @@ class GraphRAGQueryNode(BaseNode): | @@ -145,12 +145,12 @@ class GraphRAGQueryNode(BaseNode): | ||
| 145 | self.log_error("LLM 返回无效决策,终止查询") | 145 | self.log_error("LLM 返回无效决策,终止查询") |
| 146 | break | 146 | break |
| 147 | 147 | ||
| 148 | - # 3. 检查是否停止 | 148 | + # 3. 检查是否停止:LLM 可主动返回 should_query=false 以节省轮次 |
| 149 | if not decision.get('should_query', False): | 149 | if not decision.get('should_query', False): |
| 150 | self.log_info(f"LLM 决定停止查询: {decision.get('reasoning', '无原因')}") | 150 | self.log_info(f"LLM 决定停止查询: {decision.get('reasoning', '无原因')}") |
| 151 | break | 151 | break |
| 152 | 152 | ||
| 153 | - # 4. 执行查询 | 153 | + # 4. 执行查询:按 LLM 给出的参数查询本地图谱 |
| 154 | params = QueryParams( | 154 | params = QueryParams( |
| 155 | keywords=decision.get('keywords', []), | 155 | keywords=decision.get('keywords', []), |
| 156 | node_types=decision.get('node_types'), | 156 | node_types=decision.get('node_types'), |
| @@ -222,7 +222,12 @@ class GraphRAGQueryNode(BaseNode): | @@ -222,7 +222,12 @@ class GraphRAGQueryNode(BaseNode): | ||
| 222 | context: Dict[str, Any], | 222 | context: Dict[str, Any], |
| 223 | query_engine: QueryEngine, | 223 | query_engine: QueryEngine, |
| 224 | history: QueryHistory) -> Dict[str, str]: | 224 | history: QueryHistory) -> Dict[str, str]: |
| 225 | - """构建查询决策提示词""" | 225 | + """ |
| 226 | + 构建查询决策提示词 | ||
| 227 | + | ||
| 228 | + 将章节目标、模板章节概览、图谱统计、历史查询摘要整合为 | ||
| 229 | + system/user prompt,指导 LLM 生成下一轮 QueryParams。 | ||
| 230 | + """ | ||
| 226 | # 获取图谱概览 | 231 | # 获取图谱概览 |
| 227 | summary = query_engine.get_node_summary() | 232 | summary = query_engine.get_node_summary() |
| 228 | stats = summary.get('stats', {}) | 233 | stats = summary.get('stats', {}) |
| @@ -268,7 +273,12 @@ class GraphRAGQueryNode(BaseNode): | @@ -268,7 +273,12 @@ class GraphRAGQueryNode(BaseNode): | ||
| 268 | } | 273 | } |
| 269 | 274 | ||
| 270 | def _get_query_decision(self, prompt: Dict[str, str]) -> Optional[Dict[str, Any]]: | 275 | def _get_query_decision(self, prompt: Dict[str, str]) -> Optional[Dict[str, Any]]: |
| 271 | - """调用 LLM 获取查询决策""" | 276 | + """ |
| 277 | + 调用 LLM 获取查询决策 | ||
| 278 | + | ||
| 279 | + 返回的 JSON 将被转换为 QueryParams;任何解析失败都会终止后续轮次, | ||
| 280 | + 避免章节生成被异常输出阻断。 | ||
| 281 | + """ | ||
| 272 | try: | 282 | try: |
| 273 | response = self.llm_client.invoke( | 283 | response = self.llm_client.invoke( |
| 274 | system_prompt=prompt['system'], | 284 | system_prompt=prompt['system'], |
| @@ -1307,6 +1307,8 @@ def shutdown_system(): | @@ -1307,6 +1307,8 @@ def shutdown_system(): | ||
| 1307 | return jsonify({'success': False, 'message': f'系统关闭异常: {exc}'}), 500 | 1307 | return jsonify({'success': False, 'message': f'系统关闭异常: {exc}'}), 500 |
| 1308 | 1308 | ||
| 1309 | # ==================== GraphRAG API 端点 ==================== | 1309 | # ==================== GraphRAG API 端点 ==================== |
| 1310 | +# 前端控制台与 /graph-viewer 调用,均依赖 ReportEngine 在章节目录落盘的 graphrag.json。 | ||
| 1311 | +# 若 GRAPHRAG_ENABLED 关闭,这些接口仅返回“未找到图谱”提示。 | ||
| 1310 | 1312 | ||
| 1311 | @app.route('/api/graph/<report_id>') | 1313 | @app.route('/api/graph/<report_id>') |
| 1312 | def get_graph_data(report_id): | 1314 | def get_graph_data(report_id): |
| @@ -1493,6 +1495,7 @@ def query_graph(): | @@ -1493,6 +1495,7 @@ def query_graph(): | ||
| 1493 | if report_id: | 1495 | if report_id: |
| 1494 | graph_path = storage.find_graph_by_report_id(report_id) | 1496 | graph_path = storage.find_graph_by_report_id(report_id) |
| 1495 | else: | 1497 | else: |
| 1498 | + # 未指定报告ID时默认取最近一次生成的图谱,便于快速试用 | ||
| 1496 | graph_path = storage.find_latest_graph() | 1499 | graph_path = storage.find_latest_graph() |
| 1497 | 1500 | ||
| 1498 | if not graph_path or not graph_path.exists(): | 1501 | if not graph_path or not graph_path.exists(): |
| @@ -2282,6 +2282,7 @@ | @@ -2282,6 +2282,7 @@ | ||
| 2282 | query: 8503 | 2282 | query: 8503 |
| 2283 | }; | 2283 | }; |
| 2284 | 2284 | ||
| 2285 | + // ---------------- GraphRAG 开关与配置同步 ---------------- | ||
| 2285 | function syncGraphragFlag(config) { | 2286 | function syncGraphragFlag(config) { |
| 2286 | if (!config || !Object.prototype.hasOwnProperty.call(config, 'GRAPHRAG_ENABLED')) { | 2287 | if (!config || !Object.prototype.hasOwnProperty.call(config, 'GRAPHRAG_ENABLED')) { |
| 2287 | return; | 2288 | return; |
| @@ -2290,6 +2291,7 @@ | @@ -2290,6 +2291,7 @@ | ||
| 2290 | graphragSettingLoaded = true; | 2291 | graphragSettingLoaded = true; |
| 2291 | } | 2292 | } |
| 2292 | 2293 | ||
| 2294 | + // 前端懒加载配置:初次访问或强制刷新时请求 /api/config,决定是否展示图谱面板 | ||
| 2293 | async function ensureGraphragSetting(force = false) { | 2295 | async function ensureGraphragSetting(force = false) { |
| 2294 | if (!force && graphragSettingLoaded) { | 2296 | if (!force && graphragSettingLoaded) { |
| 2295 | return graphragEnabled; | 2297 | return graphragEnabled; |
| @@ -5151,6 +5153,7 @@ function getConsoleContainer() { | @@ -5151,6 +5153,7 @@ function getConsoleContainer() { | ||
| 5151 | } | 5153 | } |
| 5152 | } | 5154 | } |
| 5153 | 5155 | ||
| 5156 | + // 入口:在报告界面渲染后初始化图谱面板,若 GraphRAG 关闭则隐藏 | ||
| 5154 | async function initializeGraphPanel(statusData) { | 5157 | async function initializeGraphPanel(statusData) { |
| 5155 | const panel = document.getElementById('graphPanel'); | 5158 | const panel = document.getElementById('graphPanel'); |
| 5156 | if (!panel) return; | 5159 | if (!panel) return; |
| @@ -5175,6 +5178,7 @@ function getConsoleContainer() { | @@ -5175,6 +5178,7 @@ function getConsoleContainer() { | ||
| 5175 | refreshGraphPanel(graphPanelTaskId, true); | 5178 | refreshGraphPanel(graphPanelTaskId, true); |
| 5176 | } | 5179 | } |
| 5177 | 5180 | ||
| 5181 | + // 注册图谱面板按钮/筛选/搜索事件,只绑定一次 | ||
| 5178 | function bindGraphPanelEvents() { | 5182 | function bindGraphPanelEvents() { |
| 5179 | const refreshBtn = document.getElementById('graphRefreshBtn'); | 5183 | const refreshBtn = document.getElementById('graphRefreshBtn'); |
| 5180 | const collapseBtn = document.getElementById('graphCollapseBtn'); | 5184 | const collapseBtn = document.getElementById('graphCollapseBtn'); |
| @@ -5342,6 +5346,7 @@ function getConsoleContainer() { | @@ -5342,6 +5346,7 @@ function getConsoleContainer() { | ||
| 5342 | }); | 5346 | }); |
| 5343 | } | 5347 | } |
| 5344 | 5348 | ||
| 5349 | + // 将 graphrag.json 转换的节点/边渲染成 mini 版 vis.js 图谱 | ||
| 5345 | function renderGraphPanel(graph, resetPlaceholder = true) { | 5350 | function renderGraphPanel(graph, resetPlaceholder = true) { |
| 5346 | const panel = document.getElementById('graphPanel'); | 5351 | const panel = document.getElementById('graphPanel'); |
| 5347 | const canvasWrapper = document.getElementById('graphPanelCanvas'); | 5352 | const canvasWrapper = document.getElementById('graphPanelCanvas'); |
-
Please register or login to post a comment