What it does

You type one line — a topic — and ScriptCast returns a finished, upload-ready video package: five title candidates each with the argument for picking it, a researched narration script grounded in live web sources, a narration track in a cloned voice, and a metadata bundle with the synthetic-media disclosure platforms require. Two human gates let you approve the title and the voice; everything else is automatic. It's not a demo — it's the production pipeline behind Cosmic Quests, a live science channel, where pipeline-written videos have passed 1,000+ views.

How we built it

FastAPI + Celery + Postgres + Redis + MinIO in one docker compose up, with a Next.js UI streaming live progress over SSE. The core design decision: the worker runs exactly one stage, commits it, and re-enqueues itself. That single rule buys crash safety (you lose at most one stage), idempotency (each stage hashes its inputs, so a retry replays stored output instead of paying a vendor twice), and observability (progress lives in Postgres, so the UI and the API can never disagree). Claude Opus 5 writes the scripts with live web search; Fable 5 writes titles. Narration is self-hosted Chatterbox voice cloning on a laptop RTX 4050 — $0.00 per run. A provider abstraction (LLMProvider / TTSProvider Protocols) keeps vendor SDKs out of every layer above it, and offline fakes let the whole pipeline and its 123 tests run with no API key and no network.

Challenges I ran into

Runs are 20–40 minutes long. That killed the obvious design immediately — no HTTP request survives it. Everything had to become async, durable, and resumable before a single feature worked end to end. Real money, real mistakes. An early bug meant a paid stage could re-run on retry. Fixing it properly meant SHA-256 hashing every stage's inputs, plus a budget guard enforced at three layers — before a stage starts (worst-case cost), mid-call (a typed BudgetExceeded, so "we ran out of money" is distinguishable from "this broke"), and after the fact. The titles stage returned one 2,000-character title instead of five. Structured-output prompting needed a hard rubric and a curiosity-gap test that kills most candidates. Presigned URLs that no browser could open. MinIO is reached from two different places — inside the Compose network and from your browser — and the signature covers the host. It needed two separate endpoint settings before downloads worked. Swapping a paid TTS vendor for a GPU in the next room. This was the test of the provider abstraction, and it passed: one new file, one registry line, nothing else touched. Long scripts still had to be split across bounded HTTP requests, so a network blip costs one chunk instead of an hour of synthesis.

Built With

Share this project:

Updates

Submission history