Spaces:
Runtime error
Runtime error
| """Web UI section registry. | |
| Every known section/block is registered here. To disable something, set | |
| ``enabled=False`` (sections) or ``skip=True`` (narrative blocks) — do not delete | |
| entries. Removed ids are re-added automatically as disabled so they can be | |
| turned back on later via ``with_section_enabled`` / ``with_narrative_block_skip``. | |
| """ | |
| from __future__ import annotations | |
| from dataclasses import dataclass, replace | |
| from enum import StrEnum | |
| from typing import Any | |
| class WebSectionId(StrEnum): | |
| """Top-level blocks in the results panel.""" | |
| PLAYER_BANNER = "player_banner" | |
| STYLE_SCALE = "style_scale" | |
| STYLE_TRAITS = "style_traits" | |
| TSNE_PLOT = "tsne_plot" | |
| ELO_TSNE_PLOT = "elo_tsne_plot" | |
| NARRATIVE = "narrative" | |
| OPENINGS = "openings" | |
| PUZZLES = "puzzles" | |
| class NarrativeBlockId(StrEnum): | |
| """Narrative subsections filtered out of ``narrative_sections``.""" | |
| COACHING_REPORT = "coaching_report" | |
| COHORT_TENDENCY = "cohort_tendency" | |
| OPENING_DUPLICATE = "opening_duplicate" | |
| PUZZLE_DUPLICATE = "puzzle_duplicate" | |
| class WebSectionSpec: | |
| id: WebSectionId | |
| enabled: bool | |
| order: int | |
| label: str = "" | |
| class NarrativeBlockSpec: | |
| id: NarrativeBlockId | |
| """When ``True``, matching narrative blocks are omitted from the web payload.""" | |
| skip: bool | |
| # Canonical registry — keep every section here; toggle ``enabled`` instead of deleting. | |
| _SECTION_REGISTRY: dict[WebSectionId, WebSectionSpec] = { | |
| WebSectionId.PLAYER_BANNER: WebSectionSpec( | |
| WebSectionId.PLAYER_BANNER, True, 10, "Player summary" | |
| ), | |
| WebSectionId.STYLE_SCALE: WebSectionSpec( | |
| WebSectionId.STYLE_SCALE, True, 20, "Playing style" | |
| ), | |
| WebSectionId.TSNE_PLOT: WebSectionSpec( | |
| WebSectionId.TSNE_PLOT, True, 30, "Playstyle map (t-SNE)" | |
| ), | |
| WebSectionId.ELO_TSNE_PLOT: WebSectionSpec( | |
| WebSectionId.ELO_TSNE_PLOT, True, 40, "Rating vs t-SNE" | |
| ), | |
| WebSectionId.STYLE_TRAITS: WebSectionSpec( | |
| WebSectionId.STYLE_TRAITS, True, 50, "Playstyle changes" | |
| ), | |
| WebSectionId.NARRATIVE: WebSectionSpec( | |
| WebSectionId.NARRATIVE, True, 60, "Coaching narrative" | |
| ), | |
| WebSectionId.OPENINGS: WebSectionSpec( | |
| WebSectionId.OPENINGS, True, 70, "Top opening positions" | |
| ), | |
| WebSectionId.PUZZLES: WebSectionSpec( | |
| WebSectionId.PUZZLES, True, 80, "Puzzle practice" | |
| ), | |
| } | |
| _NARRATIVE_BLOCK_REGISTRY: dict[NarrativeBlockId, NarrativeBlockSpec] = { | |
| NarrativeBlockId.COACHING_REPORT: NarrativeBlockSpec( | |
| NarrativeBlockId.COACHING_REPORT, skip=True | |
| ), | |
| NarrativeBlockId.COHORT_TENDENCY: NarrativeBlockSpec( | |
| NarrativeBlockId.COHORT_TENDENCY, skip=True | |
| ), | |
| NarrativeBlockId.OPENING_DUPLICATE: NarrativeBlockSpec( | |
| NarrativeBlockId.OPENING_DUPLICATE, skip=True | |
| ), | |
| NarrativeBlockId.PUZZLE_DUPLICATE: NarrativeBlockSpec( | |
| NarrativeBlockId.PUZZLE_DUPLICATE, skip=True | |
| ), | |
| } | |
| # Active layout — edit ``enabled`` / ``order`` on registry entries, or pass overrides | |
| # to ``resolve_web_layout``. Entries must not be removed from the registries above. | |
| DEFAULT_WEB_UI_LAYOUT: tuple[WebSectionSpec, ...] = tuple( | |
| sorted(_SECTION_REGISTRY.values(), key=lambda s: s.order) | |
| ) | |
| DEFAULT_NARRATIVE_BLOCK_FILTERS: tuple[NarrativeBlockSpec, ...] = tuple( | |
| _NARRATIVE_BLOCK_REGISTRY.values() | |
| ) | |
| def resolve_web_layout( | |
| overrides: tuple[WebSectionSpec, ...] | None = None, | |
| ) -> tuple[WebSectionSpec, ...]: | |
| """Merge optional overrides onto the canonical section registry.""" | |
| merged = dict(_SECTION_REGISTRY) | |
| if overrides is not None: | |
| for spec in overrides: | |
| merged[spec.id] = spec | |
| return tuple(sorted(merged.values(), key=lambda s: s.order)) | |
| def resolve_narrative_block_filters( | |
| overrides: tuple[NarrativeBlockSpec, ...] | None = None, | |
| ) -> tuple[NarrativeBlockSpec, ...]: | |
| """Merge optional overrides onto the canonical narrative block registry.""" | |
| merged = dict(_NARRATIVE_BLOCK_REGISTRY) | |
| if overrides is not None: | |
| for spec in overrides: | |
| merged[spec.id] = spec | |
| return tuple(merged.values()) | |
| def ensure_complete_layout( | |
| layout: tuple[WebSectionSpec, ...] | None = None, | |
| ) -> tuple[WebSectionSpec, ...]: | |
| """Return a full layout with every ``WebSectionId`` (disabled if omitted).""" | |
| partial = {spec.id: spec for spec in (layout or ())} | |
| complete: list[WebSectionSpec] = [] | |
| for sid, default in _SECTION_REGISTRY.items(): | |
| if sid in partial: | |
| complete.append(partial[sid]) | |
| else: | |
| complete.append(replace(default, enabled=False)) | |
| return tuple(sorted(complete, key=lambda s: s.order)) | |
| def ensure_complete_narrative_filters( | |
| filters: tuple[NarrativeBlockSpec, ...] | None = None, | |
| ) -> tuple[NarrativeBlockSpec, ...]: | |
| """Return all narrative block filters (not skipped if omitted).""" | |
| partial = {spec.id: spec for spec in (filters or ())} | |
| complete: list[NarrativeBlockSpec] = [] | |
| for bid, default in _NARRATIVE_BLOCK_REGISTRY.items(): | |
| if bid in partial: | |
| complete.append(partial[bid]) | |
| else: | |
| complete.append(replace(default, skip=False)) | |
| return tuple(complete) | |
| def with_section_enabled( | |
| layout: tuple[WebSectionSpec, ...], | |
| section_id: WebSectionId | str, | |
| *, | |
| enabled: bool, | |
| ) -> tuple[WebSectionSpec, ...]: | |
| """Return a copy of ``layout`` with one section enabled or disabled.""" | |
| sid = WebSectionId(section_id) | |
| base = ensure_complete_layout(layout) | |
| return tuple( | |
| replace(spec, enabled=enabled) if spec.id == sid else spec for spec in base | |
| ) | |
| def with_narrative_block_skip( | |
| filters: tuple[NarrativeBlockSpec, ...], | |
| block_id: NarrativeBlockId | str, | |
| *, | |
| skip: bool, | |
| ) -> tuple[NarrativeBlockSpec, ...]: | |
| """Return a copy of ``filters`` with one narrative block shown or hidden.""" | |
| bid = NarrativeBlockId(block_id) | |
| base = ensure_complete_narrative_filters(filters) | |
| return tuple( | |
| replace(spec, skip=skip) if spec.id == bid else spec for spec in base | |
| ) | |
| def ui_layout_config( | |
| *, | |
| sections: tuple[WebSectionSpec, ...] | None = None, | |
| narrative_blocks: tuple[NarrativeBlockSpec, ...] | None = None, | |
| ) -> dict[str, Any]: | |
| """Serializable layout for the frontend and API consumers.""" | |
| resolved_sections = ensure_complete_layout( | |
| resolve_web_layout(sections) if sections is not None else DEFAULT_WEB_UI_LAYOUT | |
| ) | |
| resolved_blocks = ensure_complete_narrative_filters( | |
| resolve_narrative_block_filters(narrative_blocks) | |
| if narrative_blocks is not None | |
| else DEFAULT_NARRATIVE_BLOCK_FILTERS | |
| ) | |
| return { | |
| "sections": [ | |
| { | |
| "id": spec.id.value, | |
| "enabled": spec.enabled, | |
| "order": spec.order, | |
| "label": spec.label, | |
| } | |
| for spec in resolved_sections | |
| ], | |
| "narrative_blocks": [ | |
| {"id": block.id.value, "skip": block.skip} | |
| for block in resolved_blocks | |
| ], | |
| } | |
| def section_enabled( | |
| section_id: WebSectionId | str, | |
| *, | |
| layout: tuple[WebSectionSpec, ...] = DEFAULT_WEB_UI_LAYOUT, | |
| ) -> bool: | |
| sid = WebSectionId(section_id) | |
| for spec in ensure_complete_layout(layout): | |
| if spec.id == sid: | |
| return spec.enabled | |
| return False | |
| def narrative_block_skipped( | |
| block_id: NarrativeBlockId | str, | |
| *, | |
| filters: tuple[NarrativeBlockSpec, ...] | None = None, | |
| ) -> bool: | |
| bid = NarrativeBlockId(block_id) | |
| resolved = ensure_complete_narrative_filters( | |
| filters if filters is not None else DEFAULT_NARRATIVE_BLOCK_FILTERS | |
| ) | |
| for spec in resolved: | |
| if spec.id == bid: | |
| return spec.skip | |
| return False | |
| def enabled_section_ids_ordered( | |
| layout: tuple[WebSectionSpec, ...] = DEFAULT_WEB_UI_LAYOUT, | |
| ) -> list[str]: | |
| return [ | |
| spec.id.value | |
| for spec in ensure_complete_layout(layout) | |
| if spec.enabled | |
| ] | |