export.py · exporters/html.py · tree_html.py · callflow_html.pyexport.py 是 pipeline 的最後一站,把 NetworkX 圖變成各種檔案。最有名的是三個:graph.json(給查詢與其他工具)、GRAPH_REPORT.md(report.py 生成)、graph.html(互動視覺化)。本站 實作案例 的互動圖就是這個 exporter 的產物。
to_json 是 graphify 最重視資料安全的地方:
graph.json 存在且新圖節點數更少,拒絕覆寫。因為「新圖比較小」通常代表前一次 session 的 chunk 檔遺失、或 fuzzy dedup 誤併。讀不到既有檔(corrupt)時也 fail-safe——寧可不寫,也不讓局部重建覆蓋掉好的圖。community、community_name、norm_label(去掉重音符號的小寫 label,供檢索)。calls 等有向邊的端點順序搞反,build 時在 _src/_tgt 藏了真實端點,這裡還原(issue #563)。write_json_atomic() 原子寫入——中途當機不會截斷好的 graph.json。段落式說明:--obsidian flag 的實作。為每個社群產生一篇 _COMMUNITY_<name>.md,節點之間用 Obsidian wikilink([[…]])互連——這樣你在 Obsidian 的 graph view 直接看到整個知識圖譜。檔名用 _obsidian_safe_stem 安全化、_dedup_node_filenames 避免同名檔衝突、frontmatter 用 _yaml_str 防注入(與 security 對應)。
段落式說明:
to_cypher(G, path) — 產生 cypher.txt(Neo4j / FalkorDB 匯入),_cypher_escape / _cypher_label 處理 Cypher 字串與 label 安全。to_graphml(G, path) — 輸出 GraphML(Gephi / yEd)。to_svg(G, path) — SVG 圖(Notion / GitHub 內嵌)。to_canvas(G, …) — Obsidian Canvas 輸出。backup_if_protected(out_dir) — 目標目錄受保護時先備份。這就是本站 實作案例 互動圖的生成器。輸出是單一自含 HTML:
RAW_NODES / RAW_EDGES / LEGEND)寫進 <script>。vis-network(unpkg CDN)以 forceAtlas2Based 物理引擎畫力導向圖。_hyperedge_script 在 canvas afterDrawing 時畫半透明群組區域。esc() 才進 innerHTML——這呼應 SECURITY.md 的 XSS 緩解。<details> 都能理解的單一檔案。本站的 graph-zh.html 就是對它的產物做 UI 字串中文化。段落式說明:
_html_styles() — 回傳內嵌 CSS 字串(深色主題、側欄、圖例)。_html_script(nodes_json, edges_json, legend_json) — 組出全部渲染 JS(dataset 建立、network 選項、搜尋、點選、圖例互動)。_viz_node_limit() — 節點上限防護(超過就不生成 HTML,避免瀏覽器開不動)。_hyperedge_script(hyperedges_json) — 超邊的 canvas 疊加渲染。段落式說明:build_tree(paths) 把檔案路徑清單組成一棵樹(_common_root 找出共同根、_make_truncation_leaf 處理過多子節點),emit_html / write_tree_html 渲染成自含 HTML。這讓瀏覽者先看到專案結構,再進圖。
段落式說明:graphify export callflow-html 的實作。讀取圖資料(load_graph),把節點/邊正規化成統一形狀(normalize_node / normalize_edge),最後渲染成含 Mermaid 圖的 HTML。裝了 hook 時,每次 git commit 都會自動重新生成。
前面是「看 shrink guard 的原理」;這次是跨工具的分發場景:同一份知識圖譜,要同時給「網頁瀏覽者、Obsidian 使用者、Neo4j 分析師、CI 報告」四種角色。
graphify export(或預設產出)給互動圖;確認節點數低於 _viz_node_limit,太大就分流。graphify export --obsidian——每社群一篇 _COMMUNITY_<name>.md,節點間用 [[wikilink]] 互連;檔名安全化(_obsidian_safe_stem)避免跳字與同名衝突,frontmatter 走 _yaml_str 防注入。graphify export --neo4j 給 to_cypher 的產物,讓圖論分析直接在資料庫跑(Cypher 字串與 label 都有 _cypher_escape 保護)。--svg 給 Notion/GitHub 內嵌,--graphml 給 Gephi/yEd 做深度視覺化。built_at_commit 記在 graph.json,確保四份輸出都標明「由哪個 commit 產生」,不會有人拿過期圖做決策。export 頁最被低估的是一堆「寫檔防護」——它們是「圖被自己搞壞」的最後防線:
write_json_atomic() 先寫暫存再 rename——中途當機不會截斷好的 graph.json。這跟 serve 的 _load_graph 復原訊息搭配:壞檔不會默默產生。calls 這類有向邊的端點順序搞反,build 時在 _src/_tgt 藏了真實端點,export 時還原——否則「誰呼叫誰」會倒反。esc() 才進 innerHTML(XSS 緩解),與 security 的 sanitize_label 對應。community、community_name、norm_label(小寫去重音,供檢索);邊補 _src/_tgt 還原方向;還會因 shrink guard 拒絕寫入。若你拿「export 後的 graph.json」直接當建圖輸入重跑,會看到多餘屬性、甚至格式不相容——export 的產物是「給消費者讀的」,不是「給 pipeline 吃的」。想重跑要用原始 extraction/chunk 檔。| 症狀 | 可能原因 | 解決方案 |
|---|---|---|
to_json 回傳 False、檔案沒更新 | shrink guard 擋下(新圖更小)或既有檔損壞讀不到 | 檢查上一輪 chunk 檔是否遺失;確認後再 --force;不要盲推 --force |
| graph.json 半截/格式壞掉 | 舊版沒走原子寫,或外部工具覆寫 | 重新 export;確認 write_json_atomic 生效;serve 會印復原訊息 |
| Obsidian vault 出現斷鏈 wikilink | 節點 label 含不安全的檔名字元(/、空格、跳字) | 確認 _obsidian_safe_stem 與 _dedup_node_filenames 有走;重跑 export |
| 互動圖無法生成 | 節點數超過 _viz_node_limit(瀏覽器開不動) | 縮小語料、用社群篩選、或改用 SVG/GraphML |
| Neo4j 匯入報語法錯誤 | label 含特殊字元、Cypher 字串沒 escape | 確認 _cypher_escape/_cypher_label 有走;檢查產物 cypher.txt 內容 |