from __future__ import annotations import html as html_lib from dataclasses import dataclass, field from pathlib import Path from sqlalchemy import text from examples.demand.db_manager import DatabaseManager db = DatabaseManager() SOURCE_TYPES = ["实质", "形式", "意图"] THEME = { "实质": {"root": "#e8841a", "mid": "#f0c389", "leaf": "#fae6cc", "line": "#d4a574"}, "形式": {"root": "#5b9bd5", "mid": "#a3c9e8", "leaf": "#daeaf8", "line": "#8cb9dc"}, "意图": {"root": "#70ad47", "mid": "#a9d18e", "leaf": "#dbefd0", "line": "#8fc270"}, } @dataclass class CatNode: id: int name: str source_stable_id: int | None source_type: str description: str | None level: int | None parent_id: int | None element_count: int children: list[CatNode] = field(default_factory=list) @property def subtree_element_count(self) -> int: total = self.element_count or 0 for c in self.children: total += c.subtree_element_count return total def fetch_categories(eid: int) -> list[dict]: session = db.get_session() try: rows = session.execute( text( "SELECT id, source_stable_id, source_type, name, description, " "level, parent_id, element_count " "FROM topic_pattern_category WHERE execution_id = :eid " "ORDER BY source_type, level, id" ), {"eid": eid}, ).mappings().fetchall() return [dict(r) for r in rows] finally: session.close() def build_trees(categories: list[dict]) -> dict[str, list[CatNode]]: nodes: dict[int, CatNode] = {} for c in categories: n = CatNode( id=c["id"], name=c["name"], source_stable_id=c.get("source_stable_id"), source_type=c["source_type"], description=c.get("description"), level=c.get("level"), parent_id=c.get("parent_id"), element_count=c.get("element_count") or 0, ) nodes[n.id] = n roots: dict[str, list[CatNode]] = {} for n in nodes.values(): if n.parent_id and n.parent_id in nodes: nodes[n.parent_id].children.append(n) else: roots.setdefault(n.source_type, []).append(n) for n in nodes.values(): n.children.sort(key=lambda x: x.id) return roots # --------------------------------------------------------------------------- # HTML rendering # --------------------------------------------------------------------------- def _node_html(n: CatNode, th: dict, depth: int = 0, is_root: bool = False) -> str: has_ch = bool(n.children) ec = n.element_count or 0 cc = len(n.children) if is_root: bg, tc = th["root"], "#fff" elif has_ch: bg, tc = th["mid"], "#4a3520" else: bg, tc = th["leaf"], "#6b5240" badge_inner: list[str] = [] if has_ch: badge_inner.append('\u25BC') badge_inner.append(f'{html_lib.escape(n.name)}') if n.source_stable_id is not None: badge_inner.append(f'{n.source_stable_id}') if ec: badge_inner.append(f'{ec}') if cc: badge_inner.append(f'{cc}\u25B6') onclick = ' onclick="tog(this)"' if has_ch else '' cls = "b e" if has_ch else "b" title = f' title="{html_lib.escape(n.description)}"' if n.description else "" h = f'