Skip to content

Omar-Tahir/ClipForge

Repository files navigation

ClipForge — AI Viral Clip Studio

Turn any YouTube video or podcast into ready-to-publish short-form clips in minutes.

ClipForge is a production-ready AI SaaS platform that automatically extracts viral clip candidates from long-form video, adds TikTok-style captions, applies branding, and publishes directly to YouTube Shorts.


Features

  • AI Clip Detection — Multi-model support (GPT-4o, Claude, Gemini) with 0–10 virality scores
  • Auto Transcription — Local Whisper with word-level timestamps
  • Smart Formatting — 9:16 vertical reformat with centre-crop or blur-pad
  • TikTok Captions — Word-by-word karaoke burn-in, multiple style presets
  • Watermarking — Logo overlay with configurable position + opacity
  • BYOK — Encrypted API key storage, never exposed in responses
  • YouTube Publishing — OAuth2 with draft/public toggle
  • JWT Auth — Access + refresh tokens with per-user rate limiting
  • React Frontend — Dark editorial UI with live progress polling

Project Structure

clipforge/
├── app/                        # FastAPI backend
│   ├── agents/                 # AI agents
│   │   ├── content_analyzer.py # Segments transcript into narrative blocks
│   │   ├── viral_detector.py   # Detects clips + scores + generates metadata
│   │   └── prompts.py          # All LLM prompts (edit here, not in agents)
│   ├── api/
│   │   ├── dependencies.py     # Auth + rate limit dependencies
│   │   ├── error_handlers.py   # Exception → HTTP response mapping
│   │   └── routes/
│   │       ├── auth.py         # /auth/* (register, login, refresh)
│   │       ├── api_keys.py     # /api/keys CRUD
│   │       ├── videos.py       # /api/videos submit + status
│   │       ├── analysis.py     # /api/videos/{id}/analyze
│   │       ├── clips.py        # /api/clips generate + download
│   │       ├── publishing.py   # /api/clips/{id}/publish + YouTube OAuth
│   │       └── health.py       # /health, /health/ready
│   ├── models/
│   │   ├── database.py         # Async engine + session factory
│   │   ├── tables.py           # All ORM tables
│   │   └── tables_youtube.py   # YouTube credential table
│   ├── services/               # Business logic
│   │   ├── youtube_validator.py
│   │   ├── downloader.py       # yt-dlp
│   │   ├── audio_extractor.py  # ffmpeg WAV extraction
│   │   ├── transcriber.py      # Whisper (word-level)
│   │   ├── video_pipeline.py   # Phase 1 orchestrator
│   │   ├── model_router.py     # Unified LLM abstraction (OpenAI/Claude/Gemini)
│   │   ├── clip_processor.py   # Phase 3 orchestrator
│   │   ├── clipper.py          # ffmpeg cut + 9:16 reformat
│   │   ├── caption_generator.py# ASS subtitle file generator
│   │   ├── caption_burner.py   # ffmpeg caption burn-in
│   │   ├── caption_style_config.py
│   │   ├── watermarker.py      # Logo overlay
│   │   ├── ffmpeg_utils.py     # Shared ffmpeg subprocess helpers
│   │   ├── auth_service.py     # JWT + bcrypt
│   │   ├── encryption.py       # Fernet AES-128 for API keys
│   │   ├── key_resolver.py     # BYOK lookup + decrypt
│   │   ├── usage_logger.py     # Token usage + cost tracking
│   │   ├── youtube_oauth.py    # OAuth2 flow + token refresh
│   │   ├── youtube_uploader.py # Resumable upload
│   │   └── publishing_service.py
│   ├── utils/
│   │   ├── config.py           # Pydantic settings
│   │   ├── exceptions.py       # Custom exception hierarchy
│   │   └── logger.py           # Structlog setup
│   └── main.py                 # FastAPI app factory
│
├── frontend/                   # React + Vite SPA
│   ├── vite.config.js          # /api proxy → localhost:8000
│   ├── package.json
│   └── src/
│       ├── App.jsx             # Router + nav + toast
│       ├── store/index.js      # Zustand global state
│       ├── services/api.js     # Axios + auth interceptors
│       └── pages/
│           ├── LoginPage.jsx
│           ├── DashboardPage.jsx   # URL submit + video list
│           ├── VideoPage.jsx       # Clip studio
│           └── SettingsPage.jsx    # API keys + YouTube
│
├── migrations/                 # Alembic
├── tests/
│   ├── conftest.py             # Shared fixtures
│   ├── unit/                   # 21 unit test files
│   └── integration/            # E2E + load (RUN_INTEGRATION=1)
├── skills/
│   └── viral-clip-detector/    # Claude skill for prompt iteration
│       ├── SKILL.md
│       └── references/
│           ├── scoring-rubric.md
│           └── prompt-variants.md
├── storage/
│   ├── temp/                   # Temporary download files
│   └── outputs/                # Final clip MP4s
├── scripts/setup.sh            # One-command dev bootstrap
├── docker-compose.yml          # Postgres + Redis
├── pyproject.toml
└── .env.example

Prerequisites

Tool Min Version Purpose
Python 3.11+ Backend
Node.js 18+ Frontend
Docker 24+ Postgres + Redis
ffmpeg 6+ Video processing
libass any Caption rendering
# Ubuntu/Debian
sudo apt-get install ffmpeg libass-dev fonts-liberation

# macOS
brew install ffmpeg

Quick Start

1. Bootstrap

git clone https://github.com/Omar-Tahir/clipforge.git
cd clipforge
bash scripts/setup.sh

This installs deps, generates a Fernet key, starts Docker services, and runs migrations.

