"""Renderiza un grafo sigma.js como HTML standalone con dark theme y layout ForceAtlas2.""" import json import os _HTML_TEMPLATE = """\ {title}

{title}

""" def render_sigma_html( graph_data: dict, output_path: str, title: str = "OSINT Graph", ) -> str: """Genera un HTML standalone con sigma.js que visualiza el grafo OSINT. Recibe el dict producido por ops_to_sigma_json, embebe los datos como JSON en el HTML, aplica ForceAtlas2 (500 iteraciones sincrono) y renderiza con sigma.js v2.4. Incluye dark theme, panel de filtros por tipo de nodo y tooltip con metadata al hacer hover. Args: graph_data: Dict con claves 'nodes' y 'edges' en formato graphology/sigma. output_path: Ruta del archivo HTML a escribir. title: Titulo del grafo mostrado en el panel y la pestana. Returns: Ruta absoluta del archivo HTML escrito. Raises: Exception: Si no se puede escribir el archivo en output_path. """ json_data = json.dumps(graph_data, ensure_ascii=False) html = _HTML_TEMPLATE.format( title=title, json_data=json_data, ) abs_path = os.path.abspath(output_path) os.makedirs(os.path.dirname(abs_path) or ".", exist_ok=True) try: with open(abs_path, "w", encoding="utf-8") as f: f.write(html) except OSError as exc: raise Exception(f"render_sigma_html: no se pudo escribir '{abs_path}': {exc}") from exc return abs_path