Inspiration

Language is the wall between good content and a global audience. A great podcast, audiobook, or lesson stops at the edge of the language it was recorded in, and the tools that fix that are single-vendor black boxes: you hand them a file, they hand you an output, and if their one provider has a bad day your whole batch fails with no record of what was made. I wanted the opposite: a localization pipeline you can trust in production, that keeps a consistent voice across every language, survives a provider outage, and leaves an auditable trail of exactly what it generated.

What it does

Cast turns one recording into every language, in a single consistent voice. Record once, pick your languages, and get back a localized cut for each: transcribed, translated, and re-voiced, with a read-along transcript that highlights each word as it plays. You can also type your own line and hear it localized on the spot. Every result lands in Backblaze B2, content-addressed, with a manifest that traces it back to the original.

How I built it

A real multi-provider pipeline orchestrated by Genblaze. Each language runs the same steps: AssemblyAI transcribes the source, Claude translates it, and ElevenLabs speaks it, with LMNT as a live backup. Genblaze connects the models, providers, and steps into one reactive pipeline that streams progress over server-sent events, so the browser shows work fanning out under a concurrency cap and providers failing over live. I built two Genblaze connectors it was missing: Claude as a chat step, and LMNT on its current SDK. The backend is Python and Flask, ffmpeg handles assembly, and it runs live in Docker behind Caddy at cast.rowset.co.

Challenges I ran into

The hard problems were in the pipeline, not the front end. Genblaze's built-in fallback only swaps the model string on the same provider and fires on one error code, so it cannot cross providers or recover from an outage; I hand-rolled a cross-provider failover loop that survives any failure. Wiring in B2 surfaced a real gap: the sink only trusts the system temp directory, so I had to widen the allowed roots to store segments from the app's working directory. And getting true provenance meant transcribing the source once for real so every localized manifest could point back to a genuine master run. Along the way I found and filed several bugs and gaps in Genblaze itself.

Accomplishments that I'm proud of

Cross-provider failover the SDK's own primitive cannot do, recovering every segment in the same voice with no lost work. B2 used as a genuine system of record, not a file dump: content-addressed assets and manifests that carry a canonical hash and trace back to the master. And upstream bug reports, four of which the Genblaze maintainers have already fixed, plus two connectors, contributions back to the platform, not just consumption of it.

What I learned

How much of a generative-media product is really an orchestration and reliability problem. The models are the easy part; the value is in how you connect them, how you recover when one fails, where the assets land, and how you prove what was made.

What's next for Cast

Backblaze B2 Event Notifications so dropping a file in a bucket auto-localizes it, cloned-voice support so creators can re-voice their own catalog in their own voice, and a full self-serve upload flow.

Built With

Share this project:

Updates