Graph viewer: viz.html z knowledge-catalog + skrypt generujący
Viewer jest samowystarczalny — bundle jest wpiekany do HTML jako window.BUNDLE (nodes/edges/bodies), nie ma odczytu .md w runtime, więc nie potrzeba manifestu ani konkretnej ścieżki serwowania. Źródłem danych jest gen_viz.py, uruchamiany po zmianach w bundle'u. Logika viewera (viz.js, viz.css, szkielet templates/viz.html) wstawiona dosłownie z upstreamu — zweryfikowane bajt w bajt. gen_viz.py koryguje wyłącznie zbieranie danych, w dwóch miejscach niezgodnych ze spec: - _extract_links pomijał linki bundle-relative "/..." (generator.py:74), czyli formę zalecaną w §5.1 — bundle zgodny ze spec dawał graf z 0 krawędzi. Sam viewer te linki rozumie (viz.js:297). - _walk_concepts pomijał tylko index.md, więc zarezerwowany log.md trafiał do grafu jako koncept typu "Unknown" (wbrew §3.1). Wynik: 9 konceptów, 9 krawędzi (było 9 i 0). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
e3b50cd43e
commit
7ef5c34e52
100
gen_viz.py
Normal file
100
gen_viz.py
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Generuje viz.html (graph viewer) dla tego bundle'a.
|
||||
|
||||
Viewer z GoogleCloudPlatform/knowledge-catalog jest samowystarczalny: cały
|
||||
bundle jest wpiekany do pliku HTML jako `window.BUNDLE` (nodes/edges/bodies).
|
||||
Nie czyta plików .md w runtime, więc nie potrzebuje manifestu ani serwera —
|
||||
źródłem danych jest ten skrypt, uruchamiany po każdej zmianie bundle'a.
|
||||
|
||||
Logika viewera (templates/viz.html, static/viz.js, static/viz.css) jest
|
||||
wstawiana dosłownie, bez zmian. Skrypt koryguje wyłącznie warstwę zbierania
|
||||
danych, w dwóch punktach, w których upstreamowy generator rozmija się ze
|
||||
specyfikacją OKF:
|
||||
|
||||
1. `_extract_links` pomija linki bundle-relative zaczynające się od `/`
|
||||
(generator.py:74), czyli dokładnie formę zalecaną przez §5.1. Bundle
|
||||
trzymający się zalecenia dostaje graf bez krawędzi. Sam viewer te linki
|
||||
rozumie — viz.js:297 rozwiązuje `/...md` na węzeł — więc dokładamy je do
|
||||
ekstrakcji krawędzi.
|
||||
2. `_walk_concepts` pomija tylko `index.md`, przez co zarezerwowany `log.md`
|
||||
ląduje w grafie jako koncept typu "Unknown". Wg §3.1 zarezerwowane nazwy
|
||||
nie są konceptami.
|
||||
|
||||
Wymaga: PyYAML oraz repozytorium knowledge-catalog (domyślnie
|
||||
/tmp/knowledge-catalog — nadpisz zmienną KNOWLEDGE_CATALOG).
|
||||
|
||||
Uruchomienie: python3 gen_viz.py
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
BUNDLE_ROOT = Path(__file__).resolve().parent
|
||||
BUNDLE_NAME = "Ski 2027 — Skicircus Saalbach"
|
||||
CATALOG = Path(os.environ.get("KNOWLEDGE_CATALOG", "/tmp/knowledge-catalog"))
|
||||
|
||||
sys.path.insert(0, str(CATALOG / "okf" / "src"))
|
||||
|
||||
try:
|
||||
from reference_agent.viewer import generator as G
|
||||
except ModuleNotFoundError as exc: # pragma: no cover
|
||||
sys.exit(
|
||||
f"Nie znaleziono viewera ({exc}).\n"
|
||||
f"Sklonuj: git clone https://github.com/GoogleCloudPlatform/"
|
||||
f"knowledge-catalog {CATALOG}"
|
||||
)
|
||||
|
||||
RESERVED = {"index.md", "log.md"}
|
||||
|
||||
_upstream_extract_links = G._extract_links
|
||||
_upstream_walk_concepts = G._walk_concepts
|
||||
|
||||
|
||||
def _extract_links(body: str, doc_dir: Path, bundle_root: Path) -> list[str]:
|
||||
"""Upstream + linki bundle-relative (§5.1), które upstream odrzuca."""
|
||||
out = _upstream_extract_links(body, doc_dir, bundle_root)
|
||||
seen = set(out)
|
||||
for match in G._LINK_RE.finditer(body):
|
||||
target = match.group(1)
|
||||
if "://" in target or not target.startswith("/"):
|
||||
continue
|
||||
rel = target[1:]
|
||||
if rel.endswith(".md"):
|
||||
rel = rel[:-3]
|
||||
if rel and rel not in seen:
|
||||
seen.add(rel)
|
||||
out.append(rel)
|
||||
return out
|
||||
|
||||
|
||||
def _walk_concepts(bundle_root: Path):
|
||||
"""Upstream, ale bez plików zarezerwowanych (§3.1)."""
|
||||
return [
|
||||
c
|
||||
for c in _upstream_walk_concepts(bundle_root)
|
||||
if f"{c.id}.md".rsplit("/", 1)[-1] not in RESERVED
|
||||
]
|
||||
|
||||
|
||||
G._extract_links = _extract_links
|
||||
G._walk_concepts = _walk_concepts
|
||||
|
||||
|
||||
def main() -> int:
|
||||
out_path = BUNDLE_ROOT / "viz.html"
|
||||
stats = G.generate_visualization(
|
||||
BUNDLE_ROOT, out_path, bundle_name=BUNDLE_NAME
|
||||
)
|
||||
print(f"Zapisano {out_path}")
|
||||
print(
|
||||
f" koncepty: {stats['concepts']}, krawędzie: {stats['edges']}, "
|
||||
f"rozmiar: {stats['bytes'] / 1024:.1f} KiB"
|
||||
)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Loading…
Reference in a new issue