Skip to content

Latest commit

 

History

200 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

StudioCast

The quality layer for AI audio drama

Paste a chapter. StudioCast reads it, directs it into a multi-voice scene, then listens back to its own render and holds any line that came out flat.

Live demo · Architecture · License

Story AnalysisThe DirectorAudio QC, with a Producer release decision on top.

Built for the Pocket FM "Zero to One" hackathon at IIM Bangalore. Theme: Creator Tools & Copilots.


Why it exists

Generating audio drama is close to solved. Knowing whether the render is good is not.

A text model can direct a scene and a voice model can perform it, but nothing in that chain ever listens to the result. A line directed "furious" that comes out flat ships anyway, and the first listener is the one who finds it.

StudioCast closes that loop. It re-transcribes its own render, reads the delivered emotion two independent ways, measures pacing and loudness, and holds any line whose delivery does not match its direction. Above that, a Producer layer weighs each held line against what the beat is carrying and returns publish, hold or regenerate with its reasoning.

Generation, verification, regeneration: a loop, not a one-shot.

Quickstart

Needs python3.12, uv, node and pnpm. ffmpeg is not a manual step; a system build is used when present and a static build ships in the hosted pip extra otherwise.

# API (FastAPI, Python 3.12, uv)
cd api && uv run uvicorn main:app --reload --port 8000

# Web (Next.js 16, pnpm)
cd web && pnpm install && pnpm dev      # http://localhost:3000/studio

# Demo audio is gitignored, so rebuild it on a fresh clone
python3 api/scripts/gen_renders.py

Two run modes and no third, chosen by one variable, MODE=demo|live. demo is the default: cached scenes stream the full three-stage path with zero external calls, paced to arrive the way the live pipeline does rather than dumping whole. live calls every real seam and reads no fixture; a seam that fails says so instead of quietly serving a draft. Nothing in the demo path requires a key, and the header carries the mode it is running in.

cd api && uv run pytest                         # 82 tests
cd api && uv run python scripts/preflight.py    # the pre-demo gate
cd web && pnpm lint && pnpm build

preflight is authoritative. It runs all three stages in-process with no network and checks the demo assets, the honesty guardrails, the published eval figures and the data layer. DEMO READY with exit 0 is the bar. Unconfigured live seams report and never fail, because the demo is designed to run offline.

How it works

Every component is a named agent with a role, and the console lights each one as its stage runs.

Stage Agents
Story Analysis Story Analyst
The Director Showrunner, Casting Director, SFX Spotter
Audio QC Transcript Auditor, Emotion Auditor, Pacing Auditor, Voice Auditor
Release Executive Producer

Stage 1 · Story Analysis

Rubric-anchored critique with rationale and citations. An emotional-arc classifier over Reagan's six shapes (control-point Pearson fit) with a self-consistency stability band showing how far valence can drift before the label flips. Second-episode hook meter, foreshadowing tracker (setup to payoff, plus open threads), and one-click beat rewrite.

Stage 2 · The Director

Multi-voice casting with a stated rationale per character. Voice-lock persists and reuses the cast across chapters of a project. Per-line emotion direction, SFX and music cue spotting, mood to a generated music-bed match, then a render mixed with ffmpeg: the bed ducked under dialogue by sidechain compression, SFX overlaid. The renderer is a ladder, OpenAI gpt-4o-mini-tts first and a local model beneath it, so a dead key costs quality rather than taking the stage down.

Stage 3 · Audio QC

The differentiator. Transcript diff with per-line WER, then dual-path emotion: a non-LLM acoustic model and an audio-LLM, where a line is flagged only when both disagree with the direction. Neither is trusted alone. Plus pacing, an LUFS loudness badge, voice separation between characters, and an IPA guide for proper nouns. Click a flag, regenerate that one line, and the verdict flips live. Behind QC_REPORT_CARD the findings also read as a five-row chapter report card (Emotion, Pronunciation, Continuity, Pacing, Loudness), where a row with no measurement behind it says so rather than reporting clean.

The Producer · the release decision

Above the rule sits a decision layer. The rule is fixed: any flag means hold. It cannot weigh a defect against what the beat is worth, and a flat delivery on the cliffhanger is a different problem from a flat delivery on "he closed the door".

So the Producer takes the same signals the rule saw, plus the story analysis read on what each beat is carrying, and returns publish / hold / regenerate with its reasoning. When it lands somewhere the rule would not, it says so:

"The rule says hold, and I am overruling it. That line sits on a transitional beat, where a flat reading costs less than delaying the episode."

Both verdicts are always returned, so a reviewer can disagree with either.

The cached scenes

Nine chapters ship ready to run, drawn from four public-domain books: Conan Doyle, plus Bram Stoker's Dracula, Mary Shelley's Frankenstein and Jane Austen's Pride and Prejudice. Three books beyond the detective means three different arc shapes for the classifier to name and an audience panel with something to disagree about.

