Extract time-aligned chord progressions from YouTube videos or audio files and explore them in an interactive chord chart — no sign-up required.
Paste a YouTube URL (or upload an audio file), and Harmonic runs a chord-detection pipeline that returns a synchronized chord chart you can scrub through while the audio plays. The pipeline detects key, tempo, beats, and chords, then quantizes them into a clean visualization.
| Layer | Stack |
|---|---|
| Frontend | React 19, TypeScript, Vite, Tailwind CSS |
| Backend | FastAPI, Uvicorn, LibROSA, Madmom |
| Audio input | yt-dlp + bgutil-ytdlp-pot-provider |
| Chord recognition | DeepChromaRecognizer with beat quantization |
| Deployment | Docker Compose, Caddy, Hetzner VPS, GitHub Actions |
- Bun ≥ 1.0
- Python 3.11
- ffmpeg (required by yt-dlp for audio conversion)
Install ffmpeg on macOS:
brew install ffmpegcd backend
python3.11 -m venv .venv
.venv/bin/pip install -r requirements.txt
bash scripts/setup_madmom.shsetup_madmom.sh patches Madmom for Python 3.11 and NumPy 1.26 compatibility. Run it every time after installing/updating dependencies.
cd frontend
bun installStart both servers in separate terminals.
Terminal 1 — backend:
cd backend
.venv/bin/uvicorn app.main:app --reload --host 0.0.0.0 --port 8000Terminal 2 — frontend:
cd frontend
bun run devOpen http://localhost:5173. The Vite dev server proxies all /api requests to the backend at port 8000.
| Variable | Default | Description |
|---|---|---|
CORS_ORIGINS |
http://localhost:5173 |
Comma-separated allowed origins (backend) |
VITE_API_URL |
`` (empty) | API base URL for frontend — empty uses the Vite proxy in dev; set to your API domain in production |
No .env file is needed for local development.
Backend:
cd backend
.venv/bin/pytestFrontend:
cd frontend
bun run testdocker-compose up -dThis starts the FastAPI backend and the bgutil-pot YouTube proxy service. Set CORS_ORIGINS in docker-compose.yml to match your frontend domain before deploying.
All routes are prefixed with /api.
| Method | Path | Description |
|---|---|---|
POST |
/analyze |
Submit a YouTube URL or audio file |
GET |
/status/{job_id} |
Poll job progress |
GET |
/results/{job_id} |
Fetch completed chord results |
DELETE |
/job/{job_id} |
Cancel and delete a job |
See DEPLOYING.md for a full guide to deploying on a Hetzner VPS with Caddy and GitHub Actions CI/CD.
Required GitHub Actions secrets:
| Secret | Purpose |
|---|---|
VPS_HOST |
IP or hostname of the server |
VPS_SSH_KEY |
Private key for SSH access |
VITE_API_URL |
Public API URL injected at frontend build time |