2.2 KiB
2.2 KiB
Web On The Fly
Flask app that queues requests, then streams AI-generated fake websites via SSE through a Valkey-backed worker.
This is a Podman project. Use podman instead of docker for all container commands.
Commands
uv run app.py— start dev server (includes worker thread) on port 5000uv run pyright app.py— typecheck (strict mode)uv run ruff check app.py— lintuv run ruff check app.py --fix— auto-fix lint issuespodman compose up -d— start Valkey (required dependency)
Run lint/typecheck after any code changes.
Architecture
- Single file:
app.py - Valkey (Redis-compatible) is required for request queuing, chunk buffering, and worker coordination
- Request flow:
/→ loading page with SSE client/stream→ enqueues request in Valkey, then polls for worker-generated chunks- Background worker (thread in dev, gunicorn_post_fork in prod) pops from queue, calls LLM, buffers base64-encoded chunks
- Client decodes chunks in-memory, replaces document on
[RENDER]
- After LLM generation: validates HTML with lxml + LLM JS review, auto-fixes up to 2 times
- THEMES list (50+ items): tuples of
(site_type, description)— worker picks randomly
Env vars (loaded from .env via python-dotenv)
OPENAI_API_KEY— requiredOPENAI_API_URL— OpenAI-compatible endpoint (code default:https://api.openai.com/v1/chat/completions;.env.exampleuseshttps://aipi.reeseapps.com/v1/chat/completions)MODEL— model name (code default:gpt-4o-mini;.env.exampleusesturbo)VALKEY_URL— Valkey/Redis URL (default:redis://localhost:6379/0)
Production
- Runs via gunicorn: 16 workers, 300s timeout
gunicorn_post_forkhook ensures exactly one worker thread across processes (Valkey-based lock)- Containerfile uses
uv sync --frozen --no-dev, runs withuv run --no-sync
Key details
- LLM streaming uses
stream=True; chunks are base64-encoded to avoid SSE protocol breaks - HTTP timeout is 300s (long generations)
pyrightis configured in strict mode; use# noqa: BLE001for intentional broad exception catcheslxml.htmlis imported dynamically viaimportlib.import_module