提交
This commit is contained in:
1 parent
e6072457fd
commit
be4fab78e1
578 files changed
+174415
-214
No files matched your search
Executable
+201
@@ -0,0 +1,201 @@
|
||||
#!/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
|
||||
|
||||
extraction = json.loads(Path('graphify-out/.graphify_extract.json').read_text()) if Path('graphify-out/.graphify_extract.json').exists() else None
|
||||
if extraction is None:
|
||||
print('ERROR: No existing extraction found. Run full build first.')
|
||||
sys.exit(1)
|
||||
|
||||
# Re-extract AST for all code files (fast, deterministic)
|
||||
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
|
||||
to_html(G, communities, 'graphify-out/graph.html', community_labels=labels or None)
|
||||
|
||||
# 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
|
||||
rm -f graphify-out/.graphify_detect.json graphify-out/.graphify_extract.json graphify-out/.graphify_ast.json graphify-out/.graphify_incremental.json graphify-out/.graphify_analysis.json graphify-out/.graphify_labels.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"
|
||||
Reference in new issue
Block a user