#!/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())