| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- #!/bin/bash
- # update-graph.sh — 增量更新知识图谱
- # 用法:
- # ./scripts/update-graph.sh # 更新前后端
- # ./scripts/update-graph.sh backend # 只更新后端
- # ./scripts/update-graph.sh frontend # 只更新前端
- #
- # 由 AI Agent 在完成代码修改后自动调用,或手动执行。
- set -euo pipefail
- ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
- PYTHON=""
- # 检测 graphify 使用的 Python 解释器
- detect_python() {
- local graphify_out="$1/graphify-out/.graphify_python"
- if [ -f "$graphify_out" ]; then
- PYTHON="$(cat "$graphify_out")"
- else
- PYTHON="python3"
- fi
- }
- # 检查 graphify 是否安装
- check_graphify() {
- if ! "$PYTHON" -c "import graphify" 2>/dev/null; then
- echo "[graphify] 未安装,正在安装..."
- "$PYTHON" -m pip install graphifyy -q 2>/dev/null || "$PYTHON" -m pip install graphifyy -q --break-system-packages 2>&1 | tail -3
- fi
- }
- # 增量更新单个项目的图谱
- update_graph() {
- local name="$1"
- local src_dir="$2"
- local label="$3"
- echo ""
- echo "=== 更新 ${label} 知识图谱 (${src_dir}) ==="
- detect_python "$ROOT_DIR/$name"
- check_graphify
- cd "$ROOT_DIR/$name"
- local detect_json="graphify-out/.graphify_detect.json"
- local manifest_json="graphify-out/manifest.json"
- if [ ! -f "$manifest_json" ]; then
- echo "[graphify] 未找到 manifest.json,跳过增量更新(首次需运行完整构建)"
- return 0
- fi
- # 运行增量检测
- "$PYTHON" -c "
- import sys, json
- from graphify.detect import detect_incremental, save_manifest
- from pathlib import Path
- result = detect_incremental(Path('${src_dir}'))
- new_total = result.get('new_total', 0)
- Path('graphify-out/.graphify_incremental.json').write_text(json.dumps(result))
- print(f'{new_total} file(s) changed since last run.')
- if new_total == 0:
- print('SKIP: Nothing to update.')
- sys.exit(0)
- "
- # 如果没有变化,跳过
- local changed=$?
- if [ $changed -ne 0 ]; then
- return 0
- fi
- # 检查是否只是代码变更
- "$PYTHON" -c "
- import json
- from pathlib import Path
- result = json.loads(Path('graphify-out/.graphify_incremental.json').read_text())
- code_exts = {'.py','.ts','.js','.vue','.go','.rs','.java','.cpp','.c','.rb','.swift','.kt','.cs','.scala','.php','.cc','.cxx','.hpp','.h','.kts'}
- new_files = result.get('new_files', {})
- all_changed = [f for files in new_files.values() for f in files]
- code_only = all(Path(f).suffix.lower() in code_exts for f in all_changed) if all_changed else True
- print('code_only:', code_only)
- " 2>/dev/null
- # AST 提取
- "$PYTHON" -c "
- import sys, json
- from graphify.extract import collect_files, extract
- from graphify.build import build_from_json
- from graphify.cluster import cluster, score_all
- from graphify.analyze import god_nodes, surprising_connections, suggest_questions
- from graphify.report import generate
- from graphify.export import to_json, to_html
- from pathlib import Path
- # Re-extract AST for all code files (fast, deterministic)
- # 注:不依赖旧的 .graphify_extract.json;缺失时从头提取即可
- from graphify.detect import detect
- detection = detect(Path('${src_dir}'))
- Path('graphify-out/.graphify_detect.json').write_text(json.dumps(detection))
- code_files = []
- for f in detection.get('files', {}).get('code', []):
- code_files.extend(collect_files(Path(f)) if Path(f).is_dir() else [Path(f)])
- if code_files:
- result = extract(code_files)
- Path('graphify-out/.graphify_extract.json').write_text(json.dumps(result, indent=2))
- print(f'AST: {len(result[\"nodes\"])} nodes, {len(result[\"edges\"])} edges')
- else:
- print('No code files found.')
- sys.exit(1)
- # Build graph
- G = build_from_json(result)
- communities = cluster(G)
- cohesion = score_all(G, communities)
- tokens = {'input': 0, 'output': 0}
- gods = god_nodes(G)
- surprises = surprising_connections(G, communities)
- # Try to load existing labels
- labels = {}
- labels_path = Path('graphify-out/.graphify_labels.json')
- if labels_path.exists():
- labels_raw = json.loads(labels_path.read_text())
- labels = {int(k): v for k, v in labels_raw.items()}
- else:
- labels = {cid: f'Community {cid}' for cid in communities}
- questions = suggest_questions(G, communities, labels)
- # Generate outputs
- report = generate(G, communities, cohesion, labels, gods, surprises, detection, tokens, '${src_dir}', suggested_questions=questions)
- Path('graphify-out/GRAPH_REPORT.md').write_text(report)
- to_json(G, communities, 'graphify-out/graph.json')
- # Save analysis for labels
- analysis = {
- 'communities': {str(k): v for k, v in communities.items()},
- 'cohesion': {str(k): v for k, v in cohesion.items()},
- 'gods': gods,
- 'surprises': surprises,
- }
- Path('graphify-out/.graphify_analysis.json').write_text(json.dumps(analysis, indent=2))
- Path('graphify-out/.graphify_labels.json').write_text(json.dumps({str(k): v for k, v in labels.items()}))
- # Generate HTML(节点过多时跳过可视化,仍保存 json/report)
- try:
- to_html(G, communities, 'graphify-out/graph.html', community_labels=labels or None)
- except ValueError as e:
- print(f'[graphify] skip HTML viz: {e}')
- # Save manifest
- from graphify.detect import save_manifest
- save_manifest(detection['files'])
- print(f'Graph updated: {G.number_of_nodes()} nodes, {G.number_of_edges()} edges, {len(communities)} communities')
- print(f'Report: graphify-out/GRAPH_REPORT.md')
- " || {
- echo "[graphify] 增量更新失败"
- return 1
- }
- # Cleanup temp files(保留 .graphify_extract.json 供下次增量更新)
- rm -f graphify-out/.graphify_detect.json graphify-out/.graphify_ast.json graphify-out/.graphify_incremental.json
- cd "$ROOT_DIR"
- echo "[graphify] ${label} 图谱更新完成 ✓"
- }
- # ---- Main ----
- TARGET="${1:-all}"
- echo "╔══════════════════════════════════════╗"
- echo "║ zkxw 知识图谱增量更新工具 ║"
- echo "╚══════════════════════════════════════╝"
- case "$TARGET" in
- backend)
- update_graph "backend" "app" "后端"
- ;;
- frontend)
- update_graph "web-admin" "src" "前端"
- ;;
- all|"")
- update_graph "backend" "app" "后端"
- update_graph "web-admin" "src" "前端"
- ;;
- *)
- echo "用法: $0 [backend|frontend|all]"
- exit 1
- ;;
- esac
- echo ""
- echo "✅ 知识图谱更新完毕。HTML 可视化: */graphify-out/graph.html"
|