Spaces:
Paused
Paused
| title: Catbox | |
| sdk: docker | |
| app_port: 7860 | |
| # catBox | |
| Catbox is an interactive image-generation demo. You open a sealed box, a local | |
| image model runs, and the box turns into either a cozy cat scene or an eerie | |
| lifeless-cat scene. | |
| ## What this project is | |
| Catbox is a thin local product slice around a real image model. The user-facing | |
| experience is intentionally small: the Browser UI starts from a sealed box, the | |
| user observes it, and the local Model Backend generates one real Generated | |
| Outcome. The outcome is either a Living-Cat Outcome or a Dead-Cat Outcome. | |
| The project is not a static reveal, a canvas-only animation, a gallery, or a | |
| prompt playground. The normal path does not let the Browser UI choose the | |
| outcome or tune generation. Those controls exist only in development paths for | |
| validation and reproducibility. | |
| ## Why this exists | |
| The model spike showed that `sd_turbo_img2img` can create recognizable cat and | |
| empty-box images after the model is loaded; Catbox now uses that same path for a | |
| living-cat branch and a non-graphic dead-cat branch. This backend turns that | |
| experiment into code the rest of Catbox can use: | |
| - the browser asks to observe the box instead of choosing the result itself; | |
| - the backend is the source of truth for which scene was chosen; | |
| - Dev Controls can force `living` or `dead` without changing normal | |
| observation behavior; | |
| - Dev Controls can pass a seed and generation settings to reproduce a run; | |
| - generated images are returned as local file paths plus details about the run; | |
| - real intermediate frames can be captured as a single-branch Captured | |
| Denoising Trace when the runner supports it; | |
| - failures stay visible instead of being hidden behind placeholder images. | |
| Catbox v1 treats generated files as Ephemeral Outcomes. They may exist locally | |
| long enough for display and debugging, but the product does not provide | |
| gallery/history/save/share behavior. | |
| ## Model backend and Browser UI | |
| The current code defines the small Python boundary that the Browser UI calls: | |
| - `readiness()` says whether the model backend is ready. | |
| - `observe()` is the normal path. The backend chooses which scene to generate. | |
| - `observe_with_dev_controls(...)` is for development only. It can force the | |
| living-cat scene or the dead-cat scene, and it can reuse a seed or generation | |
| settings. | |
| - Successful observations return the chosen scene, a local image file path, | |
| timing details, and a short note for the reveal. | |
| - Failed observations return a clear error instead of pretending that an image | |
| was generated. | |
| The SD Turbo runner is the real product path for the first Model Backend. It | |
| loads `stabilityai/sd-turbo` once, loads the shared Box Composition, picks the | |
| right Outcome Prompt, writes an ephemeral generated image under `.runtime/`, and | |
| returns the local file path plus generation metadata through the backend | |
| contract. | |
| The fake runner is only for tests and early wiring. It lets the backend behavior | |
| be checked quickly without CUDA, model downloads, or slow image generation. | |
| The local Browser UI is served by `python -m catbox.browser_ui`. It is a | |
| full-screen sealed-system interface rather than a card-based demo. It sends a | |
| normal observation request without choosing an outcome, polls for real Captured | |
| Denoising Trace frames while the Model Backend runs, and reveals the generated | |
| image only after the backend-provided local file reference has loaded. | |
| Observation Noise remains a fallback before the first captured frame appears, | |
| and the trace surface is intentionally treated as a secondary instrument view | |
| instead of competing with the final Generated Outcome. The Browser UI keeps | |
| each state in normal document flow so the header, apparatus view, status text, | |
| and controls do not overlap. When the generated outcome loads, the page scrolls | |
| the revealed apparatus into view so the image is visible inside the viewport, | |
| with the final image presented as the dominant visual state. The Browser UI | |
| keeps the Model Backend authoritative, shows the Reveal Note, and supports Reset | |
| back to the sealed box. If generation fails, the Browser UI shows Generation | |
| Failure with Retry and Reset instead of registering or serving a fake generated | |
| image. | |
| ## How the project fits together | |
| - `catbox/model_backend.py` owns readiness, Outcome Selection, Dev Controls, and | |
| the observation response contract. | |
| - `catbox/sd_turbo_runner.py` owns the persistent SD Turbo image-to-image runner, | |
| prompt selection, generation settings, timing, and ephemeral file output. | |
| - `catbox/browser_ui.py` owns the local Browser UI, readiness polling, normal | |
| observation requests, trace polling, generated image serving, Progressive | |
| Waiting, Generation Failure, Retry, and Reset. | |
| - `catbox/validate_sd_turbo_runner.py` is the manual Dev Controls validation | |
| entrypoint for forcing outcomes and running Outcome Visibility tuning on the | |
| target GPU runtime. | |
| - `tests/` covers the public backend, runner, Browser UI, and manual validation | |
| documentation contracts with fakes and stubs instead of requiring GPU access. | |
| - `docs/adr/` records the project decisions that keep the Browser UI thin, the | |
| Model Backend authoritative, and Generated Outcomes ephemeral. | |
| ## How to verify | |
| Run the contract tests: | |
| ```bash | |
| uv run python -m unittest discover -s tests | |
| ``` | |
| These tests use fakes and stubs around the expensive model path. They do not | |
| need GPU access or model downloads. | |
| If you want Hugging Face authenticated downloads, create a local `.env` file: | |
| ```bash | |
| cp .env.example .env | |
| ``` | |
| Then edit `.env`: | |
| ```text | |
| HF_TOKEN=hf_your_read_token_here | |
| ``` | |
| The Browser UI startup command and manual validation command load `.env` before | |
| the SD Turbo runner requests model files. `.env` is ignored by git and should | |
| not be committed. | |
| Run the local Browser UI: | |
| ```bash | |
| uv run python -m catbox.browser_ui | |
| ``` | |
| Then open `http://127.0.0.1:8765`. The page starts from the sealed box, sends a | |
| normal observation request to the Model Backend without choosing an outcome, and | |
| keeps backend startup separate from active observation. During observation it | |
| polls the trace endpoint and displays Captured Denoising Trace frames as they | |
| are registered by the Model Backend, including a final-trace display from the | |
| completed observation response if polling misses the last frame. It reveals a | |
| subtle Progressive Waiting status only if generation takes long enough, reveals | |
| the generated image from the returned local file reference, scrolls the revealed | |
| apparatus into view, shows the Reveal Note, and lets Reset return to the sealed | |
| box. The layout is vertically scrollable on small screens, and inactive states | |
| are removed from layout so they cannot cover the active state or controls. If | |
| generation fails, the Browser UI shows a Generation Failure state with Retry and | |
| Reset instead of substituting a static image or fake Generated Outcome. The | |
| first real run may download model files before the observation completes. | |
| Manual GPU validation for the preferred GPU runtime: | |
| ```bash | |
| uv run python -m catbox.validate_sd_turbo_runner --outcome all --seed 41100 | |
| ``` | |
| That command preloads SD Turbo once, forces both Catbox outcomes through the | |
| development-only path, writes ephemeral generated images under `.runtime/`, and | |
| prints the same response shape the Browser UI will use. | |
| To test one explicit tuning candidate, pass generation settings through Dev | |
| Controls: | |
| ```bash | |
| uv run python -m catbox.validate_sd_turbo_runner --outcome dead --seed 41100 --steps 6 --strength 0.7 --width 512 --height 512 | |
| ``` | |
| To run the first Outcome Visibility matrix on the deployed GPU runtime: | |
| ```bash | |
| uv run python -m catbox.validate_sd_turbo_runner --matrix --seed 41100 | |
| ``` | |
| The default matrix tries both outcomes with steps `4,6,8`, sizes `512,768`, | |
| Living-Cat Outcome strengths `0.75,0.8,0.85`, and Dead-Cat Outcome strengths | |
| `0.6,0.7,0.8`. Choose the fastest passing candidate where both final Generated | |
| Outcomes are immediately recognizable, the Dead-Cat Outcome remains | |
| non-graphic, the shared Box Composition is still legible, and | |
| `metadata.generationSeconds` stays under the Primary Runtime Target. | |
| The current tuned SD Turbo defaults emphasize Outcome Visibility: both outcomes | |
| use 512px image-to-image generation with 6 steps. The Living-Cat Outcome uses | |
| strength `0.78`, and the Dead-Cat Outcome uses strength `0.7`. | |
| For the complete first-observation GPU validation checklist, including Browser | |
| UI readiness, normal observation, forced Dev Controls outcomes, runtime timing, | |
| ephemeral output files, and failure retry/reset behavior, see | |
| `docs/manual-gpu-validation.md`. | |
| ## Deploy on Hugging Face Spaces | |
| The preferred public deployment target is a Docker Hugging Face Space with GPU | |
| hardware. The container serves Catbox on port `7860`, which is the default | |
| external port for Spaces. | |
| Create a new Hugging Face Space with these settings: | |
| - SDK: Docker | |
| - Visibility: Public or Protected | |
| - Hardware: start with `1x Nvidia L4`; use `Nvidia A10G - small` if L4 is too | |
| slow or unavailable | |
| Add a Space secret named `HF_TOKEN` if the model download requires | |
| authenticated Hugging Face access. | |
| Push this repository's contents to the Space git remote. The Space README | |
| metadata at the top of this file tells Hugging Face to build the Docker image | |
| and expose port `7860`. The Space will start `python -m catbox.browser_ui`, | |
| download `sd-turbo` on first startup if it is not already cached, and serve the | |
| app from the Space URL. | |
| Generated outcomes and Captured Denoising Trace frames are still ephemeral in | |
| the deployed container. They are written under `.runtime/generated-outcomes` and | |
| may be lost when the Space restarts. | |