feat(vault): Phase 3 tools + batch citation/relation enrichment

This commit is contained in:
2026-07-01 15:20:40 +08:00
parent 8273017082
commit 407a9213bf
548 changed files with 53410 additions and 2113 deletions
+46 -5
View File
@@ -5,14 +5,17 @@ graph-search.py — 图感知搜索
流程:
1. qmd vsearch 获取语义匹配结果(Top 10)
2. 对每个结果,读取 relations 字段 → 获取相邻节点
2. 对每个结果,扩展相邻节点
- 默认:读取各页面 relations 字段(实时,慢但零状态)
- --use-graph:读取预构建的 knowledge-graph.json(快,需先 build
3. 去重后返回(直接关联 + 关系扩展)
用法:
python tools/scripts/graph-search.py "查询词" [--count 15] [--depth 1]
python tools/scripts/graph-search.py "查询词" [--count 15] [--depth 1] [--use-graph]
依赖:
- qmd 已安装(通过 node
- --use-graph 需先运行 knowledge-graph.py build
"""
import argparse
import json
@@ -28,6 +31,7 @@ except ImportError:
QMD = r'node "C:\Users\hhhh2024\AppData\Roaming\npm\node_modules\@tobilu\qmd\dist\cli\qmd.js"'
WIKI = Path(r"D:\Applications\app\kepano-obsidian-main\wiki")
GRAPH_DB = Path(r"D:\Applications\app\kepano-obsidian-main\tools\data\knowledge-graph.json")
def qmd_search(query: str, count: int = 10) -> list[str]:
@@ -57,7 +61,7 @@ def get_relations(page_name: str) -> list[dict]:
def expand_nodes(nodes: list[str], depth: int = 1) -> list[str]:
"""从起始节点出发,沿 relations 扩展相邻节点"""
"""从起始节点出发,沿 relations 扩展相邻节点(实时读取页面 frontmatter"""
expanded = list(nodes)
frontier = list(nodes)
for _ in range(depth):
@@ -75,11 +79,38 @@ def expand_nodes(nodes: list[str], depth: int = 1) -> list[str]:
return expanded
def expand_nodes_via_graph(nodes: list[str], depth: int = 1, min_conf: int = 3) -> list[str]:
"""通过预构建的 knowledge-graph.json 扩展(更快,无 IO"""
if not GRAPH_DB.exists():
return list(nodes)
graph = json.loads(GRAPH_DB.read_text(encoding="utf-8"))
adj: dict[str, list] = {}
for e in graph["edges"]:
adj.setdefault(e["source"], []).append((e["target"], e.get("confidence", 3)))
adj.setdefault(e["target"], []).append((e["source"], e.get("confidence", 3)))
expanded = list(nodes)
frontier = list(nodes)
for _ in range(depth):
next_frontier = []
for node in frontier:
for target, conf in adj.get(node, []):
if conf >= min_conf and target not in expanded:
expanded.append(target)
next_frontier.append(target)
frontier = next_frontier
if not frontier:
break
return expanded
def main():
parser = argparse.ArgumentParser(description="Graph-aware search for wiki pages")
parser.add_argument("query", help="Search query")
parser.add_argument("--count", type=int, default=15, help="Max results")
parser.add_argument("--depth", type=int, default=1, help="Graph expansion depth")
parser.add_argument("--use-graph", action="store_true",
help="Use prebuilt knowledge-graph.json instead of live frontmatter")
args = parser.parse_args()
print(f"=== Searching: {args.query} ===")
@@ -92,10 +123,20 @@ def main():
for r in results:
print(f" [[{r}]]")
expanded = expand_nodes(results, depth=args.depth)
if args.use_graph and not GRAPH_DB.exists():
print(f"\n (note: {GRAPH_DB.name} not found, run `knowledge-graph.py build`; "
f"falling back to live frontmatter)")
if args.use_graph and GRAPH_DB.exists():
expanded = expand_nodes_via_graph(results, depth=args.depth)
source = "knowledge-graph.json"
else:
expanded = expand_nodes(results, depth=args.depth)
source = "live frontmatter"
new = [e for e in expanded if e not in results]
if new:
print(f"\nGraph-expanded (via relations, depth={args.depth}):")
print(f"\nGraph-expanded (via {source}, depth={args.depth}):")
for n in new[:args.count]:
print(f" [[{n}]]")
if len(new) > args.count: