karaoke-gen 0.71.42__py3-none-any.whl → 0.75.53__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- karaoke_gen/__init__.py +32 -1
- karaoke_gen/audio_fetcher.py +1220 -67
- karaoke_gen/audio_processor.py +15 -3
- karaoke_gen/instrumental_review/server.py +154 -860
- karaoke_gen/instrumental_review/static/index.html +1529 -0
- karaoke_gen/karaoke_finalise/karaoke_finalise.py +87 -2
- karaoke_gen/karaoke_gen.py +131 -14
- karaoke_gen/lyrics_processor.py +172 -4
- karaoke_gen/utils/bulk_cli.py +3 -0
- karaoke_gen/utils/cli_args.py +7 -4
- karaoke_gen/utils/gen_cli.py +221 -5
- karaoke_gen/utils/remote_cli.py +786 -43
- {karaoke_gen-0.71.42.dist-info → karaoke_gen-0.75.53.dist-info}/METADATA +109 -4
- {karaoke_gen-0.71.42.dist-info → karaoke_gen-0.75.53.dist-info}/RECORD +37 -31
- lyrics_transcriber/core/controller.py +76 -2
- lyrics_transcriber/frontend/package.json +1 -1
- lyrics_transcriber/frontend/src/App.tsx +6 -4
- lyrics_transcriber/frontend/src/api.ts +25 -10
- lyrics_transcriber/frontend/src/components/Header.tsx +38 -12
- lyrics_transcriber/frontend/src/components/LyricsAnalyzer.tsx +17 -3
- lyrics_transcriber/frontend/src/components/LyricsSynchronizer/SyncControls.tsx +185 -0
- lyrics_transcriber/frontend/src/components/LyricsSynchronizer/TimelineCanvas.tsx +704 -0
- lyrics_transcriber/frontend/src/components/LyricsSynchronizer/UpcomingWordsBar.tsx +80 -0
- lyrics_transcriber/frontend/src/components/LyricsSynchronizer/index.tsx +905 -0
- lyrics_transcriber/frontend/src/components/ModeSelectionModal.tsx +127 -0
- lyrics_transcriber/frontend/src/components/ReplaceAllLyricsModal.tsx +190 -542
- lyrics_transcriber/frontend/tsconfig.tsbuildinfo +1 -1
- lyrics_transcriber/frontend/web_assets/assets/{index-DdJTDWH3.js → index-BECn1o8Q.js} +1802 -553
- lyrics_transcriber/frontend/web_assets/assets/index-BECn1o8Q.js.map +1 -0
- lyrics_transcriber/frontend/web_assets/index.html +1 -1
- lyrics_transcriber/output/countdown_processor.py +39 -0
- lyrics_transcriber/review/server.py +5 -5
- lyrics_transcriber/transcribers/audioshake.py +96 -7
- lyrics_transcriber/types.py +14 -12
- lyrics_transcriber/frontend/web_assets/assets/index-DdJTDWH3.js.map +0 -1
- {karaoke_gen-0.71.42.dist-info → karaoke_gen-0.75.53.dist-info}/WHEEL +0 -0
- {karaoke_gen-0.71.42.dist-info → karaoke_gen-0.75.53.dist-info}/entry_points.txt +0 -0
- {karaoke_gen-0.71.42.dist-info → karaoke_gen-0.75.53.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: karaoke-gen
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.75.53
|
|
4
4
|
Summary: Generate karaoke videos with synchronized lyrics. Handles the entire process from downloading audio and lyrics to creating the final video with title screens.
|
|
5
5
|
License: MIT
|
|
6
6
|
License-File: LICENSE
|
|
@@ -22,7 +22,7 @@ Requires-Dist: dropbox (>=12)
|
|
|
22
22
|
Requires-Dist: fastapi (>=0.104.0)
|
|
23
23
|
Requires-Dist: fetch-lyrics-from-genius (>=0.1)
|
|
24
24
|
Requires-Dist: ffmpeg-python (>=0.2.0,<0.3.0)
|
|
25
|
-
Requires-Dist: flacfetch (>=0.
|
|
25
|
+
Requires-Dist: flacfetch (>=0.9.0)
|
|
26
26
|
Requires-Dist: fonttools (>=4.55)
|
|
27
27
|
Requires-Dist: google-api-python-client
|
|
28
28
|
Requires-Dist: google-auth
|
|
@@ -48,6 +48,8 @@ Requires-Dist: lyrics-converter (>=0.2.1)
|
|
|
48
48
|
Requires-Dist: lyricsgenius (>=3)
|
|
49
49
|
Requires-Dist: matplotlib (>=3)
|
|
50
50
|
Requires-Dist: metaphone (>=0.6)
|
|
51
|
+
Requires-Dist: mutagen (>=1.47)
|
|
52
|
+
Requires-Dist: nest-asyncio (>=1.5)
|
|
51
53
|
Requires-Dist: nltk (>=3.9)
|
|
52
54
|
Requires-Dist: numpy (>=2)
|
|
53
55
|
Requires-Dist: ollama (>=0.4.7)
|
|
@@ -93,7 +95,7 @@ Description-Content-Type: text/markdown
|
|
|
93
95
|
# Karaoke Generator 🎶 🎥 🚀
|
|
94
96
|
|
|
95
97
|

|
|
96
|
-

|
|
97
99
|

|
|
98
100
|

|
|
99
101
|
|
|
@@ -146,10 +148,44 @@ pip install karaoke-gen
|
|
|
146
148
|
This installs both `karaoke-gen` (local) and `karaoke-gen-remote` (cloud) CLIs.
|
|
147
149
|
|
|
148
150
|
### Requirements
|
|
149
|
-
- Python 3.10
|
|
151
|
+
- Python 3.10-3.13
|
|
150
152
|
- FFmpeg
|
|
151
153
|
- For local processing: CUDA-capable GPU or Apple Silicon CPU recommended
|
|
152
154
|
|
|
155
|
+
### Transcription Provider Setup
|
|
156
|
+
|
|
157
|
+
**Transcription is required** for creating karaoke videos with synchronized lyrics. The system needs word-level timing data to display lyrics in sync with the music.
|
|
158
|
+
|
|
159
|
+
#### Option 1: AudioShake (Recommended)
|
|
160
|
+
Commercial service with high-quality transcription. Best for production use.
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
export AUDIOSHAKE_API_TOKEN="your_audioshake_token"
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Get an API key at [https://www.audioshake.ai/](https://www.audioshake.ai/) - business only, at time of writing this.
|
|
167
|
+
|
|
168
|
+
#### Option 2: Whisper via RunPod
|
|
169
|
+
Open-source alternative using OpenAI's Whisper model on RunPod infrastructure.
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
export RUNPOD_API_KEY="your_runpod_key"
|
|
173
|
+
export WHISPER_RUNPOD_ID="your_whisper_endpoint_id"
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Set up a Whisper endpoint at [https://www.runpod.io/](https://www.runpod.io/)
|
|
177
|
+
|
|
178
|
+
#### Without Transcription (Instrumental Only)
|
|
179
|
+
If you don't need synchronized lyrics, use the `--skip-lyrics` flag:
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
karaoke-gen --skip-lyrics "Artist" "Title"
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
This creates an instrumental-only karaoke video without lyrics overlay.
|
|
186
|
+
|
|
187
|
+
> **Note:** See `lyrics_transcriber_temp/README.md` for detailed transcription provider configuration options.
|
|
188
|
+
|
|
153
189
|
---
|
|
154
190
|
|
|
155
191
|
## 🖥️ Local CLI (`karaoke-gen`)
|
|
@@ -275,6 +311,8 @@ karaoke-gen-remote \
|
|
|
275
311
|
| `REVIEW_UI_URL` | Lyrics review UI URL | `https://lyrics.nomadkaraoke.com` |
|
|
276
312
|
| `POLL_INTERVAL` | Seconds between status polls | `5` |
|
|
277
313
|
|
|
314
|
+
**Note:** The `REVIEW_UI_URL` defaults to the hosted lyrics review UI. For local development, set it to `http://localhost:5173` if you're running the frontend dev server.
|
|
315
|
+
|
|
278
316
|
### Authentication
|
|
279
317
|
|
|
280
318
|
The backend uses token-based authentication for admin operations (bulk delete, internal worker triggers). For basic job submission and monitoring, authentication is optional.
|
|
@@ -565,6 +603,73 @@ Check backend health status.
|
|
|
565
603
|
|
|
566
604
|
---
|
|
567
605
|
|
|
606
|
+
## 🔧 Troubleshooting
|
|
607
|
+
|
|
608
|
+
### "No suitable files found for processing"
|
|
609
|
+
|
|
610
|
+
This error occurs during the finalisation step when the `(With Vocals).mkv` file is missing. This file is created during lyrics transcription.
|
|
611
|
+
|
|
612
|
+
**Most common cause:** No transcription provider configured.
|
|
613
|
+
|
|
614
|
+
**Quick fix:**
|
|
615
|
+
1. Check if transcription providers are configured:
|
|
616
|
+
```bash
|
|
617
|
+
echo $AUDIOSHAKE_API_TOKEN
|
|
618
|
+
echo $RUNPOD_API_KEY
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
2. If both are empty, set up a provider (see [Transcription Provider Setup](#transcription-provider-setup))
|
|
622
|
+
|
|
623
|
+
3. Or use `--skip-lyrics` for instrumental-only karaoke:
|
|
624
|
+
```bash
|
|
625
|
+
karaoke-gen --skip-lyrics "Artist" "Title"
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
**Other causes:**
|
|
629
|
+
- Invalid API credentials - verify your tokens are correct and active
|
|
630
|
+
- API service unavailable - check service status pages
|
|
631
|
+
- Network connectivity issues - ensure you can reach the API endpoints
|
|
632
|
+
- Transcription timeout - try again or use a different provider
|
|
633
|
+
|
|
634
|
+
### Transcription Fails Silently
|
|
635
|
+
|
|
636
|
+
If karaoke-gen runs without errors but produces no synchronized lyrics:
|
|
637
|
+
|
|
638
|
+
1. **Check logs** - Run with `--log_level debug` for detailed output:
|
|
639
|
+
```bash
|
|
640
|
+
karaoke-gen --log_level debug "Artist" "Title"
|
|
641
|
+
```
|
|
642
|
+
|
|
643
|
+
2. **Verify environment variables** - Ensure API tokens are exported in your shell:
|
|
644
|
+
```bash
|
|
645
|
+
# Check if set
|
|
646
|
+
printenv | grep -E "(AUDIOSHAKE|RUNPOD|WHISPER)"
|
|
647
|
+
|
|
648
|
+
# Set in current session
|
|
649
|
+
export AUDIOSHAKE_API_TOKEN="your_token"
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
3. **Test API connectivity** - Verify you can reach the transcription service
|
|
653
|
+
|
|
654
|
+
### "No lyrics found from any source"
|
|
655
|
+
|
|
656
|
+
This warning means no reference lyrics were fetched from online sources (Genius, Spotify, Musixmatch). The transcription will still work, but auto-correction may be less accurate.
|
|
657
|
+
|
|
658
|
+
**To fix:**
|
|
659
|
+
- Set `GENIUS_API_TOKEN` for Genius lyrics
|
|
660
|
+
- Set `SPOTIFY_COOKIE_SP_DC` for Spotify lyrics
|
|
661
|
+
- Set `RAPIDAPI_KEY` for Musixmatch lyrics
|
|
662
|
+
- Or provide lyrics manually with `--lyrics_file /path/to/lyrics.txt`
|
|
663
|
+
|
|
664
|
+
### Video Quality Issues
|
|
665
|
+
|
|
666
|
+
If the output video has quality problems:
|
|
667
|
+
- Ensure FFmpeg is properly installed: `ffmpeg -version`
|
|
668
|
+
- Check available codecs: `ffmpeg -codecs`
|
|
669
|
+
- For 4K output, ensure sufficient disk space (10GB+ per track)
|
|
670
|
+
|
|
671
|
+
---
|
|
672
|
+
|
|
568
673
|
## 🧪 Development
|
|
569
674
|
|
|
570
675
|
### Running Tests
|
|
@@ -1,18 +1,19 @@
|
|
|
1
|
-
karaoke_gen/__init__.py,sha256=
|
|
2
|
-
karaoke_gen/audio_fetcher.py,sha256=
|
|
3
|
-
karaoke_gen/audio_processor.py,sha256=
|
|
1
|
+
karaoke_gen/__init__.py,sha256=wHpDbURJxmJAMNZ0uQjISv5MIT7KD9RWYi15xlYgEhU,1351
|
|
2
|
+
karaoke_gen/audio_fetcher.py,sha256=A1c7HxUbV4inhGuj9SySr3zkOSGKfAFovXu2TKzodSA,63811
|
|
3
|
+
karaoke_gen/audio_processor.py,sha256=YCMsxh-OSzC6h1Oqht8gh48j4KaRDuRIMUUsNNQxJeY,39913
|
|
4
4
|
karaoke_gen/config.py,sha256=LBZKpvwSgta8YoVX2GFFW-4CP22AyRtqsBn-KCeh8eg,2499
|
|
5
5
|
karaoke_gen/file_handler.py,sha256=jnPc4kFtG-PX-IVPHYWa7maXd4lNmbkKd1HogDNzgN8,16674
|
|
6
6
|
karaoke_gen/instrumental_review/__init__.py,sha256=91K9wPWfQnOqbINuhxtErPnXyY0gijdiF-69n-p3334,1382
|
|
7
7
|
karaoke_gen/instrumental_review/analyzer.py,sha256=Heg8TbrwM4g5IV7bavmO6EfVD4M0UGMs_qUoZguU_OQ,15022
|
|
8
8
|
karaoke_gen/instrumental_review/editor.py,sha256=_DGTjKMk5WhoGtLGtTvHzU522LJyQQ_DSY1r8fULuiA,11568
|
|
9
9
|
karaoke_gen/instrumental_review/models.py,sha256=cUSb_JheJK0cGdKx9f59-9sRvRrhrgdTdKBzQN3lHto,5226
|
|
10
|
-
karaoke_gen/instrumental_review/server.py,sha256=
|
|
10
|
+
karaoke_gen/instrumental_review/server.py,sha256=Ick90X77t2EeMRwtx2U08sSybadQyWH7G0tDG-4JqP4,19377
|
|
11
|
+
karaoke_gen/instrumental_review/static/index.html,sha256=EjMFxCQJOUSrsgwIXAW3R4bN6hYxDLmL4MHzoXxI4f0,59362
|
|
11
12
|
karaoke_gen/instrumental_review/waveform.py,sha256=Q6LBPZrJAD6mzZ7TmRf3Tf4gwYhUYTHumJKytLs3hSg,12940
|
|
12
13
|
karaoke_gen/karaoke_finalise/__init__.py,sha256=HqZ7TIhgt_tYZ-nb_NNCaejWAcF_aK-7wJY5TaW_keM,46
|
|
13
|
-
karaoke_gen/karaoke_finalise/karaoke_finalise.py,sha256=
|
|
14
|
-
karaoke_gen/karaoke_gen.py,sha256=
|
|
15
|
-
karaoke_gen/lyrics_processor.py,sha256=
|
|
14
|
+
karaoke_gen/karaoke_finalise/karaoke_finalise.py,sha256=Wn1KcdRyINT63UxKUPT9uB-bsrFVih0Im_cjXtequS0,93534
|
|
15
|
+
karaoke_gen/karaoke_gen.py,sha256=tfoywlSEI9qOi1krHTBafumXl3bcWxn6w0AN2vQ1nHs,57048
|
|
16
|
+
karaoke_gen/lyrics_processor.py,sha256=JrbTLmMR_jvcpuxsPihLXlCBKkFNKqYHvraw3_3KCPI,23263
|
|
16
17
|
karaoke_gen/metadata.py,sha256=SZW6TuUpkGGU98gRdjPfrR8F4vWXjnfCSGry2XD5_A4,6689
|
|
17
18
|
karaoke_gen/pipeline/__init__.py,sha256=-MZnba4qobr1qGDamG9CieLl2pWCZMEB5_Yur62RKeM,2106
|
|
18
19
|
karaoke_gen/pipeline/base.py,sha256=yg4LIm7Mc9ER0zCmZcUv4huEkotSSXK_0OAFio-TSNI,6235
|
|
@@ -33,10 +34,10 @@ karaoke_gen/resources/Oswald-SemiBold.ttf,sha256=G-vSJeeyEVft7D4s7FZQtGfXAViWPjz
|
|
|
33
34
|
karaoke_gen/resources/Zurich_Cn_BT_Bold.ttf,sha256=WNG5LOQ-uGUF_WWT5aQHzVbyWvQqGO5sZ4E-nRmvPuI,37780
|
|
34
35
|
karaoke_gen/style_loader.py,sha256=13010BVxwVgamRn8K8Z9fNgLBdPs9LFmWMRMLyBdits,17908
|
|
35
36
|
karaoke_gen/utils/__init__.py,sha256=FpOHyeBRB06f3zMoLBUJHTDZACrabg-DoyBTxNKYyNY,722
|
|
36
|
-
karaoke_gen/utils/bulk_cli.py,sha256=
|
|
37
|
-
karaoke_gen/utils/cli_args.py,sha256=
|
|
38
|
-
karaoke_gen/utils/gen_cli.py,sha256=
|
|
39
|
-
karaoke_gen/utils/remote_cli.py,sha256=
|
|
37
|
+
karaoke_gen/utils/bulk_cli.py,sha256=s2SXTnnQf7TM8Fk8yz9Cfd3Xl08uHBnve_rTkf4wE5g,19337
|
|
38
|
+
karaoke_gen/utils/cli_args.py,sha256=Td8fE1FisY1fcQuOoKlAQ6B3NF4bxGvSPDaQlpfY3T0,18172
|
|
39
|
+
karaoke_gen/utils/gen_cli.py,sha256=ahoVp_n298O8yUmFOBDsm4mLXgTuEb80mBnz4_mo4SM,44137
|
|
40
|
+
karaoke_gen/utils/remote_cli.py,sha256=l1iHUz_hrsbAfTvGDhA4gzr2g1CFBFc9np0nQ1jk1tQ,144629
|
|
40
41
|
karaoke_gen/video_background_processor.py,sha256=p3sryMxmkori4Uy2MYgmlk5_QQ7Uh9IoVJLAdkdLIUI,15124
|
|
41
42
|
karaoke_gen/video_generator.py,sha256=B7BQBrjkyvk3L3sctnPXnvr1rzkw0NYx5UCAl0ZiVx0,18464
|
|
42
43
|
lyrics_transcriber/__init__.py,sha256=g9ZbJg9U1qo7XzrC25J3bTKcNzzwUJWDVdi_7-hjcM4,412
|
|
@@ -44,7 +45,7 @@ lyrics_transcriber/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3
|
|
|
44
45
|
lyrics_transcriber/cli/cli_main.py,sha256=F72ENLTj934bXjHAUbRm0toCK73qnuJhwEm9agBVKHQ,11596
|
|
45
46
|
lyrics_transcriber/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
46
47
|
lyrics_transcriber/core/config.py,sha256=AM6RZKll8tzdZtMLgvHRQb1SxiXVPek0q4vmSWVUvEo,1368
|
|
47
|
-
lyrics_transcriber/core/controller.py,sha256=
|
|
48
|
+
lyrics_transcriber/core/controller.py,sha256=laeUakqT-0CoIyoBWYvv7kWxX-_wefWRwg2xrz84gRg,29432
|
|
48
49
|
lyrics_transcriber/correction/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
49
50
|
lyrics_transcriber/correction/agentic/__init__.py,sha256=p7PHiebuvRs8RDlPDs-9gLZKzXG5KfWg3fFCdDhY6pE,222
|
|
50
51
|
lyrics_transcriber/correction/agentic/adapter.py,sha256=Z0JBTAA7xlSdctCHqO9nBMl78C4XmqsLKKtS6BvNZNI,2912
|
|
@@ -124,7 +125,7 @@ lyrics_transcriber/frontend/REPLACE_ALL_FUNCTIONALITY.md,sha256=iRZbicW5satHel9g
|
|
|
124
125
|
lyrics_transcriber/frontend/__init__.py,sha256=nW8acRSWTjXoRwGqcTU4w-__X7tMAE0iXL0uihBN3CU,836
|
|
125
126
|
lyrics_transcriber/frontend/eslint.config.js,sha256=3ADH23ANA4NNBKFy6nCVk65e8bx1DrVd_FIaYNnhuqA,734
|
|
126
127
|
lyrics_transcriber/frontend/index.html,sha256=u1m7042a1kLWZVIElYQ9y-lzfIAdYJGtQE-i4Zjc3xY,806
|
|
127
|
-
lyrics_transcriber/frontend/package.json,sha256=
|
|
128
|
+
lyrics_transcriber/frontend/package.json,sha256=5krvXBc9deVYXREN9Pxw5N6ohiAsSCnPXnXlcb6p-U0,1182
|
|
128
129
|
lyrics_transcriber/frontend/public/android-chrome-192x192.png,sha256=lg-6aPF5mGLiuG7LyftZk_0RI41srmpA8wj-NkaaQms,17632
|
|
129
130
|
lyrics_transcriber/frontend/public/android-chrome-512x512.png,sha256=x-zuKT3NYsTqAWzhKRTZeD4-0uYoUjqMPZpKTChqNJ8,123447
|
|
130
131
|
lyrics_transcriber/frontend/public/apple-touch-icon.png,sha256=6y5vGra54w5oc8VP6sn2JjoQtN9hWTKn0YPhmdlmfU0,16188
|
|
@@ -132,8 +133,8 @@ lyrics_transcriber/frontend/public/favicon-16x16.png,sha256=2wy_7ZmVS4d7umByJVHQ
|
|
|
132
133
|
lyrics_transcriber/frontend/public/favicon-32x32.png,sha256=6TyrRMIw6G8dpG4_QWVTY8DMxo0bIGzc_9aOJrkiJKM,1297
|
|
133
134
|
lyrics_transcriber/frontend/public/favicon.ico,sha256=ZK7QvdBuZp0QxPkluCW4IKxfleFmFLp1KkG_d5xmx7E,15406
|
|
134
135
|
lyrics_transcriber/frontend/public/nomad-karaoke-logo.png,sha256=jTTBFXV6hGJGolZYQ-dIjgQQbMsehk5XGtsllhLrdzg,212641
|
|
135
|
-
lyrics_transcriber/frontend/src/App.tsx,sha256=
|
|
136
|
-
lyrics_transcriber/frontend/src/api.ts,sha256=
|
|
136
|
+
lyrics_transcriber/frontend/src/App.tsx,sha256=XI93-pX2p76ID45XUQTitDclUZHZ1kxhZZB2VriMV8k,6747
|
|
137
|
+
lyrics_transcriber/frontend/src/api.ts,sha256=GcjbOrlU7EdUpZ7MUPFqE1rtH-ckdw8wHtgyQxWateY,8648
|
|
137
138
|
lyrics_transcriber/frontend/src/components/AIFeedbackModal.tsx,sha256=N-M8LNKE3nCjrSkWTf8ObWSdBqD0Cv3Xiz_wVv9OtFo,3133
|
|
138
139
|
lyrics_transcriber/frontend/src/components/AddLyricsModal.tsx,sha256=ubJwQewryjUrXwpBkITQNu4POhoUtDbNA93cqa-yJKY,3416
|
|
139
140
|
lyrics_transcriber/frontend/src/components/AgenticCorrectionMetrics.tsx,sha256=Yg6FG0LtrneRfAYeBu3crt_RdN-_o7FojtYhDMDKi0o,8595
|
|
@@ -149,14 +150,19 @@ lyrics_transcriber/frontend/src/components/EditTimelineSection.tsx,sha256=VQy5fp
|
|
|
149
150
|
lyrics_transcriber/frontend/src/components/EditWordList.tsx,sha256=atl-9Z-24U-KWojwo0apTy1Y9DbQGoVo2dFX4P-1Z9E,13681
|
|
150
151
|
lyrics_transcriber/frontend/src/components/FileUpload.tsx,sha256=fwn2rMWtMLPTZLREMb3ps4prSf9nzxGwnjmeC6KYsJA,2383
|
|
151
152
|
lyrics_transcriber/frontend/src/components/FindReplaceModal.tsx,sha256=U7duKns4IqNXwbWFbQfdyaswnvkSRpfsU0UG__-Serc,20192
|
|
152
|
-
lyrics_transcriber/frontend/src/components/Header.tsx,sha256=
|
|
153
|
-
lyrics_transcriber/frontend/src/components/LyricsAnalyzer.tsx,sha256=
|
|
153
|
+
lyrics_transcriber/frontend/src/components/Header.tsx,sha256=KE8TirDEUgojgHjP9R4HTtCxaVr_CWumky-Es7xAGsE,18754
|
|
154
|
+
lyrics_transcriber/frontend/src/components/LyricsAnalyzer.tsx,sha256=TFo2HCr6k9bENsQm-AfT797ZyFLqvKDa8g5W-pw1v24,54256
|
|
155
|
+
lyrics_transcriber/frontend/src/components/LyricsSynchronizer/SyncControls.tsx,sha256=j4rQjBQVbaPsp1ra_rvEoCqmX3JFJdfNnFvj3BvfsgQ,6069
|
|
156
|
+
lyrics_transcriber/frontend/src/components/LyricsSynchronizer/TimelineCanvas.tsx,sha256=h-sAfDFm-DfayZbKuNJmbAqxmMr89oC26xI4WB45bxA,26896
|
|
157
|
+
lyrics_transcriber/frontend/src/components/LyricsSynchronizer/UpcomingWordsBar.tsx,sha256=BXkEeo5yMgHkeOCBcZKqxMb1rspjXH-X5_6X9Hl7z3E,2588
|
|
158
|
+
lyrics_transcriber/frontend/src/components/LyricsSynchronizer/index.tsx,sha256=jOAmlkodaGzceQLG11ihprFMcARVbeJ_qjMcUkQj5Oo,34275
|
|
154
159
|
lyrics_transcriber/frontend/src/components/MetricsDashboard.tsx,sha256=33XpyHj0siBQivE8vLgliyiwmdsAfnNQh5Py4mnhXi8,1724
|
|
160
|
+
lyrics_transcriber/frontend/src/components/ModeSelectionModal.tsx,sha256=eihGI49r9tKq-AaEtnmVrbiBOoJApWvabaZW4ydmg-4,5302
|
|
155
161
|
lyrics_transcriber/frontend/src/components/ModeSelector.tsx,sha256=HnBAK_gFgNBJLtMC_ESMVdUapDjmqmoLX8pQeyHfpOw,2651
|
|
156
162
|
lyrics_transcriber/frontend/src/components/ModelSelector.tsx,sha256=lfG_B5VAzSfrU0FqJl8XptN6DVt2kSljU96HMXo8mf4,559
|
|
157
163
|
lyrics_transcriber/frontend/src/components/PreviewVideoSection.tsx,sha256=59ZhG5XsxUZ_dkK8BjTQhYmYP5Wv86uRR-xtuwFRK8c,5582
|
|
158
164
|
lyrics_transcriber/frontend/src/components/ReferenceView.tsx,sha256=2ugpkVtxZLS6Al-lmYbMZj7d3w9e2qNNYKJjkSxZ_X8,10494
|
|
159
|
-
lyrics_transcriber/frontend/src/components/ReplaceAllLyricsModal.tsx,sha256=
|
|
165
|
+
lyrics_transcriber/frontend/src/components/ReplaceAllLyricsModal.tsx,sha256=pVlqHrSloxXZV_Ib8cbk1invF7WA3uge5b7pnFPe9Pc,12290
|
|
160
166
|
lyrics_transcriber/frontend/src/components/ReviewChangesModal.tsx,sha256=VQg_gBFViAxQu9Z75o6rOsvmH5DZBjKq9FkU8aB_7mI,13790
|
|
161
167
|
lyrics_transcriber/frontend/src/components/SegmentDetailsModal.tsx,sha256=6ME02FkFwCgDAxW49yW260N4vbr80eAJ332Ex811GOo,1643
|
|
162
168
|
lyrics_transcriber/frontend/src/components/TimelineEditor.tsx,sha256=gJRCxdmJo80g0h5hq5AtDHK-HbOoYhMaQYvP2WgOuRI,13201
|
|
@@ -188,7 +194,7 @@ lyrics_transcriber/frontend/src/vite-env.d.ts,sha256=ZZlpNvuwQpFfe3SiAPzd5-QQ8yp
|
|
|
188
194
|
lyrics_transcriber/frontend/tsconfig.app.json,sha256=7aUBVcaBqEtmtfQXsbwsgBxSUng06xzQi5t4QCgWQ3E,665
|
|
189
195
|
lyrics_transcriber/frontend/tsconfig.json,sha256=AOS5v1AsNPL3wGc8bt58Ybh8HHpbYrlK91q0KIzaSgs,627
|
|
190
196
|
lyrics_transcriber/frontend/tsconfig.node.json,sha256=oMBhK5xufBrVE7SkbADRxA3pxm8_L9m5YwtCOZSafsc,536
|
|
191
|
-
lyrics_transcriber/frontend/tsconfig.tsbuildinfo,sha256=
|
|
197
|
+
lyrics_transcriber/frontend/tsconfig.tsbuildinfo,sha256=TGnTUZG3ScMXJTHpm1GmyxtEte94DRXNrmWx6-VlB9M,2248
|
|
192
198
|
lyrics_transcriber/frontend/update_version.js,sha256=PxkqCnsucXnXiIqutsanVcx00Gq4k7pgCYj_uXCa4qw,411
|
|
193
199
|
lyrics_transcriber/frontend/vite.config.d.ts,sha256=S5bdGf0pSdKM6A6RNBKwAm3EIeW_bDHYfHtesRtXU7Q,76
|
|
194
200
|
lyrics_transcriber/frontend/vite.config.js,sha256=P4GuPgRZzwEWPQZpyujUe7eA3mjPoFAe2CgE5sQAXg8,232
|
|
@@ -196,12 +202,12 @@ lyrics_transcriber/frontend/vite.config.ts,sha256=8FdW0dN8zDFqfhQSxX5h7sIu72X2pi
|
|
|
196
202
|
lyrics_transcriber/frontend/web_assets/android-chrome-192x192.png,sha256=lg-6aPF5mGLiuG7LyftZk_0RI41srmpA8wj-NkaaQms,17632
|
|
197
203
|
lyrics_transcriber/frontend/web_assets/android-chrome-512x512.png,sha256=x-zuKT3NYsTqAWzhKRTZeD4-0uYoUjqMPZpKTChqNJ8,123447
|
|
198
204
|
lyrics_transcriber/frontend/web_assets/apple-touch-icon.png,sha256=6y5vGra54w5oc8VP6sn2JjoQtN9hWTKn0YPhmdlmfU0,16188
|
|
199
|
-
lyrics_transcriber/frontend/web_assets/assets/index-
|
|
200
|
-
lyrics_transcriber/frontend/web_assets/assets/index-
|
|
205
|
+
lyrics_transcriber/frontend/web_assets/assets/index-BECn1o8Q.js,sha256=yNW-EWYuyaj_16fGDyvCGkb2BGoCufHlpKquqOxzQac,1421945
|
|
206
|
+
lyrics_transcriber/frontend/web_assets/assets/index-BECn1o8Q.js.map,sha256=aY17CfmBvSG6FgnuQLzgc9V02xfaOimIIAo8l4fiAJk,3004853
|
|
201
207
|
lyrics_transcriber/frontend/web_assets/favicon-16x16.png,sha256=2wy_7ZmVS4d7umByJVHQ37DBB_8xrU9xfT1_konSXQI,604
|
|
202
208
|
lyrics_transcriber/frontend/web_assets/favicon-32x32.png,sha256=6TyrRMIw6G8dpG4_QWVTY8DMxo0bIGzc_9aOJrkiJKM,1297
|
|
203
209
|
lyrics_transcriber/frontend/web_assets/favicon.ico,sha256=ZK7QvdBuZp0QxPkluCW4IKxfleFmFLp1KkG_d5xmx7E,15406
|
|
204
|
-
lyrics_transcriber/frontend/web_assets/index.html,sha256=
|
|
210
|
+
lyrics_transcriber/frontend/web_assets/index.html,sha256=qqHYlM3VAy_3YJn3QgETGjR94XTWL3Ci_S-5_lHYgxw,830
|
|
205
211
|
lyrics_transcriber/frontend/web_assets/nomad-karaoke-logo.png,sha256=jTTBFXV6hGJGolZYQ-dIjgQQbMsehk5XGtsllhLrdzg,212641
|
|
206
212
|
lyrics_transcriber/frontend/yarn.lock,sha256=wtImLsCO1P1Lpkhc1jAN6IiHQ0As4xn39n0cwKoh4LM,131996
|
|
207
213
|
lyrics_transcriber/lyrics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -247,7 +253,7 @@ lyrics_transcriber/output/cdgmaker/transitions/wipeleft.png,sha256=7jY6Z-mdY94PE
|
|
|
247
253
|
lyrics_transcriber/output/cdgmaker/transitions/wipeout.png,sha256=YSLdv2RCGeSilOGt7PYTLAOlBfL4bofu8Vpj-PcskZo,9995
|
|
248
254
|
lyrics_transcriber/output/cdgmaker/transitions/wiperight.png,sha256=Dw3N6cqJaSwL3owDqyAM4W573EmdNnkjdiXhoxWC4yk,8443
|
|
249
255
|
lyrics_transcriber/output/cdgmaker/utils.py,sha256=TNcOnccegpxT3OogWQCexy8BrDqfihLAShMvqeM81cw,2945
|
|
250
|
-
lyrics_transcriber/output/countdown_processor.py,sha256=
|
|
256
|
+
lyrics_transcriber/output/countdown_processor.py,sha256=EsUmnamNiG3SRfqPsZjSH3BH81a9AUg7wIdtfDkW57s,10848
|
|
251
257
|
lyrics_transcriber/output/fonts/AvenirNext-Bold.ttf,sha256=YxgKz2OP46lwLPCpIZhVa8COi_9KRDSXw4n8dIHHQSs,327048
|
|
252
258
|
"lyrics_transcriber/output/fonts/DMSans-VariableFont_opsz,wght.ttf",sha256=7uav75vmxRukpMx8wqtPeNvaxqOzlBljO400geBzYYI,238984
|
|
253
259
|
lyrics_transcriber/output/fonts/DMSerifDisplay-Regular.ttf,sha256=mMHMLr3CMjEQgJ5cKlYEn8YSsHwSnDtxT-Qjn_n8ffM,72220
|
|
@@ -264,18 +270,18 @@ lyrics_transcriber/output/segment_resizer.py,sha256=rrgcQC28eExSAmGnm6ytkF-E-nH4
|
|
|
264
270
|
lyrics_transcriber/output/subtitles.py,sha256=TW8IFTedj7-jHDyKKLYk1rFSFmuk8qysrI83Lkc3x-o,19555
|
|
265
271
|
lyrics_transcriber/output/video.py,sha256=n6QtT3ljtx1t8CT9jmVTKSpdezF2gC0FJsYDDtkP5fE,24084
|
|
266
272
|
lyrics_transcriber/review/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
267
|
-
lyrics_transcriber/review/server.py,sha256=
|
|
273
|
+
lyrics_transcriber/review/server.py,sha256=_05ul0MsddKf8iTIg-NASVYkl9kBRo0M3WhWBxp79i8,29462
|
|
268
274
|
lyrics_transcriber/storage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
269
275
|
lyrics_transcriber/storage/dropbox.py,sha256=Dyam1ULTkoxD1X5trkZ5dGp5XhBGCn998moC8IS9-68,9804
|
|
270
276
|
lyrics_transcriber/transcribers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
271
|
-
lyrics_transcriber/transcribers/audioshake.py,sha256=
|
|
277
|
+
lyrics_transcriber/transcribers/audioshake.py,sha256=RihuLKzhhHfX7m5cjKISwIuTQkGWapCS29D6Qk3hR4U,15869
|
|
272
278
|
lyrics_transcriber/transcribers/base_transcriber.py,sha256=T3m4ZCwZ9Bpv6Jvb2hNcnllk-lmeNmADDJlSySBtP1Q,6480
|
|
273
279
|
lyrics_transcriber/transcribers/whisper.py,sha256=YcCB1ic9H6zL1GS0jD0emu8-qlcH0QVEjjjYB4aLlIQ,13260
|
|
274
|
-
lyrics_transcriber/types.py,sha256=
|
|
280
|
+
lyrics_transcriber/types.py,sha256=UJjaxhVd2o14AG4G8ToU598p0JeYdiTFjpG38jGCoYQ,27917
|
|
275
281
|
lyrics_transcriber/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
276
282
|
lyrics_transcriber/utils/word_utils.py,sha256=-cMGpj9UV4F6IsoDKAV2i1aiqSO8eI91HMAm_igtVMk,958
|
|
277
|
-
karaoke_gen-0.
|
|
278
|
-
karaoke_gen-0.
|
|
279
|
-
karaoke_gen-0.
|
|
280
|
-
karaoke_gen-0.
|
|
281
|
-
karaoke_gen-0.
|
|
283
|
+
karaoke_gen-0.75.53.dist-info/METADATA,sha256=DR2eCSIs1DM9Xudkimpy66AgxZRfYSYyzpBX-sxkhgE,20662
|
|
284
|
+
karaoke_gen-0.75.53.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
|
|
285
|
+
karaoke_gen-0.75.53.dist-info/entry_points.txt,sha256=xIyLe7K84ZyjO8L0_AmNectz93QjGSs5AkApMtlAd4g,160
|
|
286
|
+
karaoke_gen-0.75.53.dist-info/licenses/LICENSE,sha256=81R_4XwMZDODHD7JcZeUR8IiCU8AD7Ajl6bmwR9tYDk,1074
|
|
287
|
+
karaoke_gen-0.75.53.dist-info/RECORD,,
|
|
@@ -307,6 +307,37 @@ class LyricsTranscriber:
|
|
|
307
307
|
self.results.transcription_corrected = CorrectionResult.from_dict(corrections_data)
|
|
308
308
|
self.logger.info("Successfully loaded existing corrections data")
|
|
309
309
|
|
|
310
|
+
# Check if the loaded corrections have countdown padding applied
|
|
311
|
+
# This is important because the video needs to use padded audio to sync
|
|
312
|
+
# with the countdown-adjusted timestamps in the ASS subtitles
|
|
313
|
+
if self.output_config.add_countdown:
|
|
314
|
+
from lyrics_transcriber.output.countdown_processor import CountdownProcessor
|
|
315
|
+
|
|
316
|
+
countdown_processor = CountdownProcessor(
|
|
317
|
+
cache_dir=self.output_config.cache_dir,
|
|
318
|
+
logger=self.logger,
|
|
319
|
+
)
|
|
320
|
+
|
|
321
|
+
if countdown_processor.has_countdown(self.results.transcription_corrected):
|
|
322
|
+
self.logger.info(
|
|
323
|
+
"Loaded corrections have countdown - creating padded audio for video sync"
|
|
324
|
+
)
|
|
325
|
+
# Create padded audio file to match the countdown-adjusted timestamps
|
|
326
|
+
padded_audio_path = countdown_processor.create_padded_audio_only(self.audio_filepath)
|
|
327
|
+
self.audio_filepath = padded_audio_path
|
|
328
|
+
|
|
329
|
+
# Set countdown padding attributes on results
|
|
330
|
+
self.results.countdown_padding_added = True
|
|
331
|
+
self.results.countdown_padding_seconds = countdown_processor.COUNTDOWN_PADDING_SECONDS
|
|
332
|
+
self.results.padded_audio_filepath = padded_audio_path
|
|
333
|
+
|
|
334
|
+
self.logger.info(
|
|
335
|
+
f"Countdown padding applied: {countdown_processor.COUNTDOWN_PADDING_SECONDS}s. "
|
|
336
|
+
f"Using padded audio: {padded_audio_path}"
|
|
337
|
+
)
|
|
338
|
+
else:
|
|
339
|
+
self.logger.info("Loaded corrections do not have countdown - no padding needed")
|
|
340
|
+
|
|
310
341
|
# Skip to output generation
|
|
311
342
|
self.generate_outputs()
|
|
312
343
|
self.logger.info("Processing completed successfully using existing corrections")
|
|
@@ -363,7 +394,24 @@ class LyricsTranscriber:
|
|
|
363
394
|
|
|
364
395
|
def transcribe(self) -> None:
|
|
365
396
|
"""Run transcription using all available transcribers."""
|
|
366
|
-
|
|
397
|
+
provider_names = list(self.transcribers.keys())
|
|
398
|
+
|
|
399
|
+
if not provider_names:
|
|
400
|
+
self.logger.warning(
|
|
401
|
+
"Starting transcription with providers: [] - NO TRANSCRIPTION PROVIDERS CONFIGURED!\n"
|
|
402
|
+
"\n"
|
|
403
|
+
"This means no word-level timing data will be generated, and synchronized karaoke "
|
|
404
|
+
"lyrics cannot be created. The output will lack the '(With Vocals).mkv' video file.\n"
|
|
405
|
+
"\n"
|
|
406
|
+
"To enable transcription, configure at least one provider:\n"
|
|
407
|
+
" - AudioShake: Set AUDIOSHAKE_API_TOKEN environment variable\n"
|
|
408
|
+
" - Whisper/RunPod: Set RUNPOD_API_KEY and WHISPER_RUNPOD_ID environment variables\n"
|
|
409
|
+
"\n"
|
|
410
|
+
"See README.md 'Transcription Providers' section for detailed setup instructions."
|
|
411
|
+
)
|
|
412
|
+
else:
|
|
413
|
+
self.logger.info(f"Starting transcription with providers: {provider_names}")
|
|
414
|
+
self._log_provider_configuration_status()
|
|
367
415
|
|
|
368
416
|
for name, transcriber_info in self.transcribers.items():
|
|
369
417
|
self.logger.info(f"Running transcription with {name}")
|
|
@@ -376,7 +424,33 @@ class LyricsTranscriber:
|
|
|
376
424
|
self.logger.debug(f"Transcription completed for {name}")
|
|
377
425
|
|
|
378
426
|
if not self.results.transcription_results:
|
|
379
|
-
self.logger.warning(
|
|
427
|
+
self.logger.warning(
|
|
428
|
+
"No successful transcriptions from any provider. "
|
|
429
|
+
"Check that your API tokens are valid and the services are accessible."
|
|
430
|
+
)
|
|
431
|
+
|
|
432
|
+
def _log_provider_configuration_status(self) -> None:
|
|
433
|
+
"""Log detailed configuration status for each potential transcription provider."""
|
|
434
|
+
self.logger.debug("Transcription provider configuration status:")
|
|
435
|
+
|
|
436
|
+
# AudioShake status
|
|
437
|
+
if self.transcriber_config.audioshake_api_token:
|
|
438
|
+
self.logger.debug(" - AudioShake: CONFIGURED (API token provided)")
|
|
439
|
+
else:
|
|
440
|
+
self.logger.debug(" - AudioShake: NOT CONFIGURED (missing AUDIOSHAKE_API_TOKEN)")
|
|
441
|
+
|
|
442
|
+
# Whisper/RunPod status
|
|
443
|
+
has_runpod_key = bool(self.transcriber_config.runpod_api_key)
|
|
444
|
+
has_whisper_id = bool(self.transcriber_config.whisper_runpod_id)
|
|
445
|
+
|
|
446
|
+
if has_runpod_key and has_whisper_id:
|
|
447
|
+
self.logger.debug(" - Whisper (RunPod): CONFIGURED (API key and endpoint ID provided)")
|
|
448
|
+
elif has_runpod_key:
|
|
449
|
+
self.logger.debug(" - Whisper (RunPod): PARTIALLY CONFIGURED (missing WHISPER_RUNPOD_ID)")
|
|
450
|
+
elif has_whisper_id:
|
|
451
|
+
self.logger.debug(" - Whisper (RunPod): PARTIALLY CONFIGURED (missing RUNPOD_API_KEY)")
|
|
452
|
+
else:
|
|
453
|
+
self.logger.debug(" - Whisper (RunPod): NOT CONFIGURED (missing RUNPOD_API_KEY and WHISPER_RUNPOD_ID)")
|
|
380
454
|
|
|
381
455
|
def correct_lyrics(self) -> None:
|
|
382
456
|
"""Run lyrics correction using transcription and internet lyrics."""
|
|
@@ -19,25 +19,27 @@ export default function App() {
|
|
|
19
19
|
const params = new URLSearchParams(window.location.search)
|
|
20
20
|
const encodedApiUrl = params.get('baseApiUrl')
|
|
21
21
|
const audioHashParam = params.get('audioHash')
|
|
22
|
+
const reviewTokenParam = params.get('reviewToken')
|
|
22
23
|
|
|
23
24
|
if (encodedApiUrl) {
|
|
24
25
|
const baseApiUrl = decodeURIComponent(encodedApiUrl)
|
|
25
|
-
|
|
26
|
+
// Pass reviewToken to LiveApiClient for authentication
|
|
27
|
+
setApiClient(new LiveApiClient(baseApiUrl, reviewTokenParam || undefined))
|
|
26
28
|
setIsReadOnly(false)
|
|
27
29
|
if (audioHashParam) {
|
|
28
30
|
setAudioHash(audioHashParam)
|
|
29
31
|
}
|
|
30
32
|
// Fetch initial data
|
|
31
|
-
fetchData(baseApiUrl)
|
|
33
|
+
fetchData(baseApiUrl, reviewTokenParam || undefined)
|
|
32
34
|
} else {
|
|
33
35
|
setApiClient(new FileOnlyClient())
|
|
34
36
|
setIsReadOnly(true)
|
|
35
37
|
}
|
|
36
38
|
}, [])
|
|
37
39
|
|
|
38
|
-
const fetchData = async (baseUrl: string) => {
|
|
40
|
+
const fetchData = async (baseUrl: string, reviewToken?: string) => {
|
|
39
41
|
try {
|
|
40
|
-
const client = new LiveApiClient(baseUrl)
|
|
42
|
+
const client = new LiveApiClient(baseUrl, reviewToken)
|
|
41
43
|
const data = await client.getCorrectionData()
|
|
42
44
|
// console.log('Full correction data from API:', data)
|
|
43
45
|
setData(data)
|
|
@@ -35,14 +35,29 @@ interface AddLyricsRequest {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
export class LiveApiClient implements ApiClient {
|
|
38
|
-
|
|
38
|
+
private reviewToken?: string;
|
|
39
|
+
|
|
40
|
+
constructor(private baseUrl: string, reviewToken?: string) {
|
|
39
41
|
this.baseUrl = baseUrl.replace(/\/$/, '')
|
|
42
|
+
this.reviewToken = reviewToken
|
|
40
43
|
}
|
|
41
44
|
|
|
42
45
|
public isUpdatingHandlers = false;
|
|
43
46
|
|
|
47
|
+
/**
|
|
48
|
+
* Build URL with reviewToken query parameter if available
|
|
49
|
+
*/
|
|
50
|
+
private buildUrl(path: string): string {
|
|
51
|
+
const url = `${this.baseUrl}${path}`
|
|
52
|
+
if (this.reviewToken) {
|
|
53
|
+
const separator = url.includes('?') ? '&' : '?'
|
|
54
|
+
return `${url}${separator}review_token=${encodeURIComponent(this.reviewToken)}`
|
|
55
|
+
}
|
|
56
|
+
return url
|
|
57
|
+
}
|
|
58
|
+
|
|
44
59
|
async getCorrectionData(): Promise<CorrectionData> {
|
|
45
|
-
const response = await fetch(
|
|
60
|
+
const response = await fetch(this.buildUrl('/correction-data'));
|
|
46
61
|
if (!response.ok) {
|
|
47
62
|
throw new Error(`API error: ${response.statusText}`);
|
|
48
63
|
}
|
|
@@ -64,7 +79,7 @@ export class LiveApiClient implements ApiClient {
|
|
|
64
79
|
corrected_segments: data.corrected_segments
|
|
65
80
|
};
|
|
66
81
|
|
|
67
|
-
const response = await fetch(
|
|
82
|
+
const response = await fetch(this.buildUrl('/complete'), {
|
|
68
83
|
method: 'POST',
|
|
69
84
|
headers: {
|
|
70
85
|
'Content-Type': 'application/json',
|
|
@@ -78,7 +93,7 @@ export class LiveApiClient implements ApiClient {
|
|
|
78
93
|
}
|
|
79
94
|
|
|
80
95
|
getAudioUrl(audioHash: string): string {
|
|
81
|
-
return
|
|
96
|
+
return this.buildUrl(`/audio/${audioHash}`)
|
|
82
97
|
}
|
|
83
98
|
|
|
84
99
|
async generatePreviewVideo(data: CorrectionData): Promise<PreviewVideoResponse> {
|
|
@@ -88,7 +103,7 @@ export class LiveApiClient implements ApiClient {
|
|
|
88
103
|
corrected_segments: data.corrected_segments
|
|
89
104
|
};
|
|
90
105
|
|
|
91
|
-
const response = await fetch(
|
|
106
|
+
const response = await fetch(this.buildUrl('/preview-video'), {
|
|
92
107
|
method: 'POST',
|
|
93
108
|
headers: {
|
|
94
109
|
'Content-Type': 'application/json',
|
|
@@ -107,7 +122,7 @@ export class LiveApiClient implements ApiClient {
|
|
|
107
122
|
}
|
|
108
123
|
|
|
109
124
|
getPreviewVideoUrl(previewHash: string): string {
|
|
110
|
-
return
|
|
125
|
+
return this.buildUrl(`/preview-video/${previewHash}`);
|
|
111
126
|
}
|
|
112
127
|
|
|
113
128
|
async updateHandlers(enabledHandlers: string[]): Promise<CorrectionData> {
|
|
@@ -116,7 +131,7 @@ export class LiveApiClient implements ApiClient {
|
|
|
116
131
|
console.log('API: Set isUpdatingHandlers to', this.isUpdatingHandlers);
|
|
117
132
|
|
|
118
133
|
try {
|
|
119
|
-
const response = await fetch(
|
|
134
|
+
const response = await fetch(this.buildUrl('/handlers'), {
|
|
120
135
|
method: 'POST',
|
|
121
136
|
headers: {
|
|
122
137
|
'Content-Type': 'application/json',
|
|
@@ -147,7 +162,7 @@ export class LiveApiClient implements ApiClient {
|
|
|
147
162
|
lyrics
|
|
148
163
|
};
|
|
149
164
|
|
|
150
|
-
const response = await fetch(
|
|
165
|
+
const response = await fetch(this.buildUrl('/add-lyrics'), {
|
|
151
166
|
method: 'POST',
|
|
152
167
|
headers: {
|
|
153
168
|
'Content-Type': 'application/json',
|
|
@@ -170,7 +185,7 @@ export class LiveApiClient implements ApiClient {
|
|
|
170
185
|
async submitAnnotations(annotations: Omit<CorrectionAnnotation, 'annotation_id' | 'timestamp'>[]): Promise<void> {
|
|
171
186
|
// Submit each annotation to the backend
|
|
172
187
|
for (const annotation of annotations) {
|
|
173
|
-
const response = await fetch(
|
|
188
|
+
const response = await fetch(this.buildUrl('/v1/annotations'), {
|
|
174
189
|
method: 'POST',
|
|
175
190
|
headers: {
|
|
176
191
|
'Content-Type': 'application/json',
|
|
@@ -186,7 +201,7 @@ export class LiveApiClient implements ApiClient {
|
|
|
186
201
|
}
|
|
187
202
|
|
|
188
203
|
async getAnnotationStats(): Promise<any> {
|
|
189
|
-
const response = await fetch(
|
|
204
|
+
const response = await fetch(this.buildUrl('/v1/annotations/stats'));
|
|
190
205
|
if (!response.ok) {
|
|
191
206
|
throw new Error(`API error: ${response.statusText}`);
|
|
192
207
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Box, Button, Typography, useMediaQuery, useTheme, Switch, FormControlLabel, Tooltip, Paper, IconButton } from '@mui/material'
|
|
1
|
+
import { Box, Button, Typography, useMediaQuery, useTheme, Switch, FormControlLabel, Tooltip, Paper, IconButton, Chip } from '@mui/material'
|
|
2
2
|
import LockIcon from '@mui/icons-material/Lock'
|
|
3
3
|
import UploadFileIcon from '@mui/icons-material/UploadFile'
|
|
4
4
|
import FindReplaceIcon from '@mui/icons-material/FindReplace'
|
|
@@ -7,6 +7,7 @@ import UndoIcon from '@mui/icons-material/Undo'
|
|
|
7
7
|
import RedoIcon from '@mui/icons-material/Redo'
|
|
8
8
|
import TimerIcon from '@mui/icons-material/Timer'
|
|
9
9
|
import RestoreIcon from '@mui/icons-material/Restore'
|
|
10
|
+
import RateReviewIcon from '@mui/icons-material/RateReview'
|
|
10
11
|
import { CorrectionData, InteractionMode } from '../types'
|
|
11
12
|
import CorrectionMetrics from './CorrectionMetrics'
|
|
12
13
|
import AgenticCorrectionMetrics from './AgenticCorrectionMetrics'
|
|
@@ -41,6 +42,8 @@ interface HeaderProps {
|
|
|
41
42
|
onRedo: () => void
|
|
42
43
|
canUndo: boolean
|
|
43
44
|
canRedo: boolean
|
|
45
|
+
annotationsEnabled?: boolean
|
|
46
|
+
onAnnotationsToggle?: (enabled: boolean) => void
|
|
44
47
|
}
|
|
45
48
|
|
|
46
49
|
export default function Header({
|
|
@@ -65,6 +68,8 @@ export default function Header({
|
|
|
65
68
|
onRedo,
|
|
66
69
|
canUndo,
|
|
67
70
|
canRedo,
|
|
71
|
+
annotationsEnabled = true,
|
|
72
|
+
onAnnotationsToggle,
|
|
68
73
|
}: HeaderProps) {
|
|
69
74
|
const theme = useTheme()
|
|
70
75
|
const isMobile = useMediaQuery(theme.breakpoints.down('md'))
|
|
@@ -135,17 +140,38 @@ export default function Header({
|
|
|
135
140
|
<Typography variant="h4" sx={{ fontSize: isMobile ? '1.3rem' : '1.5rem' }}>
|
|
136
141
|
Nomad Karaoke: Lyrics Transcription Review
|
|
137
142
|
</Typography>
|
|
138
|
-
{
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
143
|
+
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
|
144
|
+
{!isReadOnly && onAnnotationsToggle && (
|
|
145
|
+
<Tooltip title={annotationsEnabled
|
|
146
|
+
? "Click to disable annotation prompts when editing"
|
|
147
|
+
: "Click to enable annotation prompts when editing"
|
|
148
|
+
}>
|
|
149
|
+
<Chip
|
|
150
|
+
icon={<RateReviewIcon />}
|
|
151
|
+
label={annotationsEnabled ? "Feedback On" : "Feedback Off"}
|
|
152
|
+
onClick={() => onAnnotationsToggle(!annotationsEnabled)}
|
|
153
|
+
color={annotationsEnabled ? "primary" : "default"}
|
|
154
|
+
variant={annotationsEnabled ? "filled" : "outlined"}
|
|
155
|
+
size="small"
|
|
156
|
+
sx={{
|
|
157
|
+
cursor: 'pointer',
|
|
158
|
+
'& .MuiChip-icon': { fontSize: '1rem' }
|
|
159
|
+
}}
|
|
160
|
+
/>
|
|
161
|
+
</Tooltip>
|
|
162
|
+
)}
|
|
163
|
+
{isReadOnly && (
|
|
164
|
+
<Button
|
|
165
|
+
variant="outlined"
|
|
166
|
+
size="small"
|
|
167
|
+
startIcon={<UploadFileIcon />}
|
|
168
|
+
onClick={onFileLoad}
|
|
169
|
+
fullWidth={isMobile}
|
|
170
|
+
>
|
|
171
|
+
Load File
|
|
172
|
+
</Button>
|
|
173
|
+
)}
|
|
174
|
+
</Box>
|
|
149
175
|
</Box>
|
|
150
176
|
|
|
151
177
|
<Box sx={{
|