Spaces:
Running
Running
Case Zero - initial public release (fully local: Qwen2.5-1.5B via llama.cpp + Supertonic, custom pixel-noir SPA via gradio.Server)
414dc55 | """Visual provider abstraction. | |
| ``CompositeProvider`` renders procedural pixel art and caches PNGs to disk so each | |
| portrait/scene/prop is drawn once - instant, offline, deterministic, no model. | |
| """ | |
| from __future__ import annotations | |
| from pathlib import Path | |
| from typing import Protocol | |
| from ..config import Settings | |
| from ..constants import SPRITES_DIR | |
| from ..schemas.visual import VisualDescriptor | |
| from . import compositor | |
| from .cache import cached_png | |
| class VisualProvider(Protocol): | |
| is_local: bool | |
| def portrait_path(self, descriptor: VisualDescriptor | None, key: str) -> Path: ... | |
| def portrait_sheet_path(self, descriptor: VisualDescriptor | None, key: str) -> Path: ... | |
| def scene_path(self, name: str, key: str, accent: str | None = None) -> Path: ... | |
| def prop_path(self, name: str, key: str, accent: str | None = None) -> Path: ... | |
| class CompositeProvider: | |
| is_local = True | |
| def __init__(self, cache_dir: Path | None = None) -> None: | |
| self._cache = cache_dir or (SPRITES_DIR / "cache") | |
| def portrait_path(self, descriptor: VisualDescriptor | None, key: str) -> Path: | |
| accent = descriptor.accent_color if descriptor else "" | |
| mood = descriptor.mood if descriptor else "" | |
| return cached_png( | |
| self._cache, ("portrait", key, mood or "", accent or ""), | |
| lambda: compositor.render_portrait(descriptor, key), | |
| ) | |
| def portrait_sheet_path(self, descriptor: VisualDescriptor | None, key: str) -> Path: | |
| accent = descriptor.accent_color if descriptor else "" | |
| mood = descriptor.mood if descriptor else "" | |
| return cached_png( | |
| self._cache, ("sheet", key, mood or "", accent or ""), | |
| lambda: compositor.render_portrait_sheet(descriptor, key), | |
| ) | |
| def scene_path(self, name: str, key: str, accent: str | None = None) -> Path: | |
| return cached_png( | |
| self._cache, ("scene", key, name, accent or ""), | |
| lambda: compositor.render_scene(name, key, accent), | |
| ) | |
| def prop_path(self, name: str, key: str, accent: str | None = None) -> Path: | |
| return cached_png( | |
| self._cache, ("prop", key, name, accent or ""), | |
| lambda: compositor.render_prop(name, key, accent), | |
| ) | |
| def make_visual_provider(settings: Settings) -> VisualProvider: | |
| return CompositeProvider() | |