YT Auto - (Local)
Overview
YT Auto is an autonomous pipeline for a Telugu faceless YouTube channel. It runs a chain of agents: find a topic, pick a strategy, write a script, storyboard, produce voice + motion-graphics video, review compliance/quality, then generate metadata and (optionally) upload via the YouTube API.
Architecture
Architecture notes
yt-auto is a single-process LangGraph pipeline with a thin Control Room UI. Agents do not talk to each other over APIs. They share one PipelineState object, write artifacts under output/run_YYYYMMDD_HHMMSS/, and emit live progress to output/.dashboard/live.json plus events.jsonl.
Three layers:
| Layer | Responsibility |
|---|---|
| Entry | CLI (python -m yt_auto) and FastAPI Control Room (python -m yt_auto web on 127.0.0.1:8787) |
| Orchestration | LangGraph in yt_auto/graph.py: 10 nodes, two review loops, quarantine exit |
| Services | LLM, TTS, trends, media, FFmpeg render, YouTube OAuth/upload, storage |
The web server does not run the pipeline in-process. Run in the UI spawns python -m yt_auto run --mode short|long so each run loads current code and .env. The UI polls /api/live and /api/runs. Secrets stay in env vars only.
Default compute is local: Ollama for text, local TTS (Svara / Indic-Mio) for voice, FFmpeg + Pillow for video. Gemini, Edge TTS, and YouTube APIs are optional fallbacks or publish path.
Service boundaries
Do not call other agents. An agent reads PipelineState, uses services, writes JSON/media, returns an updated state.
Agents (yt_auto/agents/) — workflow only
| Agent | Owns | Must not |
|---|---|---|
| Trend Scout | Live topic board | Pick the final topic |
| Strategist | One topic + grounded facts | Write the full script |
| Script Writer | Telugu script beats + scene specs | Render audio/video |
| Storyboarder | Timed scene list / aspect | Synthesize voice |
| Producer | Voice + MP4 | Upload or SEO package |
| Compliance | Policy / education-not-advice gate | Re-render video |
| Quality | Hook, pacing, A/V completeness | Rewrite the script (sends Producer back) |
| Metadata | Title, description, tags, thumbnail | Upload |
| Publisher | YouTube upload or dry-run | Create the video |
| Quarantine | Failed run hold + optional webhook | Publish |
Review loops: Compliance fail → Script Writer (up to MAX_REVISIONS). Quality fail → Producer. Too many fails → Quarantine.
Services (yt_auto/services/) — reusable I/O, no graph logic
| Boundary | Modules | Talks to |
|---|---|---|
| Config | config.py | .env (Pydantic settings) |
| LLM | llm.py | Ollama (qwen3.5:9b + fallbacks), optional Gemini |
| Trends | trends.py, link_finder.py | Google Trends, Google News RSS, YouTube Data API |
| TTS | tts.py, local_tts.py, gemini_tts.py, emotion.py | Svara/Indic-Mio GPU worker, Gemini TTS, Edge TTS, MMS-TTS |
| Visuals | scene_render.py, visual_plan.py, media.py, pexels.py, stock_*, thumbnail.py | FFmpeg, Pillow, Pexels, Pixabay, Wikimedia, optional Diffusers / Gemini image |
| YouTube | youtube_auth.py, youtube_upload.py | YouTube Data API OAuth |
| Run telemetry | run_events.py, storage.py | live.json, events.jsonl, run folders, used-topic store |
| Ops | alerts.py | Optional ALERT_WEBHOOK_URL |
UI (yt_auto/web/)
Serves the dashboard and REST: health, agents/flow, live state, run list/detail/events, video file, start/stop. It does not own LLM, TTS, or FFmpeg.
Data flow
Rendering diagram…
Happy-path artifacts per run (output/run_*/):
candidates.json— ranked topicsselected_topic.json— one topic + source factsscript.json— beats, scene specs, CTA/disclaimerstoryboard.json— timed scenes, 9:16 or 16:9audio/voice.mp3— concatenated TTSvideo/final_short.mp4(or long equivalent)review/compliance.json,review/quality.jsonyoutube/metadata.json, thumbnail,youtube/upload_result.jsonevents.jsonl— live agent log for the UI
State carried in memory (PipelineState): run_id, mode, candidates, selected_topic, script, storyboard, audio_path, video_path, review results, retry counts, metadata, upload_result, status.
Config that changes behavior without code changes: LLM_PROVIDER, TTS_ENGINE / TTS_FALLBACKS, VISUAL_ENGINE, CONTENT_LANG, YT_DRY_RUN, MAX_REVISIONS. Restart web after editing .env.
Challenges & solution
The problem
I set out to automate a full YouTube content pipeline — researching trending topics, writing scripts, generating natural-sounding Telugu narration, rendering animated video, and publishing — without paying for cloud AI APIs. That single constraint turned out to be the hardest part of the project.
Cloud LLM/TTS APIs (I used Gemini early on) are reliable by default: near-unlimited scale, consistent quality, and someone else's infrastructure keeping the model alive. Running the same pipeline locally on a single RTX 3070 Ti laptop GPU (8GB VRAM) meant I had to build all of that reliability myself:
Free-tier quota exhaustion — Gemini's free tier ran out constantly (text, voice, and even image generation), which pushed the whole architecture to a local-first design: a local LLM via Ollama for scripts, and a local speech-synthesis model for narration, with Gemini only as an occasional fallback. A silent production outage traced to a GPU driver bug — one model started failing every run with a generic error. I had to dig through Ollama's own server logs to find a CUDA kernel crash specific to that model's architecture on this GPU, confirm it wasn't fixed by the latest update, and route around it with an automatic model-fallback chain instead of waiting on an upstream fix. Telugu is a second-class citizen in most ML tooling — the standard text-rendering library couldn't shape Telugu script correctly, and small open speech models default to a flat, robotic delivery. Both needed custom fixes: proper glyph shaping through a different rendering path, and hand-tuned pitch/pace/emotion parameters to get natural-sounding speech. Small local models hallucinate more than large cloud ones — I had to build my own fact-grounding layer that checks every number and claim in a generated script against the real source material before it's allowed on screen, something a bigger hosted model would need much less of.
The result runs a full daily content pipeline for effectively zero marginal cost per video, which wouldn't have been possible by just calling a cloud API and hoping it stays within budget.
The solution
- Free-tier quota exhaustion → local-first architecture with automatic fallback chains
Rather than architecting around one AI provider, every stage (script LLM, voice, even thumbnail generation) got a chain of engines, not a single one: local model first, cloud API only as a last resort. TTS_ENGINE=local → gemini → edge for voice, and the same pattern for the script-writing LLM. Each stage tries the next option automatically and logs which one it actually used, so a quota wall on one provider degrades the pipeline instead of stopping it.
- A GPU driver crash traced through raw server logs → self-healing model chain
When one model started failing every run, I didn't just retry it — I went into Ollama's own server logs and found the actual crash: a CUDA kernel-capability check failing for that specific model's architecture on this GPU. I isolated it by testing other models on the same GPU (they worked fine, proving it wasn't a hardware or driver problem generally), restarted and updated Ollama to rule out a stale process, and confirmed the crash was deterministic and unfixed upstream. The permanent fix: an automatic model-fallback chain that detects this exact crash signature, blacklists that model for an hour so it stops wasting time retrying something that will fail again immediately, and falls through to the next local model — turning a hard outage into a one-line warning in the logs.
- Telugu as a second-class citizen in ML tooling → custom rendering and voice tuning Text: the standard image library (Pillow) draws Telugu with broken conjuncts because it has no font-shaping engine. I routed all on-screen Telugu through ffmpeg's HarfBuzz-based text renderer instead — rendering each string to a cached alpha mask and compositing that, so the video's on-screen text is correctly shaped. Voice: got the local speech model from flat and robotic to something with real delivery through several rounds of measurable tuning — per-speaker pitch, pace, and clarity settings, natural variable pauses instead of fixed gaps, and an "emotion director" step where the script's own local LLM reads the narration and decides the delivery style per line. For a two-host format, I found the same "energetic" style that helped the male voice made the female voice sound harsh, so each speaker got separately tuned settings rather than one shared preset — validated by building a small evaluation harness that renders both before/after versions and scores them for reproducibility, timing, and (with a disclosed-as-unreliable) automated listener, rather than just eyeballing a single sample.
- Small local models hallucinate more → a grounding layer the cloud version didn't need
Built a fact-checking pass that sits between the LLM and the final video: the topic-research step extracts facts verbatim from real sources instead of letting the model paraphrase them (paraphrasing was quietly losing real numbers and specific names), the script-writing prompt explicitly forbids inventing any figure — including a fabricated statistic spelled out as a word instead of a digit, which is how one bad number slipped through the original numeric-only check — and any on-screen stat/comparison graphic gets dropped if its number doesn't trace back to a real source. The same discipline applies to links in the video description: only a link that's been scraped from a real source or matched to a hand-verified official URL is used, and even then only after a live reachability check right before publishing, so a dead or fabricated link never goes out.
Net result
A pipeline that runs a full research → script → voice → video → publish cycle on its own schedule, for the cost of electricity rather than a per-video API bill, with the same kind of reliability engineering (fallback chains, crash recovery, fact validation) that a paid cloud stack would otherwise have handled for me.
Technologies
Metrics & results
Reliability
Automatic recovery from a GPU-level model crash: primary LLM fails → detected, blacklisted, next model in the chain takes over — demonstrated live, script generation succeeded despite the crash, with zero manual intervention. Voice generation reproducibility: same input + same seed → bit-for-bit identical output (measured correlation 1.0, max sample difference 0.0) — the pipeline is deterministic, not flaky. At least one video confirmed fully published live and public on YouTube end-to-end through the automated pipeline (script → voice → render → thumbnail → upload), not just a dry run.
Content quality (before/after, same real topic, same source material)
Description length: 458 → 881 characters, going from a two-line summary to a structured, detailed writeup. Reference links per video: 0 → up to 2, each verified with a live HTTP check immediately before publishing (never a dead or invented link). A concrete factual-grounding defect I caught and fixed: the script generator had fabricated a "17x salary increase" claim; after the fix, the same real source data produced the actual figures (₹2.8L → ₹40L, named person, named company) instead.
Cost / efficiency
$0 marginal API cost per video — script and voice generation run on local models, not paid cloud calls. Local voice generation: faster than real-time (roughly 3-4x — a several-minute narration synthesized in under two minutes). Peak GPU memory during voice generation: ~5.5-5.8 GB, comfortably inside an 8 GB consumer laptop GPU. Disk footprint of the local model stack: ~23-26 GB (measured directly). Estimated running cost if left on the original machine: roughly ₹30-100/month in electricity for two videos/day — an estimate based on typical GPU draw and run time, not a metered figure, so I'd flag it as an estimate if you use it.
Housekeeping
Cleaned up the project's own footprint: trimmed old run output from 2.5 GB down to ~400 MB by enforcing a keep-last-5-runs policy, and removed dead code paths that had accumulated across the build.