Every cached scene is captured pipeline output, frozen. scripts/capture_live.py runs the real three-stage path over the chapters in api/scenes.py and writes the result to the manifest one scene at a time; nothing in it is hand-authored. /studio reads the picker from GET /scenes, so the button text and the fixture cannot drift apart. The renders the manifest names are tracked, because they are captured model output that CI cannot reproduce.

Running a chapter live a second time replays the stored result instead of calling and billing again. The replay is labelled with its age and re-measures nothing; Fresh run forces the real call.

Two of them exist to show the same defect resolving two ways, and the difference comes from the analysed beats rather than from the fixtures.

Scene Flagged line sits on Rule Producer
The Speckled Band (hero) the cliffhanger, tension 0.95 hold regenerate, upholding the hold
The Red-Headed League a transitional beat, tension 0.15 hold publish, overruled_rule

preflight fails if the two ever resolve the same way.

Honesty guardrails

These are enforced by tests and by preflight, not just stated. They are the reason the QC claim is worth anything.

  • Never claim a measurement that wasn't taken. Every emotion reading records which rung produced it, and a text-derived reading is never presented as if it heard the audio. Every measurement field is nullable, and absence survives all the way to the UI.
  • The planted flaw is real. The flagged line is acoustically flat in the samples, and preflight measures it. There is no "always flag this line" detector.
  • The Producer reads measurements, never audio. The audio critics stay the acoustic model and the audio-LLM. Its confidence is labelled self-reported and uncalibrated, and it never silently replaces the rule's verdict.
  • Two run modes and no third, labelled on every stage: demo serves the cached scenes with no network, live calls every real seam. A live stage that cannot reach its model fails and says so rather than quietly serving a draft. A deterministic decision is labelled policy, never a model.
  • Classifier numbers are reported as agreement, never as absolute quality. No churn, pay or conversion claims appear anywhere in shipped copy; preflight greps for them.

Measured, not claimed

Shipped classifiers scored against a hand-labeled public-domain set (api/evals/):

Classifier Accuracy Cohen's κ Macro-F1
Emotion (text) 0.87 0.84 0.88
Story arc (Reagan shapes) 0.86 0.83 0.78

κ > 0.8 is "almost perfect" agreement (Landis and Koch), with visible misclassifications left in. Emotion labels carry the acted-versus-natural caveat. Story signals such as cliffhanger strength and hook are shown as relative bands with rationale and citations, never as validated metrics.

Screens

Route What it is
/ Landing
/audience What the listener panel is, read off the running build
/report-card What the five chapter rows measure, read off the running build
/studio Source picker: the chapters this build ships with
/studio/run The three-stage console, the demo path
/scene/[id] Share page: listener player, generated PNG mood cover, OG audio card
/explore Feed of published scenes that have audio

This build is public demo only. There is no sign in, no sign up and no account. Every route above is open to everyone and every demo endpoint is reachable without a token. The creator layer (dashboard, series library, saved chapters) has been removed from the web app, and proxy.ts returns 404 for /dashboard, /series, /sign-in and /sign-up so nothing survives in a stale link or a bookmark.

Project layout

Path What
api/ FastAPI, Python 3.12, uv. Flat module layout: pipeline.py orchestrates, producer.py decides, qc_live.py / ser.py / prosody.py / asr.py measure, db.py fronts three backends.
web/ Next.js 16, pnpm, Tailwind. app/studio is the demo surface.
api/cache/ The offline demo. manifest.json is committed; renders are gitignored and rebuilt by scripts/gen_renders.py.
api/evals/ The hand-labeled sets behind the table above.
api/databricks/ Workspace-side SQL: Delta ingest, catalog views, CI grants.
localdocs/ Working notes and ops records. Gitignored.

Judging axes

Innovation. The only stage here that hears its own output, with a Producer above it that makes a judgement rather than matching a threshold, sometimes overruling the rule and always saying why.

Technical execution. Strict-schema structured outputs on every stage; SSE streaming with guaranteed failure propagation, job recovery and terminal replay; three storage backends behind one interface, verified value-identical; an append-only QC-event flywheel exported as a fact table.

Use of AI. Each model justified and attributed exactly. Audio QC is deliberately not one model: an audio-LLM paired with a non-LLM acoustic model, agreeing before anything is flagged. The audio judge has earned that distrust, since asked twice about the same clip it can answer differently. It is one opinion, not a measurement.

Real-world impact. Sits after the authoring suite and before publish, which is the verification gap in the stack. Every flagged line and every human accept or reject becomes an append-only training triple, so the QC data compounds.

Working demo. Three beats in 90 seconds, with a cached offline path underneath so a dead network cannot take it down.

Documentation

  • ARCHITECTURE.md for the system design: pipeline internals, the degradation ladders, the data layer, deployment topology and CI.
  • CLAUDE.md for the repo working agreement.

License

Proprietary. All rights reserved. See LICENSE. This source is published for review and evaluation only. It is not open source, and no permission is granted to use, copy, modify or redistribute it. For any other use, ask first.

About

The quality layer for AI audio drama

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages