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