2. Configure .env

# Core (auto-populated by setup.sh — review and adjust)
DATABASE_URL=postgresql+asyncpg://clipforge:clipforge@localhost:5432/clipforge
DATABASE_URL_SYNC=postgresql://clipforge:clipforge@localhost:5432/clipforge
APP_SECRET_KEY=change-me-in-production
FERNET_KEY=<auto-generated>

# YouTube publishing (get from Google Cloud Console)
YOUTUBE_CLIENT_ID=
YOUTUBE_CLIENT_SECRET=
YOUTUBE_REDIRECT_URI=http://localhost:8000/auth/youtube/callback

3. Start backend

source .venv/bin/activate
uvicorn app.main:app --reload
# → http://localhost:8000
# → http://localhost:8000/docs  (Swagger UI)

4. Start frontend

cd frontend
npm install
npm run dev
# → http://localhost:3000

Environment Variables

Variable Required Description
DATABASE_URL PostgreSQL async URL
DATABASE_URL_SYNC PostgreSQL sync URL (Alembic)
REDIS_URL Redis URL
APP_SECRET_KEY JWT signing secret (32+ chars)
FERNET_KEY AES-128 key for API key encryption
YOUTUBE_CLIENT_ID Publishing Google OAuth client ID
YOUTUBE_CLIENT_SECRET Publishing Google OAuth client secret
YOUTUBE_REDIRECT_URI Publishing OAuth callback URL
STORAGE_BACKEND No local (default) or s3
SENTRY_DSN No Error tracking

Generate a Fernet key manually:

python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"

API Reference

Auth

Method Endpoint Body Response
POST /auth/register {email, password} {access_token, refresh_token}
POST /auth/login {email, password} {access_token, refresh_token}
POST /auth/refresh {refresh_token} {access_token, refresh_token}
GET /auth/me {id, email}

Full API Pipeline

# 1. Submit video
POST /api/videos/submit  { "url": "https://youtube.com/watch?v=..." }

# 2. Poll until status = "completed"
GET  /api/videos/{video_id}/status

# 3. Run AI detection (pass your API key)
POST /api/videos/{video_id}/analyze
     { "provider": "claude", "api_key": "sk-ant-...", "max_clips": 5 }

# 4. Generate processed clips
POST /api/clips/generate
     { "clip_ids": ["..."], "caption_style": "tiktok", "watermark_enabled": true }

# 5. Poll until clip status = "completed"
GET  /api/clips/{clip_id}/status

# 6. Download
GET  /api/clips/{clip_id}/download   → MP4 file

# 7. Publish to YouTube (requires /auth/youtube/connect first)
POST /api/clips/{clip_id}/publish  { "draft": true }

See /docs for the full interactive Swagger UI.


Virality Scoring

Dimension Weight Measures
Hook strength 35% First 3 seconds — stop-scroll factor
Emotional resonance 30% Laugh, surprise, inspiration, anger
Shareability 20% "Send this to a friend" factor
Pacing 15% Information density for Shorts

Score thresholds:

  • 9–10 — Guaranteed viral (rare)
  • 7–8 — High potential, publish these
  • 5–6 — Decent, missing one ingredient
  • < 5 — Poor fit for short-form

Caption Styles

Style Font Best for
tiktok Arial Black Bold karaoke, yellow highlight (default)
minimal Helvetica Professional, educational
bold_yellow Impact High-energy, entertainment

Database Schema

users               id, email, hashed_password, is_active
api_keys            id, user_id, provider, encrypted_key, label
videos              id, user_id, youtube_url, transcript (JSONB), status
clips               id, video_id, start/end_time, virality_score,
                    ai_title, ai_description, ai_hashtags, output_path, status
usage_logs          id, user_id, provider, input/output_tokens, estimated_cost_usd
publishing_logs     id, clip_id, youtube_video_id, status, metadata_used
youtube_credentials id, user_id, encrypted_access_token, encrypted_refresh_token

Running Tests

# All unit tests (no network, no DB required)
pytest tests/unit/ -v

# With coverage
pytest tests/unit/ --cov=app --cov-report=term-missing

# Integration tests (needs ffmpeg + network + running DB)
RUN_INTEGRATION=1 pytest tests/integration/ -v

Migrations

# After editing app/models/tables.py
alembic revision --autogenerate -m "describe change"
alembic upgrade head

# Rollback
alembic downgrade -1

YouTube Setup

  1. Google Cloud Console → Enable YouTube Data API v3
  2. OAuth consent screen → add scope youtube.upload
  3. Create OAuth 2.0 Web Application credentials
  4. Authorised redirect URI: http://localhost:8000/auth/youtube/callback
  5. Add YOUTUBE_CLIENT_ID + YOUTUBE_CLIENT_SECRET to .env

Security Notes

  • API keys encrypted with Fernet (AES-128-CBC + HMAC-SHA256) — DB dump is useless without FERNET_KEY
  • Passwords hashed with bcrypt (work factor 12)
  • Decrypted keys exist only in memory at request time, never logged
  • Rate limiting: 3 jobs/minute, 20 jobs/hour per user
  • JWT access tokens expire in 30 minutes, refresh tokens in 30 days

Tech Stack

Layer Tech
Backend FastAPI, SQLAlchemy (async), Alembic
Database PostgreSQL 16, Redis 7
AI Whisper (local), OpenAI, Anthropic, Google Gemini
Video ffmpeg, yt-dlp, libass
Auth python-jose, passlib, cryptography
Frontend React 18, Vite, Zustand, Axios, React Router
Publishing Google OAuth2, YouTube Data API v3

License

MIT

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors