github-actions
Sync Docker Space
5f3e9f5

TextBro β€” Flask Backend

The Python/Flask service that powers Text→Video, HTML→Video, and Image/PDF→Video generation. Originally lived in shiv12345678901/yt-project; now colocated with the React frontend in this repo.

Running locally

cd backend
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
playwright install chromium

cp config/config.example.py config/config.py   # add your API_KEY/API_URL/MODEL
cp .env.example .env                           # tweak security knobs

python start.py
# β†’ http://127.0.0.1:5000

By default the server binds to 127.0.0.1 only β€” there's no shared-secret auth out of the box, so don't expose it on a LAN until you set API_KEY.

Running in production

Use a real WSGI server. The repo ships wsgi.py and pins both gunicorn (Linux/Mac) and waitress (Windows) in requirements.txt:

# Linux/Mac
gunicorn -w 4 -b 127.0.0.1:5000 wsgi:app

# Windows
waitress-serve --listen=127.0.0.1:5000 wsgi:app

app.run(debug=True) is never invoked unless FLASK_DEBUG=1 is set, and start.py will refuse to enable debug mode on a non-loopback host.

Security configuration

All knobs live in backend/.env (see .env.example). Defaults are safe for local dev:

Variable Default Purpose
FLASK_DEBUG 0 1 enables Werkzeug debug + reloader. NEVER on in prod (PIN-protected RCE shell).
FLASK_HOST 127.0.0.1 Bind address. Override only behind an authenticating reverse proxy.
PORT 5000 Listen port.
ALLOWED_ORIGINS http://localhost:5173,http://127.0.0.1:5173,http://localhost:5000,http://127.0.0.1:5000 CORS allowlist (comma-separated). Wildcard intentionally unsupported.
API_KEY (unset) Shared secret. When set, every non-public request must carry X-API-Key.
RATE_LIMIT_DEFAULT 200 per hour;30 per minute Per-IP global limit.
RATE_LIMIT_HEAVY 20 per hour;5 per minute Tighter limit on /generate*, /extract-from-image, /image-to-screenshots-sse, /regenerate.
RATE_LIMIT_STORAGE_URI memory:// Switch to e.g. redis://localhost:6379 when running multiple workers.
MAX_CONTENT_LENGTH_BYTES 33554432 32 MiB cap on uploaded files.

Public paths (always reachable)

  • GET /healthz β€” liveness probe (200 if process is alive).
  • GET / β€” index page.
  • GET /static/... β€” static assets.

Every other route (including /screenshots/* and /html/*) requires the API key when one is configured.

Threat model

This is a single-tenant developer tool. The defaults assume:

  • The process runs on a trusted machine on a trusted network.
  • Only a small group of operators hits the AI / screenshot endpoints.
  • Production deployment puts the app behind a reverse proxy that adds TLS and (optionally) further auth. API_KEY is a coarse-grained shared secret, not user-level auth.

If you need multi-tenant access, swap the _enforce_api_key before_request hook for a real auth middleware (OIDC, JWT, etc.).

Project layout

backend/
β”œβ”€β”€ app.py            # Flask app factory + security middleware
β”œβ”€β”€ start.py          # Dev launcher with preflight checks
β”œβ”€β”€ wsgi.py           # Production WSGI entrypoint (gunicorn / waitress)
β”œβ”€β”€ requirements.txt
β”œβ”€β”€ .env.example
β”œβ”€β”€ config/
β”‚   └── config.example.py   # copy to config.py and fill in
β”œβ”€β”€ routes/           # generate / html / image / resources blueprints
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ core/         # AI + vision clients
β”‚   β”œβ”€β”€ screenshot_engines/   # Playwright wrapper
β”‚   └── utils/        # cache, metrics, ETA, retry helpers
β”œβ”€β”€ static/
└── templates/

Backend endpoints used by the React frontend

Path Method Purpose
/healthz GET Liveness probe
/generate-sse POST Text β†’ HTML β†’ screenshots (SSE)
/generate-html POST HTML β†’ screenshots
/image-to-screenshots-sse POST Image/PDF β†’ screenshots (SSE)
/cancel/<operation_id> POST Cancel an in-progress generation
/beautify, /minify POST HTML helpers
/screenshots/<filename> GET Serve screenshot PNG
/html/<filename> GET Serve HTML
/download-zip POST Bundle files into a ZIP
/list GET List generated files
/delete/<type>/<filename> DELETE Delete a file
/history GET Generation history
/cache/stats, /cache/clear GET/POST AI response cache