WCA0202/Timbre-Audio-to-Brief
Timbre β Audio-to-Brief Engine
 
Timbre is a two-sided creative marketplace connecting clients who need music made with musicians, producers, and bands who make it. The core product is the Brief Engine β it translates a client's emotional description into a structured acoustic specification that musicians can actually execute.
Repository Structure
.
βββ app.py # Hugging Face / Gradio entry point + JSON API
βββ recommend_v2.py # Semantic matching engine (imported by app.py)
βββ requirements.txt # Production dependencies
β
βββ training/ # Offline data pipeline (run once)
β βββ download_songs_v2.py # Bulk YouTube downloader + Kworb Japan scraper
β βββ build_library.py # Scan songs/ β data/song_library.csv
β βββ download_models.py # Download Essentia .pb models (~500 MB)
β βββ extract_features.py # Feature + genre score extraction
β βββ get_song_emotions.py # Assign emotion labels
β βββ enrich_metadata.py # Refresh language + genre columns only
β
βββ data/ # Generated CSVs (gitignored)
β βββ song_features.csv # Source of truth β acoustic + genre data (~9,983 songs)
β βββ song_library.csv # Song index with language/ISRC
β
βββ ui/ # HF Space frontend assets
β βββ emotion_ui.html # Standalone interactive bubble UI
β
βββ docs/ # Project documentation
β βββ CONTRIBUTING.md # Dev setup, scripts, PR checklist
β βββ RUNBOOK.md # Deployments, health, rollback
β βββ ENV.md # Environment variables & secrets
β βββ architecture/
β β βββ backend.md # D1 + Workers + Stripe design notes
β βββ ε΅ζ₯θ¨εζΈ.md # Business plan (Chinese)
β
βββ web/ # timbrebrief.com β Vite + React SPA
βββ src/
β βββ App.jsx # Root β page router, global state (darkMode, lang)
β βββ theme.js # Light / dark design tokens
β βββ data.js # Sample data (emotions, brief, musicians)
β βββ pages/
β β βββ HomePage.jsx # Hero + Brief preview + trust strip
β β βββ ExplorePage.jsx # Emotion Explorer (full React port)
β β βββ HowClientsPage.jsx # 5-step editorial for clients
β β βββ HowMusiciansPage.jsx # 5-step editorial + commission split
β β βββ PricingPage.jsx # Two-column pricing + FAQ accordion
β β βββ OnboardingFlow.jsx # 6-step brief builder + Clerk auth
β β βββ Dashboards.jsx # Client dashboard, ProjectPage, MusicianDashboard
β βββ components/
β βββ Nav.jsx # Global nav β page links, dark mode, lang toggle
β βββ BriefDoc.jsx # Acoustic brief document component
β βββ EmotionExplorer.jsx # Compact bubble selector (legacy; onboarding now uses ExplorePage embedded)
β βββ EmotionCanvas.jsx # Canvas-based emotion visualization
β βββ AcousticRadar.jsx # Radar chart for acoustic features
β βββ MusicianCard.jsx # Musician match card
β βββ StatusPill.jsx # Project status badge
βββ public/
βββ songs.json # ~9,983 songs β normalized acoustic data for offline recsProduct Overview
Pages
Onboarding Flow (6 steps)
- Start β choose entry point: describe a feeling / upload reference tracks
- Explore β full
ExplorePage(4-layer bubble UI) embedded inline, or upload reference tracks - Purpose β placement context, audience, story, commercial vs. personal use
- Technical β tempo, length, instrumentation, stems, exclusivity, revisions (pre-filled from mood)
- Review β full
BriefDocpreview, all fields editable - Match β 3 musician cards matched to the brief; choose one to start the project
Business Model
- Clients β entirely free. Brief engine, Emotion Explorer, matching, project workspace, file delivery, messaging, milestone management.
- Musicians β no subscription, no pay-per-lead. One commission per completed project (the majority of the project fee stays with the musician). Shown as a line item on every transaction.
Trust & Safety Features
- Escrow payments β funds held until client approval
- Brief-as-contract β scope is locked at brief stage
- Dispute resolution β Timbre mediates
- Transparent commission β one line item, always visible
Emotion Explorer
A full-screen interactive 4-layer emotional journey implemented in React (ExplorePage.jsx), ported from the original vanilla JS ui/emotion_ui.html.
Layers:
- Core emotion β Joy, Calm, Sadness, Anger, Fear, Anticipation (click one or blend two)
- Nuance β 6 fine-grained descriptors per emotion
- Somatic sensation β where you feel it in the body
- Action urge β what the emotion wants to do
After completing the constellation:
- Emotion path is mapped to a weighted acoustic profile
- Top-25 matching songs are surfaced from
songs.json(fully offline β no API call) - Client view: paginated reference track list with YouTube search links
- Musician view: tracks + auto-generated Acoustic Brief (tempo, energy, tone, style tags, production suggestions)
Bilingual: full δΈζ / English support. Language toggle is global (in Nav) and switches the entire UI mid-session without losing state.
Recommendation Engine
Web (offline, ExplorePage.jsx)
- Constellation path β emotion key (from
LABEL_TO_KEYmap) - Emotion key β acoustic target profile from
EMOTION_PROFILES(valence, arousal, mood scores, danceability) - Songs from
songs.jsonscored:score = mood_dot_product β distance Γ 1.5 - Top 25 returned, paginated by 5
HF Space (recommend_v2.py)
- User text β cosine similarity against 16
EMOTION_DESCRIPTIONSviaparaphrase-multilingual-MiniLM-L12-v2 - Matched emotion β target feature vector from
MOOD_PROFILES - Songs ranked by Euclidean distance in normalized feature space
- Primary emotion label:
boost=100; neighbouring emotions:boost=30
Isolated ML Microservices (HF Spaces)
Two single-responsibility Gradio Spaces handle on-demand ML inference. Both are stateless and ephemeral β no CSV reads/writes.
WCA0202/Timbre-Feature-Extractor
Extracts acoustic features from an uploaded audio file using Essentia.
- Repo: github.com/willwang0202/Timbre-Feature-Extractor
- Models: Discogs-EffNet (mood heads + danceability), MusiCNN β DEAM (valence/arousal), RhythmExtractor2013 (BPM)
- Input: audio file (MP3, WAV, AAC, FLAC, M4A)
- Output:
{ "emotion": "melancholic", "features": { "bpm", "valence", "arousal", "mood_*", "danceability" } } - Web call:
@gradio/clientwithhandle_file(file); large WAV uploads use a longer analysis timeout than the Space startup/connect timeout. - API:
POST /call/analyze_audio { "data": [<audio>] } β { "event_id": "..." }
GET /call/analyze_audio/{event_id} β SSE streamWCA0202/Timbre-Text-to-Emotion
Classifies a free-text mood description into a Timbre emotion + acoustic target profile.
- Repo: github.com/willwang0202/Timbre-Text-to-Emotion
- Model:
j-hartmann/emotion-english-distilroberta-base(~82MB, DistilRoBERTa fine-tuned on 6 emotion labels) - Input: plain text string (e.g.
"driving alone at night, feeling weightless") - Output:
{ "emotion": "melancholic", "confidence": 0.87, "acoustic_profile": { "valence", "arousal", "bpm", "mood_*", "danceability" } } - API:
POST /call/classify_mood { "data": ["mood text"] } β { "event_id": "..." }
GET /call/classify_mood/{event_id} β SSE streamWhen to call which:
- Client uploads a track β
Timbre-Feature-Extractor - Client types a mood description β
Timbre-Text-to-Emotion - Client uses the Emotion Explorer bubble UI β offline scoring against
songs.json(no API call needed)
Running Locally
HF Space (Python/Gradio)
source .venv/bin/activate
python app.py
# http://0.0.0.0:7860Requires data/song_features.csv. If missing, run the data pipeline first.
Web Frontend
cd web
npm install
npm run dev # http://localhost:5173
npm run build # β web/dist/Environment variable (create web/.env.local):
VITE_CLERK_PUBLISHABLE_KEY=pk_live_...Data Pipeline (one-time setup)
# 1. Download songs via YouTube (global top 10,000)
python training/download_songs_v2.py
# 2. Download Japanese songs from Kworb.net
python training/download_songs_v2.py --japan
# 3. Scan songs/ β data/song_library.csv
python training/build_library.py
# 4. Download Essentia models (first time only, ~500 MB)
python training/download_models.py
# 5. Extract acoustic + genre features β data/song_features.csv
python training/extract_features.py
# 6. Assign emotion labels
python training/get_song_emotions.pyTo regenerate web/public/songs.json after updating data/song_features.csv:
node web/scripts/export-songs.mjsEnriching without re-extraction
python training/build_library.py
python training/enrich_metadata.pyDeployment
Web β Vercel
Configured via vercel.json at repo root.
- Build command:
cd web && npm install && npm run build - Build output:
web/dist - Env vars:
VITE_CLERK_PUBLISHABLE_KEY,VITE_SUPABASE_URL,VITE_SUPABASE_ANON_KEYβ set in Vercel dashboard
Domain: timbrebrief.com β registered on Cloudflare Registrar; DNS points at Vercel (A record 76.76.21.21, grey cloud).
Git Remotes
Always push to both:
git push origin main # β Hugging Face
git push github main # β GitHub / VercelAuth β Clerk
- Package:
@clerk/react - Production instance tied to
timbrebrief.com <ClerkProvider>inmain.jsxwith global theme tokens- Protected routes:
dashboard,project,musician-dashboard,onboardingβ redirect tologinwhen signed out unsafeMetadata.role:'client'or'musician'saved on signup
Tech Stack
Open TODOs
- Project workspace β project pages read Supabase projects/messages/milestones, store musician deliverables in private Supabase Storage, and move milestones through submit/approve/revision checkpoints; next step is Stripe capture + Connect payout on approved milestones
- Musician onboarding/profile β onboarding now saves matchable profile data to Supabase; next step is runtime audio analysis for uploaded portfolio files
- Clerk social connections β Google OAuth live; Spotify OAuth planned for reference-track import
- HF cold start β free-tier Spaces sleep after 48h; consider $9/mo always-on for Feature Extractor and Text-to-Emotion
- Wire Text-to-Emotion to frontend β
StepUploadβTimbre-Feature-Extractoris live;StepExplorefree-text input βTimbre-Text-to-Emotionnot yet wired (next step: add text input +/classify_moodcall inStepExplore) - ExplorePage dark mode β canvas and bubble UI currently hardcodes light cream palette regardless of
darkModeprop
License
All rights reserved. This codebase is proprietary and confidential. Access is granted solely for authorized use. No part of this software may be copied, modified, distributed, or used without explicit written permission from the copyright holder.
