Files
llm_wiki/tools/scripts/graph-search.py
T
hehaiguang1123 a6f05ab2d5 Phase 0-2: Schema cleanup, typed relations, event-driven automation
- Phase 0: AGENTS.md cleanup (dedup quotes, renumber sections, merge qmd)
- Phase 1: typed relations (manage-relations.py, graph-search.py, check-staleness.py, detect-conflicts.py)
- Phase 2: frontmatter validator, weekly lint, knowledge promotion, git hooks
- Fix .gitignore to track tools/ and .githooks/
- Fix git remote URL (remove plaintext token)
- New wiki pages: 504 pages, 34 raw sources
2026-07-01 08:05:43 +08:00

109 lines
3.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
graph-search.py — 图感知搜索
流程:
1. qmd vsearch 获取语义匹配结果(Top 10)
2. 对每个结果,读取 relations 字段 → 获取相邻节点
3. 去重后返回(直接关联 + 关系扩展)
用法:
python tools/scripts/graph-search.py "查询词" [--count 15] [--depth 1]
依赖:
- qmd 已安装(通过 node
"""
import argparse
import json
import re
import subprocess
import sys
from pathlib import Path
try:
import yaml
except ImportError:
yaml = None
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")
def qmd_search(query: str, count: int = 10) -> list[str]:
"""调用 qmd vsearch 获取匹配的页面名列表"""
cmd = f'{QMD} vsearch "{query}" -c wiki -n {count}'
result = subprocess.run(cmd, capture_output=True, text=True, shell=True, timeout=30)
lines = [line.strip() for line in result.stdout.splitlines() if line.strip()]
return lines
def get_relations(page_name: str) -> list[dict]:
"""读取页面的 relations 字段"""
fp = WIKI / f"{page_name}.md"
if not fp.exists():
return []
content = fp.read_text(encoding="utf-8")
m = re.match(r"^---\n(.*?)\n---", content, re.DOTALL)
if not m:
return []
if not yaml:
return []
try:
front = yaml.safe_load(m.group(1)) or {}
except:
return []
return front.get("relations", [])
def expand_nodes(nodes: list[str], depth: int = 1) -> list[str]:
"""从起始节点出发,沿 relations 扩展相邻节点"""
expanded = list(nodes)
frontier = list(nodes)
for _ in range(depth):
next_frontier = []
for node in frontier:
rels = get_relations(node)
for r in rels:
target = r.get("target", "").strip("[]")
if target 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")
args = parser.parse_args()
print(f"=== Searching: {args.query} ===")
results = qmd_search(args.query, count=max(10, args.count))
if not results:
print(" No results from qmd")
return
print(f"\nDirect matches ({len(results)}):")
for r in results:
print(f" [[{r}]]")
expanded = expand_nodes(results, depth=args.depth)
new = [e for e in expanded if e not in results]
if new:
print(f"\nGraph-expanded (via relations, depth={args.depth}):")
for n in new[:args.count]:
print(f" [[{n}]]")
if len(new) > args.count:
print(f" ... and {len(new) - args.count} more")
print(f"\nTotal unique: {len(expanded)}")
if __name__ == "__main__":
main()