Commit Graph

26 Commits

Author SHA1 Message Date
Jeff Emmett 8efeae63c7 Wire Infisical for backend and worker secrets
- Add Python entrypoint.sh for Infisical secret injection
- Both backend and worker fetch DATABASE_URL, OPENAI_API_KEY from Infisical
- Worker uses network_mode:service:wireguard (shares traefik-public via WG)
- Keep env_file for non-secret config vars

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 09:32:45 -08:00
Jeff Emmett e1d9085396 feat: inline video previews and caption rendering with style options
- Replace download links with inline <video> players for clip preview
- Add clip download endpoint separate from inline preview
- Add caption style options: TikTok, Hormozi, Karaoke, Minimal, None
- Implement ASS subtitle generation from word-level Whisper timestamps
- Render pipeline: aspect ratio conversion + burned-in captions via FFmpeg
- Add render preview endpoint for inline playback of rendered clips
- Add fonts to Docker image for subtitle rendering

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 02:11:20 +00:00
Jeff Emmett db4b7b10fd fix: use raw seconds in transcript timestamps to prevent AI misinterpretation
The AI model was interpreting MM:SS timestamps (e.g., 38:07) as decimal
seconds (38.07s) instead of 2287s, causing clips from long videos to have
near-zero durations. Switching to raw seconds (e.g., [2287.0s - 2295.0s])
eliminates the ambiguity.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 01:43:38 +00:00
Jeff Emmett 3ce7945096 fix: robust JSON parsing with regex fallback for LLM responses
Gemini sometimes produces JSON with unescaped characters that break
standard parsing. Added multiple fallback strategies including regex
extraction of individual clip objects.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 01:17:15 +00:00
Jeff Emmett 1bac0b90a6 debug: improve AI analysis JSON parsing error logging
Show more context in error messages to diagnose parse failures.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 01:13:00 +00:00
Jeff Emmett 72efed481f perf: limit YouTube downloads to 720p max
4K downloads are 229MB+ and too slow through the WG tunnel.
720p is sufficient quality for clip analysis and extraction.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 01:08:52 +00:00
Jeff Emmett 6c40f713a4 fix: strip markdown code fences from LLM JSON response
Gemini wraps JSON output in ```json fences which broke the parser.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 00:50:10 +00:00
Jeff Emmett 362fe1e860 feat: add cloud AI inference support (Gemini/OpenAI-compatible)
CPU-based Ollama inference on Netcup is too slow due to server memory
pressure. Add OpenAI-compatible API support so we can use Gemini Flash
or other cloud APIs for clip analysis. Also increase transcript sample
size to 20K chars since cloud APIs handle it easily.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 00:44:13 +00:00
Jeff Emmett d480c635ff Increase Ollama timeout to 1800s for long video transcripts
47-minute videos produce ~48K chars of transcript which takes
>10 minutes for llama3.1:8b on CPU to process.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 21:27:36 +00:00
Jeff Emmett c06e17c016 Connect WG to traefik-public for direct Whisper access
Worker accesses Whisper via Docker DNS (whisper-local:8000) instead
of through the WG tunnel, avoiding 524 timeout on large audio uploads.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 20:16:25 +00:00
Jeff Emmett 8068a64265 Add whisper.jeffemmett.com host override to WG container
Routes Whisper API traffic directly to local Traefik instead of
through the WG tunnel via Cloudflare, avoiding 524 timeouts on
large audio file uploads.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 20:14:40 +00:00
Jeff Emmett 091ad039af Reverse WireGuard architecture: server on Netcup, client at home
Flipped WG topology to avoid WSL2 UDP port forwarding issues:
- Netcup is now WG server (has public IP, listens on UDP 51820)
- Home WSL2 is WG client (connects outbound, no port forwarding needed)
- Home client NAT masquerades worker traffic through residential IP
- AllowedIPs=0.0.0.0/0 routes all worker internet through tunnel

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 20:06:04 +00:00
Jeff Emmett 19468aeac8 Add WireGuard tunnel for YouTube downloads through residential IP
YouTube blocks datacenter IPs. This adds a WireGuard client sidecar
to route worker traffic through a home residential IP tunnel.
- wireguard/ has the WG server config (runs on WSL2 at home)
- Worker uses network_mode: service:wireguard for tunnel routing
- wg-client/ and cookies.txt added to .gitignore (contain secrets)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 19:58:39 +00:00
Jeff Emmett 0e4eec4f12 fix: add web_creator client fallback, friendlier YouTube bot error
- Try multiple YouTube player clients for better compatibility
- Show user-friendly error suggesting upload when YouTube blocks download

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 18:41:19 +00:00
Jeff Emmett be3b1ca706 fix: copy cookies to temp file so yt-dlp doesn't overwrite originals
yt-dlp saves rotated cookies back on exit, destroying fresh exports.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 18:39:35 +00:00
Jeff Emmett c5505417a5 feat: add deno runtime for yt-dlp YouTube JS extraction
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 18:35:11 +00:00
Jeff Emmett 5c9b7c74e0 fix: use raw string for HTML template to preserve JS backslashes
Python was interpreting \' as ' in the onclick handlers, breaking JS.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 11:36:48 +00:00
Jeff Emmett 128aad405c feat: add user-friendly frontend with upload, progress, and clip gallery
Replaces API endpoint listing with a proper UI:
- YouTube URL input or drag-and-drop video upload
- Real-time SSE progress bar with stage messages
- Clip results gallery with virality scores, categories, transcripts
- Preview/download links for extracted clips
- Recent jobs history with click-to-view

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 11:27:29 +00:00
Jeff Emmett 53c1ed5c4c feat: add landing page with API docs at root URL
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 13:14:13 +00:00
Jeff Emmett 1784bb35ff fix: increase Ollama timeout to 600s for CPU inference
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 13:05:29 +00:00
Jeff Emmett 4619b53b5e fix: update yt-dlp to latest for YouTube bot detection bypass
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 12:40:59 +00:00
Jeff Emmett fb5d189334 fix: make cookies file writable for yt-dlp cookie saving
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 12:39:50 +00:00
Jeff Emmett 7e121334ba fix: simplify cookies mount path
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 12:38:46 +00:00
Jeff Emmett 5018915b10 fix: mount YouTube cookies file for yt-dlp authentication
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 12:35:49 +00:00
Jeff Emmett 6ab5f805a4 fix: use arq CLI to start worker instead of python -m
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 12:33:02 +00:00
Jeff Emmett 6aa8a676ec feat: ClipForge Phase 1 - core pipeline MVP
Self-hosted AI video clipper (Opus Clip alternative).
Pipeline: YouTube URL -> yt-dlp download -> Whisper transcription ->
Ollama AI clip selection -> FFmpeg extraction.

- FastAPI backend with PostgreSQL + Redis + ARQ worker
- 7-stage processing pipeline with SSE progress tracking
- Services: download (yt-dlp), transcription (whisper.jeffemmett.com),
  AI analysis (Ollama), clip extraction (FFmpeg stream copy)
- API: create jobs, track progress, list clips, render, download
- Docker Compose with Traefik labels for clip.jeffemmett.com

Cost: $0/video using existing infrastructure.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 12:27:43 +00:00