Project Overview
Calliope is a content repurposing platform built to convert YouTube videos into publish-ready blog posts. Instead of forcing creators, writers, and marketers to transcribe videos by hand and write articles from scratch, Calliope automates the entire pipeline: fetching video subtitles, parsing transcript timestamps, enriching prompts with search context, and streaming structured blog drafts in real time.
I built the application end to end as a Full-stack Developer, designing the browser UI, FastAPI REST endpoints, Celery background workers, multi-model LLM chains, and admin token analytics.
Link to the product: Calliope

Technology Stack
flowchart LR
subgraph Client ["Frontend"]
UI["React 19 / TypeScript UI"]
Editor["Markdown Editor & Stream"]
end
subgraph Backend ["FastAPI & Workers"]
API["FastAPI REST API"]
Worker["Celery Background Worker"]
YT["YouTube Subtitle Pipeline"]
SERP["SERP Context Engine"]
LLM["LangChain Orchestration"]
end
subgraph Storage ["Data & Messaging"]
Redis[("Redis Broker")]
DB[("PostgreSQL")]
end
UI <-->|HTTP / JSON| API
API -->|Enqueue Task| Redis
Redis --> Worker
Worker --> YT
Worker --> SERP
Worker --> LLM
Worker <--> DB
API <--> DB
sequenceDiagram
actor User
participant UI as React UI
participant API as FastAPI
participant DB as PostgreSQL
participant YT as YouTube
participant Redis as Redis
participant Worker as Celery Worker
participant LLM as LLM Provider
participant SERP as SERP API
User->>UI: Paste YouTube URL
UI->>API: POST /videos/transcribe
API->>DB: Lookup blog by yt_id
alt Transcript not cached
API->>YT: Extract subtitles via yt-dlp
YT-->>API: Subtitle tracks
opt yt-dlp fails
API->>YT: Fallback via Google YouTube Data API
YT-->>API: Transcript text
end
API->>DB: Upsert Blog + transcript metadata
end
API->>DB: Create or link UserBlog draft
API->>Redis: Enqueue generate_blog task
API-->>UI: draft_id + status
loop Poll every 2s
UI->>API: GET /drafts/{id}
API->>DB: Read draft content + status
API-->>UI: Partial or final content
end
Redis->>Worker: Dequeue generate_blog
Worker->>DB: Load transcript from Blog
Worker->>LLM: Classify content type + topic
LLM-->>Worker: content_type, topic
Worker->>LLM: Extract knowledge document
LLM-->>Worker: Structured knowledge doc
opt SERP enabled
Worker->>SERP: Research topic keywords
SERP-->>Worker: Top ranking snippets
end
Worker->>LLM: Stream blog draft
loop Token stream
LLM-->>Worker: Token chunks
Worker->>Redis: Publish status and token events
Worker->>DB: Flush partial content
end
Worker->>DB: Save final draft + token usage
Worker->>Redis: Publish done event
- Frontend: React 19, TypeScript, Vite, Tailwind CSS v4, Base UI / Shadcn, Recharts, Zustand
- Backend: Python, FastAPI, Celery, SQLAlchemy, Alembic, Pydantic
- AI Orchestration: LangChain, LangChain-Google-GenAI, LangChain-OpenAI (supporting DeepSeek, Gemini, and GPT models)
- Video & SERP Processing:
yt-dlp, YouTube Data API v3, SerpApi, DataForSEO - Storage & Infrastructure: PostgreSQL, Redis, Docker Compose
- Auth & Services: Google OAuth2, JWT sessions, Resend email delivery, FingerprintJS visitor tracking
Product Context
Long-form YouTube videos contain rich expertise, but turning spoken video content into rankable, reader-friendly articles takes hours of transcription, outline structuring, and editing. Naive transcript dumps fail because spoken raw text lacks formatting, headings, and search intent alignment.
Calliope exists to bridge raw audio content and structured publishing. It extracts transcripts, cleans conversational filler, identifies core topic angles, cross-references top-ranking search results when enabled, and drafts structured articles with titles, subheadings, key takeaways, and frontmatter metadata.
What I Built

- YouTube Extraction Engine: dual-layer subtitle parser that pulls captions with
yt-dlpfirst, then falls back to the Google YouTube Data API when scraping fails. - Async Task Pipeline: Celery and Redis worker queue handling long-running transcript processing and LLM synthesis without blocking web API requests.
- Multi-Model LLM Orchestration: flexible LangChain abstraction supporting models including DeepSeek v4 Pro, Google Gemini 2.5/3.0, and OpenAI GPT-4o.
- SERP Research Integration: optional Google SERP lookup via SerpApi and DataForSEO to inject competitor angles and searcher intent into the drafting prompt.
- Interactive Markdown Editor: real-time draft streaming, markdown preview, draft highlight notes, custom theme preferences, and one-click copy with frontmatter metadata (title, meta description, OG image, and tags).
- History & Saved Drafts: user workspace with draft history, title search, pinned posts, and original video source attribution.
- Admin Analytics Dashboard: daily UTC metrics tracking user signups, cumulative growth, and exact prompt/completion token consumption per LLM provider.
Key Engineering Decisions
1. Decouple Transcript Extraction from Synchronous API Routes
Fetching subtitles for 40-minute videos and generating 2,000-word articles takes tens of seconds. Running this work inside synchronous HTTP handlers causes request timeouts and degrades server throughput. Pushing jobs to a Celery worker queue backed by Redis keeps the API responsive while persisting intermediate task state in PostgreSQL.
2. Implement a Resilient Subtitle Fallback Chain
YouTube caption endpoints frequently change or throw rate limits. Calliope uses a resilient pipeline: it first extracts subtitle tracks with yt-dlp; if that fails, it falls back to the Google YouTube Data API. This order keeps the primary path fast and reliable while the official API catches edge cases where scraping breaks.
3. Enrich Draft Prompts with SERP Intent Context
A video transcript alone might miss key terminology or related questions that readers expect. When SERP research is enabled, Calliope queries top Google search results for the video’s primary topic and passes these search snippets as optional context to the LLM. That produces articles aligned with searcher intent without hallucinating outside the video’s core content.
4. Track Token Usage and Cost Boundaries per Request
To keep operational costs predictable, the database records exact input and output token counts for every LLM call alongside model provider metadata. The admin dashboard aggregates these metrics over selectable time ranges, providing immediate visibility into model costs and user activity.
Outcome
Calliope is deployed live at calliope.ekky.dev. It transforms 30+ minute YouTube videos into formatted 1,500+ word blog posts in under 30 seconds, providing creators and marketers with a reliable tool for multi-channel content expansion.
Lessons Learned
- Third-party transcript APIs are fragile;
yt-dlpshould be the primary extraction path, with the Google YouTube Data API as fallback when scraping fails. - Combining video transcript data with top search results creates significantly more comprehensive articles than transcript text alone.
- Admin analytics for token metrics should be designed into the schema from day one to ensure transparent cost tracking as traffic grows.
Attachments
Landing Page

Login Screen

Create Account Screen

Main Dashboard & Navigation

Generation History

Admin Analytics & Token Metrics

Transcript & Highlights Workspace

Blog Draft Editor & Streaming View

