karaoke-gen 0.103.1__py3-none-any.whl → 0.107.0__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.
- backend/Dockerfile.base +1 -0
- backend/api/routes/admin.py +226 -3
- backend/api/routes/push.py +238 -0
- backend/api/routes/users.py +14 -3
- backend/config.py +12 -1
- backend/main.py +2 -1
- backend/models/job.py +4 -0
- backend/models/user.py +20 -2
- backend/services/encoding_interface.py +4 -0
- backend/services/gce_encoding/main.py +22 -8
- backend/services/job_manager.py +68 -11
- backend/services/job_notification_service.py +4 -21
- backend/services/push_notification_service.py +409 -0
- backend/services/stripe_service.py +2 -2
- backend/tests/conftest.py +2 -1
- backend/tests/test_admin_delete_outputs.py +352 -0
- backend/tests/test_gce_encoding_worker.py +229 -0
- backend/tests/test_impersonation.py +18 -3
- backend/tests/test_job_notification_service.py +24 -58
- backend/tests/test_push_notification_service.py +460 -0
- backend/tests/test_push_routes.py +357 -0
- backend/tests/test_stripe_service.py +205 -0
- backend/tests/test_video_worker_orchestrator.py +189 -0
- backend/workers/video_worker_orchestrator.py +23 -0
- karaoke_gen/instrumental_review/server.py +145 -35
- karaoke_gen/nextjs_frontend/__init__.py +98 -0
- karaoke_gen/nextjs_frontend/out/404/index.html +1 -0
- karaoke_gen/nextjs_frontend/out/404.html +1 -0
- karaoke_gen/nextjs_frontend/out/__next.__PAGE__.txt +9 -0
- karaoke_gen/nextjs_frontend/out/__next._full.txt +22 -0
- karaoke_gen/nextjs_frontend/out/__next._head.txt +8 -0
- karaoke_gen/nextjs_frontend/out/__next._index.txt +9 -0
- karaoke_gen/nextjs_frontend/out/__next._tree.txt +2 -0
- karaoke_gen/nextjs_frontend/out/_next/static/chunks/01a7f8fe40f1ff47.js +1 -0
- karaoke_gen/nextjs_frontend/out/_next/static/chunks/112f346e31f991df.js +4 -0
- karaoke_gen/nextjs_frontend/out/_next/static/chunks/16d1a4dd9d8a873a.js +3 -0
- karaoke_gen/nextjs_frontend/out/_next/static/chunks/1ab85c362b8b0e86.js +9 -0
- karaoke_gen/nextjs_frontend/out/_next/static/chunks/247eb132b7f7b574.js +1 -0
- karaoke_gen/nextjs_frontend/out/_next/static/chunks/2b80d15cc95e4818.js +1 -0
- karaoke_gen/nextjs_frontend/out/_next/static/chunks/32c7eba5cd46c1bc.js +7 -0
- karaoke_gen/nextjs_frontend/out/_next/static/chunks/483f26794eae53d0.js +1 -0
- karaoke_gen/nextjs_frontend/out/_next/static/chunks/550c3b02e85f196a.js +1 -0
- karaoke_gen/nextjs_frontend/out/_next/static/chunks/55c5ade44387bef8.js +1 -0
- karaoke_gen/nextjs_frontend/out/_next/static/chunks/5628d92b5893add2.css +1 -0
- karaoke_gen/nextjs_frontend/out/_next/static/chunks/56ebf7665e4341c8.js +7 -0
- karaoke_gen/nextjs_frontend/out/_next/static/chunks/5997132b61dec430.js +1 -0
- karaoke_gen/nextjs_frontend/out/_next/static/chunks/5ea55255bce3eb9e.js +5 -0
- karaoke_gen/nextjs_frontend/out/_next/static/chunks/5eda89a57490b3cd.js +1 -0
- karaoke_gen/nextjs_frontend/out/_next/static/chunks/692f5d9e0d700c76.js +3 -0
- karaoke_gen/nextjs_frontend/out/_next/static/chunks/71d7a05b14f9f0f4.js +1 -0
- karaoke_gen/nextjs_frontend/out/_next/static/chunks/81ac355749ef3302.js +1 -0
- karaoke_gen/nextjs_frontend/out/_next/static/chunks/95f7e5934dbb0e5d.js +1 -0
- karaoke_gen/nextjs_frontend/out/_next/static/chunks/9bce8f19eaa46940.js +1 -0
- karaoke_gen/nextjs_frontend/out/_next/static/chunks/a6dad97d9634a72d.js +1 -0
- karaoke_gen/nextjs_frontend/out/_next/static/chunks/a9ed54eed3e14c92.js +2 -0
- karaoke_gen/nextjs_frontend/out/_next/static/chunks/b35cd41238ecfb17.js +1 -0
- karaoke_gen/nextjs_frontend/out/_next/static/chunks/b5bc3c3d5ebd49eb.js +1 -0
- karaoke_gen/nextjs_frontend/out/_next/static/chunks/b5c078c08db5ae32.js +5 -0
- karaoke_gen/nextjs_frontend/out/_next/static/chunks/be9c44a178104187.js +1 -0
- karaoke_gen/nextjs_frontend/out/_next/static/chunks/c4c840e18cb4861c.js +1 -0
- karaoke_gen/nextjs_frontend/out/_next/static/chunks/c645af7d6b65f73e.js +1 -0
- karaoke_gen/nextjs_frontend/out/_next/static/chunks/d2c5e2575df784d4.js +1 -0
- karaoke_gen/nextjs_frontend/out/_next/static/chunks/d30af02b96d81462.js +1 -0
- karaoke_gen/nextjs_frontend/out/_next/static/chunks/d9bdf64f4ec1e9b7.js +7 -0
- karaoke_gen/nextjs_frontend/out/_next/static/chunks/dcde6ed684dacd0e.js +5 -0
- karaoke_gen/nextjs_frontend/out/_next/static/chunks/e422cbe931246000.js +1 -0
- karaoke_gen/nextjs_frontend/out/_next/static/chunks/e483af34fc792d38.js +1 -0
- karaoke_gen/nextjs_frontend/out/_next/static/chunks/e57422aad6b897da.js +1 -0
- karaoke_gen/nextjs_frontend/out/_next/static/chunks/ef02697fb404726a.js +1 -0
- karaoke_gen/nextjs_frontend/out/_next/static/chunks/ff1a16fafef87110.js +1 -0
- karaoke_gen/nextjs_frontend/out/_next/static/chunks/turbopack-2d9ca3017a9deedf.js +3 -0
- karaoke_gen/nextjs_frontend/out/_next/static/zpw_-rjFIDV5tlPPtnvRI/_buildManifest.js +11 -0
- karaoke_gen/nextjs_frontend/out/_next/static/zpw_-rjFIDV5tlPPtnvRI/_clientMiddlewareManifest.json +1 -0
- karaoke_gen/nextjs_frontend/out/_next/static/zpw_-rjFIDV5tlPPtnvRI/_ssgManifest.js +1 -0
- karaoke_gen/nextjs_frontend/out/_not-found/__next._full.txt +18 -0
- karaoke_gen/nextjs_frontend/out/_not-found/__next._head.txt +8 -0
- karaoke_gen/nextjs_frontend/out/_not-found/__next._index.txt +9 -0
- karaoke_gen/nextjs_frontend/out/_not-found/__next._not-found.__PAGE__.txt +5 -0
- karaoke_gen/nextjs_frontend/out/_not-found/__next._not-found.txt +4 -0
- karaoke_gen/nextjs_frontend/out/_not-found/__next._tree.txt +2 -0
- karaoke_gen/nextjs_frontend/out/_not-found/index.html +1 -0
- karaoke_gen/nextjs_frontend/out/_not-found/index.txt +18 -0
- karaoke_gen/nextjs_frontend/out/admin/__next._full.txt +25 -0
- karaoke_gen/nextjs_frontend/out/admin/__next._head.txt +8 -0
- karaoke_gen/nextjs_frontend/out/admin/__next._index.txt +9 -0
- karaoke_gen/nextjs_frontend/out/admin/__next._tree.txt +2 -0
- karaoke_gen/nextjs_frontend/out/admin/__next.admin.__PAGE__.txt +9 -0
- karaoke_gen/nextjs_frontend/out/admin/__next.admin.txt +7 -0
- karaoke_gen/nextjs_frontend/out/admin/beta/__next._full.txt +25 -0
- karaoke_gen/nextjs_frontend/out/admin/beta/__next._head.txt +8 -0
- karaoke_gen/nextjs_frontend/out/admin/beta/__next._index.txt +9 -0
- karaoke_gen/nextjs_frontend/out/admin/beta/__next._tree.txt +2 -0
- karaoke_gen/nextjs_frontend/out/admin/beta/__next.admin.beta.__PAGE__.txt +9 -0
- karaoke_gen/nextjs_frontend/out/admin/beta/__next.admin.beta.txt +4 -0
- karaoke_gen/nextjs_frontend/out/admin/beta/__next.admin.txt +7 -0
- karaoke_gen/nextjs_frontend/out/admin/beta/index.html +1 -0
- karaoke_gen/nextjs_frontend/out/admin/beta/index.txt +25 -0
- karaoke_gen/nextjs_frontend/out/admin/index.html +1 -0
- karaoke_gen/nextjs_frontend/out/admin/index.txt +25 -0
- karaoke_gen/nextjs_frontend/out/admin/jobs/__next._full.txt +25 -0
- karaoke_gen/nextjs_frontend/out/admin/jobs/__next._head.txt +8 -0
- karaoke_gen/nextjs_frontend/out/admin/jobs/__next._index.txt +9 -0
- karaoke_gen/nextjs_frontend/out/admin/jobs/__next._tree.txt +2 -0
- karaoke_gen/nextjs_frontend/out/admin/jobs/__next.admin.jobs.__PAGE__.txt +9 -0
- karaoke_gen/nextjs_frontend/out/admin/jobs/__next.admin.jobs.txt +4 -0
- karaoke_gen/nextjs_frontend/out/admin/jobs/__next.admin.txt +7 -0
- karaoke_gen/nextjs_frontend/out/admin/jobs/index.html +1 -0
- karaoke_gen/nextjs_frontend/out/admin/jobs/index.txt +25 -0
- karaoke_gen/nextjs_frontend/out/admin/rate-limits/__next._full.txt +25 -0
- karaoke_gen/nextjs_frontend/out/admin/rate-limits/__next._head.txt +8 -0
- karaoke_gen/nextjs_frontend/out/admin/rate-limits/__next._index.txt +9 -0
- karaoke_gen/nextjs_frontend/out/admin/rate-limits/__next._tree.txt +2 -0
- karaoke_gen/nextjs_frontend/out/admin/rate-limits/__next.admin.rate-limits.__PAGE__.txt +9 -0
- karaoke_gen/nextjs_frontend/out/admin/rate-limits/__next.admin.rate-limits.txt +4 -0
- karaoke_gen/nextjs_frontend/out/admin/rate-limits/__next.admin.txt +7 -0
- karaoke_gen/nextjs_frontend/out/admin/rate-limits/index.html +1 -0
- karaoke_gen/nextjs_frontend/out/admin/rate-limits/index.txt +25 -0
- karaoke_gen/nextjs_frontend/out/admin/searches/__next._full.txt +25 -0
- karaoke_gen/nextjs_frontend/out/admin/searches/__next._head.txt +8 -0
- karaoke_gen/nextjs_frontend/out/admin/searches/__next._index.txt +9 -0
- karaoke_gen/nextjs_frontend/out/admin/searches/__next._tree.txt +2 -0
- karaoke_gen/nextjs_frontend/out/admin/searches/__next.admin.searches.__PAGE__.txt +9 -0
- karaoke_gen/nextjs_frontend/out/admin/searches/__next.admin.searches.txt +4 -0
- karaoke_gen/nextjs_frontend/out/admin/searches/__next.admin.txt +7 -0
- karaoke_gen/nextjs_frontend/out/admin/searches/index.html +1 -0
- karaoke_gen/nextjs_frontend/out/admin/searches/index.txt +25 -0
- karaoke_gen/nextjs_frontend/out/admin/users/__next._full.txt +25 -0
- karaoke_gen/nextjs_frontend/out/admin/users/__next._head.txt +8 -0
- karaoke_gen/nextjs_frontend/out/admin/users/__next._index.txt +9 -0
- karaoke_gen/nextjs_frontend/out/admin/users/__next._tree.txt +2 -0
- karaoke_gen/nextjs_frontend/out/admin/users/__next.admin.txt +7 -0
- karaoke_gen/nextjs_frontend/out/admin/users/__next.admin.users.__PAGE__.txt +9 -0
- karaoke_gen/nextjs_frontend/out/admin/users/__next.admin.users.txt +4 -0
- karaoke_gen/nextjs_frontend/out/admin/users/detail/__next._full.txt +25 -0
- karaoke_gen/nextjs_frontend/out/admin/users/detail/__next._head.txt +8 -0
- karaoke_gen/nextjs_frontend/out/admin/users/detail/__next._index.txt +9 -0
- karaoke_gen/nextjs_frontend/out/admin/users/detail/__next._tree.txt +2 -0
- karaoke_gen/nextjs_frontend/out/admin/users/detail/__next.admin.txt +7 -0
- karaoke_gen/nextjs_frontend/out/admin/users/detail/__next.admin.users.detail.__PAGE__.txt +9 -0
- karaoke_gen/nextjs_frontend/out/admin/users/detail/__next.admin.users.detail.txt +4 -0
- karaoke_gen/nextjs_frontend/out/admin/users/detail/__next.admin.users.txt +4 -0
- karaoke_gen/nextjs_frontend/out/admin/users/detail/index.html +1 -0
- karaoke_gen/nextjs_frontend/out/admin/users/detail/index.txt +25 -0
- karaoke_gen/nextjs_frontend/out/admin/users/index.html +1 -0
- karaoke_gen/nextjs_frontend/out/admin/users/index.txt +25 -0
- karaoke_gen/nextjs_frontend/out/app/__next._full.txt +22 -0
- karaoke_gen/nextjs_frontend/out/app/__next._head.txt +8 -0
- karaoke_gen/nextjs_frontend/out/app/__next._index.txt +9 -0
- karaoke_gen/nextjs_frontend/out/app/__next._tree.txt +2 -0
- karaoke_gen/nextjs_frontend/out/app/__next.app.__PAGE__.txt +9 -0
- karaoke_gen/nextjs_frontend/out/app/__next.app.txt +4 -0
- karaoke_gen/nextjs_frontend/out/app/index.html +1 -0
- karaoke_gen/nextjs_frontend/out/app/index.txt +22 -0
- karaoke_gen/nextjs_frontend/out/app/jobs/__next._full.txt +19 -0
- karaoke_gen/nextjs_frontend/out/app/jobs/__next._head.txt +8 -0
- karaoke_gen/nextjs_frontend/out/app/jobs/__next._index.txt +9 -0
- karaoke_gen/nextjs_frontend/out/app/jobs/__next._tree.txt +2 -0
- karaoke_gen/nextjs_frontend/out/app/jobs/__next.app.jobs.$oc$slug.__PAGE__.txt +6 -0
- karaoke_gen/nextjs_frontend/out/app/jobs/__next.app.jobs.$oc$slug.txt +4 -0
- karaoke_gen/nextjs_frontend/out/app/jobs/__next.app.jobs.txt +4 -0
- karaoke_gen/nextjs_frontend/out/app/jobs/__next.app.txt +4 -0
- karaoke_gen/nextjs_frontend/out/app/jobs/index.html +1 -0
- karaoke_gen/nextjs_frontend/out/app/jobs/index.txt +19 -0
- karaoke_gen/nextjs_frontend/out/app/jobs/local/instrumental/__next._full.txt +19 -0
- karaoke_gen/nextjs_frontend/out/app/jobs/local/instrumental/__next._head.txt +8 -0
- karaoke_gen/nextjs_frontend/out/app/jobs/local/instrumental/__next._index.txt +9 -0
- karaoke_gen/nextjs_frontend/out/app/jobs/local/instrumental/__next._tree.txt +2 -0
- karaoke_gen/nextjs_frontend/out/app/jobs/local/instrumental/__next.app.jobs.$oc$slug.__PAGE__.txt +6 -0
- karaoke_gen/nextjs_frontend/out/app/jobs/local/instrumental/__next.app.jobs.$oc$slug.txt +4 -0
- karaoke_gen/nextjs_frontend/out/app/jobs/local/instrumental/__next.app.jobs.txt +4 -0
- karaoke_gen/nextjs_frontend/out/app/jobs/local/instrumental/__next.app.txt +4 -0
- karaoke_gen/nextjs_frontend/out/app/jobs/local/instrumental/index.html +1 -0
- karaoke_gen/nextjs_frontend/out/app/jobs/local/instrumental/index.txt +19 -0
- karaoke_gen/nextjs_frontend/out/app/jobs/local/review/__next._full.txt +19 -0
- karaoke_gen/nextjs_frontend/out/app/jobs/local/review/__next._head.txt +8 -0
- karaoke_gen/nextjs_frontend/out/app/jobs/local/review/__next._index.txt +9 -0
- karaoke_gen/nextjs_frontend/out/app/jobs/local/review/__next._tree.txt +2 -0
- karaoke_gen/nextjs_frontend/out/app/jobs/local/review/__next.app.jobs.$oc$slug.__PAGE__.txt +6 -0
- karaoke_gen/nextjs_frontend/out/app/jobs/local/review/__next.app.jobs.$oc$slug.txt +4 -0
- karaoke_gen/nextjs_frontend/out/app/jobs/local/review/__next.app.jobs.txt +4 -0
- karaoke_gen/nextjs_frontend/out/app/jobs/local/review/__next.app.txt +4 -0
- karaoke_gen/nextjs_frontend/out/app/jobs/local/review/index.html +1 -0
- karaoke_gen/nextjs_frontend/out/app/jobs/local/review/index.txt +19 -0
- karaoke_gen/nextjs_frontend/out/auth/verify/__next._full.txt +22 -0
- karaoke_gen/nextjs_frontend/out/auth/verify/__next._head.txt +8 -0
- karaoke_gen/nextjs_frontend/out/auth/verify/__next._index.txt +9 -0
- karaoke_gen/nextjs_frontend/out/auth/verify/__next._tree.txt +2 -0
- karaoke_gen/nextjs_frontend/out/auth/verify/__next.auth.txt +4 -0
- karaoke_gen/nextjs_frontend/out/auth/verify/__next.auth.verify.__PAGE__.txt +9 -0
- karaoke_gen/nextjs_frontend/out/auth/verify/__next.auth.verify.txt +4 -0
- karaoke_gen/nextjs_frontend/out/auth/verify/index.html +1 -0
- karaoke_gen/nextjs_frontend/out/auth/verify/index.txt +22 -0
- karaoke_gen/nextjs_frontend/out/index.html +1 -0
- karaoke_gen/nextjs_frontend/out/index.txt +22 -0
- karaoke_gen/nextjs_frontend/out/manifest.webmanifest +31 -0
- karaoke_gen/nextjs_frontend/out/order/success/__next._full.txt +22 -0
- karaoke_gen/nextjs_frontend/out/order/success/__next._head.txt +8 -0
- karaoke_gen/nextjs_frontend/out/order/success/__next._index.txt +9 -0
- karaoke_gen/nextjs_frontend/out/order/success/__next._tree.txt +2 -0
- karaoke_gen/nextjs_frontend/out/order/success/__next.order.success.__PAGE__.txt +9 -0
- karaoke_gen/nextjs_frontend/out/order/success/__next.order.success.txt +4 -0
- karaoke_gen/nextjs_frontend/out/order/success/__next.order.txt +4 -0
- karaoke_gen/nextjs_frontend/out/order/success/index.html +1 -0
- karaoke_gen/nextjs_frontend/out/order/success/index.txt +22 -0
- karaoke_gen/nextjs_frontend/out/payment/success/__next._full.txt +22 -0
- karaoke_gen/nextjs_frontend/out/payment/success/__next._head.txt +8 -0
- karaoke_gen/nextjs_frontend/out/payment/success/__next._index.txt +9 -0
- karaoke_gen/nextjs_frontend/out/payment/success/__next._tree.txt +2 -0
- karaoke_gen/nextjs_frontend/out/payment/success/__next.payment.success.__PAGE__.txt +9 -0
- karaoke_gen/nextjs_frontend/out/payment/success/__next.payment.success.txt +4 -0
- karaoke_gen/nextjs_frontend/out/payment/success/__next.payment.txt +4 -0
- karaoke_gen/nextjs_frontend/out/payment/success/index.html +1 -0
- karaoke_gen/nextjs_frontend/out/payment/success/index.txt +22 -0
- karaoke_gen/nextjs_frontend/out/screenshots/email-action_reminder.png +0 -0
- karaoke_gen/nextjs_frontend/out/screenshots/email-beta_welcome.png +0 -0
- karaoke_gen/nextjs_frontend/out/screenshots/email-job_completion.png +0 -0
- karaoke_gen/nextjs_frontend/out/screenshots/example-output.avif +0 -0
- karaoke_gen/nextjs_frontend/out/screenshots/homepage-full.png +0 -0
- karaoke_gen/nextjs_frontend/out/screenshots/homepage-hero.png +0 -0
- karaoke_gen/nextjs_frontend/out/screenshots/instrumental-review.avif +0 -0
- karaoke_gen/nextjs_frontend/out/screenshots/instrumental-review.png +0 -0
- karaoke_gen/nextjs_frontend/out/screenshots/job-dashboard.avif +0 -0
- karaoke_gen/nextjs_frontend/out/screenshots/lyrics-review.avif +0 -0
- karaoke_gen/nextjs_frontend/out/screenshots/lyrics-review.png +0 -0
- karaoke_gen/nextjs_frontend/out/sw.js +183 -0
- karaoke_gen/utils/cli_args.py +3 -3
- karaoke_gen/utils/gen_cli.py +4 -0
- karaoke_gen/utils/remote_cli.py +8 -40
- {karaoke_gen-0.103.1.dist-info → karaoke_gen-0.107.0.dist-info}/METADATA +2 -1
- {karaoke_gen-0.103.1.dist-info → karaoke_gen-0.107.0.dist-info}/RECORD +244 -131
- {karaoke_gen-0.103.1.dist-info → karaoke_gen-0.107.0.dist-info}/WHEEL +1 -1
- lyrics_transcriber/correction/agentic/agent.py +83 -60
- lyrics_transcriber/correction/anchor_sequence.py +48 -3
- lyrics_transcriber/correction/corrector.py +92 -58
- lyrics_transcriber/review/server.py +165 -33
- lyrics_transcriber/utils/tracing.py +214 -0
- karaoke_gen/instrumental_review/static/index.html +0 -1695
- lyrics_transcriber/frontend/.gitignore +0 -24
- lyrics_transcriber/frontend/.yarn/releases/yarn-4.7.0.cjs +0 -935
- lyrics_transcriber/frontend/.yarnrc.yml +0 -3
- lyrics_transcriber/frontend/README.md +0 -50
- lyrics_transcriber/frontend/REPLACE_ALL_FUNCTIONALITY.md +0 -210
- lyrics_transcriber/frontend/__init__.py +0 -25
- lyrics_transcriber/frontend/e2e/agentic-corrections.spec.ts +0 -207
- lyrics_transcriber/frontend/e2e/fixtures/agentic-correction-data.json +0 -226
- lyrics_transcriber/frontend/eslint.config.js +0 -28
- lyrics_transcriber/frontend/index.html +0 -22
- lyrics_transcriber/frontend/package-lock.json +0 -4553
- lyrics_transcriber/frontend/package.json +0 -48
- lyrics_transcriber/frontend/playwright.config.ts +0 -69
- lyrics_transcriber/frontend/public/android-chrome-192x192.png +0 -0
- lyrics_transcriber/frontend/public/android-chrome-512x512.png +0 -0
- lyrics_transcriber/frontend/src/App.tsx +0 -243
- lyrics_transcriber/frontend/src/api.ts +0 -262
- lyrics_transcriber/frontend/src/components/AIFeedbackModal.tsx +0 -111
- lyrics_transcriber/frontend/src/components/AddLyricsModal.tsx +0 -114
- lyrics_transcriber/frontend/src/components/AgenticCorrectionMetrics.tsx +0 -204
- lyrics_transcriber/frontend/src/components/AppHeader.tsx +0 -65
- lyrics_transcriber/frontend/src/components/AudioPlayer.tsx +0 -180
- lyrics_transcriber/frontend/src/components/CorrectedWordWithActions.tsx +0 -175
- lyrics_transcriber/frontend/src/components/CorrectionAnnotationModal.tsx +0 -359
- lyrics_transcriber/frontend/src/components/CorrectionDetailCard.tsx +0 -281
- lyrics_transcriber/frontend/src/components/CorrectionMetrics.tsx +0 -162
- lyrics_transcriber/frontend/src/components/DurationTimelineView.tsx +0 -257
- lyrics_transcriber/frontend/src/components/EditActionBar.tsx +0 -94
- lyrics_transcriber/frontend/src/components/EditModal.tsx +0 -720
- lyrics_transcriber/frontend/src/components/EditTimelineSection.tsx +0 -592
- lyrics_transcriber/frontend/src/components/EditWordList.tsx +0 -431
- lyrics_transcriber/frontend/src/components/FileUpload.tsx +0 -77
- lyrics_transcriber/frontend/src/components/FindReplaceModal.tsx +0 -467
- lyrics_transcriber/frontend/src/components/Header.tsx +0 -520
- lyrics_transcriber/frontend/src/components/LyricsAnalyzer.tsx +0 -1526
- lyrics_transcriber/frontend/src/components/LyricsSynchronizer/SyncControls.tsx +0 -216
- lyrics_transcriber/frontend/src/components/LyricsSynchronizer/TimelineCanvas.tsx +0 -721
- lyrics_transcriber/frontend/src/components/LyricsSynchronizer/UpcomingWordsBar.tsx +0 -80
- lyrics_transcriber/frontend/src/components/LyricsSynchronizer/index.tsx +0 -999
- lyrics_transcriber/frontend/src/components/MetricsDashboard.tsx +0 -51
- lyrics_transcriber/frontend/src/components/ModeSelectionModal.tsx +0 -127
- lyrics_transcriber/frontend/src/components/ModeSelector.tsx +0 -67
- lyrics_transcriber/frontend/src/components/ModelSelector.tsx +0 -23
- lyrics_transcriber/frontend/src/components/PreviewVideoSection.tsx +0 -177
- lyrics_transcriber/frontend/src/components/ReferenceView.tsx +0 -268
- lyrics_transcriber/frontend/src/components/ReplaceAllLyricsModal.tsx +0 -336
- lyrics_transcriber/frontend/src/components/ReviewChangesModal.tsx +0 -354
- lyrics_transcriber/frontend/src/components/SegmentDetailsModal.tsx +0 -64
- lyrics_transcriber/frontend/src/components/TimelineEditor.tsx +0 -383
- lyrics_transcriber/frontend/src/components/TimingOffsetModal.tsx +0 -131
- lyrics_transcriber/frontend/src/components/TranscriptionView.tsx +0 -266
- lyrics_transcriber/frontend/src/components/WordDivider.tsx +0 -191
- lyrics_transcriber/frontend/src/components/shared/components/HighlightedText.tsx +0 -466
- lyrics_transcriber/frontend/src/components/shared/components/SourceSelector.tsx +0 -56
- lyrics_transcriber/frontend/src/components/shared/components/Word.tsx +0 -89
- lyrics_transcriber/frontend/src/components/shared/constants.ts +0 -30
- lyrics_transcriber/frontend/src/components/shared/hooks/useWordClick.ts +0 -180
- lyrics_transcriber/frontend/src/components/shared/styles.ts +0 -13
- lyrics_transcriber/frontend/src/components/shared/types.js +0 -2
- lyrics_transcriber/frontend/src/components/shared/types.ts +0 -135
- lyrics_transcriber/frontend/src/components/shared/utils/keyboardHandlers.ts +0 -177
- lyrics_transcriber/frontend/src/components/shared/utils/localStorage.ts +0 -78
- lyrics_transcriber/frontend/src/components/shared/utils/referenceLineCalculator.ts +0 -75
- lyrics_transcriber/frontend/src/components/shared/utils/segmentOperations.ts +0 -360
- lyrics_transcriber/frontend/src/components/shared/utils/timingUtils.ts +0 -110
- lyrics_transcriber/frontend/src/components/shared/utils/wordUtils.ts +0 -22
- lyrics_transcriber/frontend/src/hooks/useManualSync.ts +0 -537
- lyrics_transcriber/frontend/src/main.tsx +0 -11
- lyrics_transcriber/frontend/src/theme.ts +0 -406
- lyrics_transcriber/frontend/src/types/global.d.ts +0 -9
- lyrics_transcriber/frontend/src/types.js +0 -2
- lyrics_transcriber/frontend/src/types.ts +0 -199
- lyrics_transcriber/frontend/src/validation.ts +0 -132
- lyrics_transcriber/frontend/src/vite-env.d.ts +0 -1
- lyrics_transcriber/frontend/tsconfig.app.json +0 -26
- lyrics_transcriber/frontend/tsconfig.json +0 -25
- lyrics_transcriber/frontend/tsconfig.node.json +0 -23
- lyrics_transcriber/frontend/tsconfig.tsbuildinfo +0 -1
- lyrics_transcriber/frontend/update_version.js +0 -11
- lyrics_transcriber/frontend/vite.config.d.ts +0 -2
- lyrics_transcriber/frontend/vite.config.js +0 -15
- lyrics_transcriber/frontend/vite.config.ts +0 -16
- lyrics_transcriber/frontend/web_assets/android-chrome-192x192.png +0 -0
- lyrics_transcriber/frontend/web_assets/android-chrome-512x512.png +0 -0
- lyrics_transcriber/frontend/web_assets/apple-touch-icon.png +0 -0
- lyrics_transcriber/frontend/web_assets/assets/index-BSMgOq4Z.js +0 -44465
- lyrics_transcriber/frontend/web_assets/assets/index-BSMgOq4Z.js.map +0 -1
- lyrics_transcriber/frontend/web_assets/favicon-16x16.png +0 -0
- lyrics_transcriber/frontend/web_assets/favicon-32x32.png +0 -0
- lyrics_transcriber/frontend/web_assets/favicon.ico +0 -0
- lyrics_transcriber/frontend/web_assets/index.html +0 -22
- lyrics_transcriber/frontend/web_assets/nomad-karaoke-logo.png +0 -0
- lyrics_transcriber/frontend/web_assets/nomad-karaoke-logo.svg +0 -5
- lyrics_transcriber/frontend/yarn.lock +0 -3711
- {lyrics_transcriber/frontend/public → karaoke_gen/nextjs_frontend/out}/apple-touch-icon.png +0 -0
- {lyrics_transcriber/frontend/public → karaoke_gen/nextjs_frontend/out}/favicon-16x16.png +0 -0
- {lyrics_transcriber/frontend/public → karaoke_gen/nextjs_frontend/out}/favicon-32x32.png +0 -0
- {lyrics_transcriber/frontend/public → karaoke_gen/nextjs_frontend/out}/favicon.ico +0 -0
- {lyrics_transcriber/frontend/public → karaoke_gen/nextjs_frontend/out}/nomad-karaoke-logo.svg +0 -0
- /lyrics_transcriber/frontend/public/nomad-karaoke-logo.png → /karaoke_gen/nextjs_frontend/out/nomad-logo.png +0 -0
- {karaoke_gen-0.103.1.dist-info → karaoke_gen-0.107.0.dist-info}/entry_points.txt +0 -0
- {karaoke_gen-0.103.1.dist-info → karaoke_gen-0.107.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "lyrics-transcriber-frontend",
|
|
3
|
-
"private": true,
|
|
4
|
-
"homepage": "https://nomadkaraoke.github.io/lyrics-transcriber-frontend",
|
|
5
|
-
"version": "0.86.0",
|
|
6
|
-
"type": "module",
|
|
7
|
-
"scripts": {
|
|
8
|
-
"dev": "vite",
|
|
9
|
-
"build": "tsc -b && vite build --mode development",
|
|
10
|
-
"build-prod": "tsc -b && vite build",
|
|
11
|
-
"lint": "eslint .",
|
|
12
|
-
"preview": "vite preview",
|
|
13
|
-
"predeploy": "npm run build-prod",
|
|
14
|
-
"deploy": "gh-pages -d dist",
|
|
15
|
-
"test": "playwright test",
|
|
16
|
-
"test:ui": "playwright test --ui",
|
|
17
|
-
"test:headed": "playwright test --headed"
|
|
18
|
-
},
|
|
19
|
-
"dependencies": {
|
|
20
|
-
"@emotion/react": "^11.14.0",
|
|
21
|
-
"@emotion/styled": "^11.14.0",
|
|
22
|
-
"@mui/icons-material": "^6.3.0",
|
|
23
|
-
"@mui/material": "^6.3.0",
|
|
24
|
-
"@mui/system": "^6.4.3",
|
|
25
|
-
"lucide-react": "^0.562.0",
|
|
26
|
-
"nanoid": "^5.0.9",
|
|
27
|
-
"react": "^18.3.1",
|
|
28
|
-
"react-dom": "^18.3.1",
|
|
29
|
-
"zod": "^3.24.1"
|
|
30
|
-
},
|
|
31
|
-
"devDependencies": {
|
|
32
|
-
"@eslint/js": "^9.17.0",
|
|
33
|
-
"@playwright/test": "^1.57.0",
|
|
34
|
-
"@types/react": "^18.3.18",
|
|
35
|
-
"@types/react-dom": "^18.3.5",
|
|
36
|
-
"@vitejs/plugin-react": "^4.3.4",
|
|
37
|
-
"eslint": "^9.17.0",
|
|
38
|
-
"eslint-plugin-react-hooks": "^5.0.0",
|
|
39
|
-
"eslint-plugin-react-refresh": "^0.4.16",
|
|
40
|
-
"gh-pages": "^6.3.0",
|
|
41
|
-
"globals": "^15.14.0",
|
|
42
|
-
"playwright": "^1.57.0",
|
|
43
|
-
"typescript": "~5.6.2",
|
|
44
|
-
"typescript-eslint": "^8.18.2",
|
|
45
|
-
"vite": "^6.0.5"
|
|
46
|
-
},
|
|
47
|
-
"packageManager": "yarn@4.7.0"
|
|
48
|
-
}
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import { defineConfig, devices } from '@playwright/test';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Playwright configuration for lyrics-transcriber frontend E2E tests.
|
|
5
|
-
* Tests run against the local dev server (localhost:5173) served by vite.
|
|
6
|
-
*/
|
|
7
|
-
export default defineConfig({
|
|
8
|
-
testDir: './e2e',
|
|
9
|
-
|
|
10
|
-
// Run tests sequentially for now
|
|
11
|
-
fullyParallel: false,
|
|
12
|
-
|
|
13
|
-
// Fail the build on CI if you accidentally left test.only in the source code
|
|
14
|
-
forbidOnly: !!process.env.CI,
|
|
15
|
-
|
|
16
|
-
// Retry on CI only
|
|
17
|
-
retries: process.env.CI ? 2 : 0,
|
|
18
|
-
|
|
19
|
-
// Single worker
|
|
20
|
-
workers: 1,
|
|
21
|
-
|
|
22
|
-
// Reporter to use
|
|
23
|
-
reporter: [
|
|
24
|
-
['html', { open: 'never' }],
|
|
25
|
-
['list'],
|
|
26
|
-
],
|
|
27
|
-
|
|
28
|
-
// Shared settings for all tests
|
|
29
|
-
use: {
|
|
30
|
-
// Base URL for the local dev server
|
|
31
|
-
baseURL: 'http://localhost:5173',
|
|
32
|
-
|
|
33
|
-
// Collect trace on failure for debugging
|
|
34
|
-
trace: 'on-first-retry',
|
|
35
|
-
|
|
36
|
-
// Screenshot on failure
|
|
37
|
-
screenshot: 'only-on-failure',
|
|
38
|
-
|
|
39
|
-
// Video on failure
|
|
40
|
-
video: 'on-first-retry',
|
|
41
|
-
|
|
42
|
-
// Increase timeout for complex interactions
|
|
43
|
-
actionTimeout: 30000,
|
|
44
|
-
},
|
|
45
|
-
|
|
46
|
-
// Longer timeout for tests
|
|
47
|
-
timeout: 120000, // 2 minutes per test
|
|
48
|
-
|
|
49
|
-
// Expect timeout for assertions
|
|
50
|
-
expect: {
|
|
51
|
-
timeout: 30000, // 30 seconds for expects
|
|
52
|
-
},
|
|
53
|
-
|
|
54
|
-
// Configure projects (browsers)
|
|
55
|
-
projects: [
|
|
56
|
-
{
|
|
57
|
-
name: 'chromium',
|
|
58
|
-
use: { ...devices['Desktop Chrome'] },
|
|
59
|
-
},
|
|
60
|
-
],
|
|
61
|
-
|
|
62
|
-
// Run local dev server before starting tests
|
|
63
|
-
webServer: {
|
|
64
|
-
command: 'npm run dev',
|
|
65
|
-
url: 'http://localhost:5173',
|
|
66
|
-
reuseExistingServer: !process.env.CI,
|
|
67
|
-
timeout: 120000,
|
|
68
|
-
},
|
|
69
|
-
});
|
|
Binary file
|
|
Binary file
|
|
@@ -1,243 +0,0 @@
|
|
|
1
|
-
import UploadFileIcon from '@mui/icons-material/UploadFile'
|
|
2
|
-
import { Alert, Box, Button, Modal, Typography } from '@mui/material'
|
|
3
|
-
import { ThemeProvider } from '@mui/material/styles'
|
|
4
|
-
import CssBaseline from '@mui/material/CssBaseline'
|
|
5
|
-
import { useEffect, useState, useMemo } from 'react'
|
|
6
|
-
import { ApiClient, FileOnlyClient, LiveApiClient } from './api'
|
|
7
|
-
import CorrectionMetrics from './components/CorrectionMetrics'
|
|
8
|
-
import LyricsAnalyzer from './components/LyricsAnalyzer'
|
|
9
|
-
import AppHeader from './components/AppHeader'
|
|
10
|
-
import { CorrectionData } from './types'
|
|
11
|
-
import { createAppTheme } from './theme'
|
|
12
|
-
|
|
13
|
-
const THEME_STORAGE_KEY = 'nomad-karaoke-lyrics-theme'
|
|
14
|
-
|
|
15
|
-
export default function App() {
|
|
16
|
-
const [isDarkMode, setIsDarkMode] = useState(() => {
|
|
17
|
-
// Initialize from localStorage
|
|
18
|
-
const stored = localStorage.getItem(THEME_STORAGE_KEY)
|
|
19
|
-
return stored !== 'light' // Default to dark
|
|
20
|
-
})
|
|
21
|
-
const [data, setData] = useState<CorrectionData | null>(null)
|
|
22
|
-
const [showMetadata, setShowMetadata] = useState(false)
|
|
23
|
-
const [error, setError] = useState<string | null>(null)
|
|
24
|
-
const [apiClient, setApiClient] = useState<ApiClient | null>(null)
|
|
25
|
-
const [isReadOnly, setIsReadOnly] = useState(true)
|
|
26
|
-
const [audioHash, setAudioHash] = useState<string>('')
|
|
27
|
-
|
|
28
|
-
// Create theme based on mode
|
|
29
|
-
const theme = useMemo(() => createAppTheme(isDarkMode ? 'dark' : 'light'), [isDarkMode])
|
|
30
|
-
|
|
31
|
-
// Handle theme toggle
|
|
32
|
-
const handleToggleTheme = () => {
|
|
33
|
-
const newIsDark = !isDarkMode
|
|
34
|
-
setIsDarkMode(newIsDark)
|
|
35
|
-
localStorage.setItem(THEME_STORAGE_KEY, newIsDark ? 'dark' : 'light')
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
useEffect(() => {
|
|
39
|
-
// Parse query parameters
|
|
40
|
-
const params = new URLSearchParams(window.location.search)
|
|
41
|
-
const encodedApiUrl = params.get('baseApiUrl')
|
|
42
|
-
const audioHashParam = params.get('audioHash')
|
|
43
|
-
const reviewTokenParam = params.get('reviewToken')
|
|
44
|
-
|
|
45
|
-
if (encodedApiUrl) {
|
|
46
|
-
const baseApiUrl = decodeURIComponent(encodedApiUrl)
|
|
47
|
-
// Pass reviewToken to LiveApiClient for authentication
|
|
48
|
-
setApiClient(new LiveApiClient(baseApiUrl, reviewTokenParam || undefined))
|
|
49
|
-
setIsReadOnly(false)
|
|
50
|
-
if (audioHashParam) {
|
|
51
|
-
setAudioHash(audioHashParam)
|
|
52
|
-
}
|
|
53
|
-
// Fetch initial data
|
|
54
|
-
fetchData(baseApiUrl, reviewTokenParam || undefined)
|
|
55
|
-
} else {
|
|
56
|
-
setApiClient(new FileOnlyClient())
|
|
57
|
-
setIsReadOnly(true)
|
|
58
|
-
}
|
|
59
|
-
}, [])
|
|
60
|
-
|
|
61
|
-
const fetchData = async (baseUrl: string, reviewToken?: string) => {
|
|
62
|
-
try {
|
|
63
|
-
const client = new LiveApiClient(baseUrl, reviewToken)
|
|
64
|
-
const data = await client.getCorrectionData()
|
|
65
|
-
// console.log('Full correction data from API:', data)
|
|
66
|
-
setData(data)
|
|
67
|
-
} catch (err) {
|
|
68
|
-
const error = err as Error
|
|
69
|
-
setError(`Failed to fetch data: ${error.message}`)
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const handleFileLoad = async () => {
|
|
74
|
-
const input = document.createElement('input')
|
|
75
|
-
input.type = 'file'
|
|
76
|
-
input.accept = '.json'
|
|
77
|
-
|
|
78
|
-
input.onchange = async (e) => {
|
|
79
|
-
const file = (e.target as HTMLInputElement).files?.[0]
|
|
80
|
-
if (!file) return
|
|
81
|
-
|
|
82
|
-
try {
|
|
83
|
-
const text = await file.text()
|
|
84
|
-
const parsedData = JSON.parse(text) as CorrectionData
|
|
85
|
-
console.log('File data loaded:', {
|
|
86
|
-
sampleGap: parsedData.gap_sequences?.[0],
|
|
87
|
-
sampleWord: parsedData.corrected_segments?.[0]?.words?.[0],
|
|
88
|
-
sampleCorrection: parsedData.corrections?.[0]
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
// Validate the structure
|
|
92
|
-
if (!parsedData.corrected_segments || !parsedData.gap_sequences) {
|
|
93
|
-
throw new Error('Invalid file format: missing required fields')
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
setData(parsedData)
|
|
97
|
-
} catch (err) {
|
|
98
|
-
const error = err as Error
|
|
99
|
-
setError(`Error loading file: ${error.message}. Please make sure it is a valid JSON file.`)
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
input.click()
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
const renderMetadataModal = () => {
|
|
107
|
-
if (!data) return null
|
|
108
|
-
|
|
109
|
-
return (
|
|
110
|
-
<Modal
|
|
111
|
-
open={showMetadata}
|
|
112
|
-
onClose={() => setShowMetadata(false)}
|
|
113
|
-
aria-labelledby="metadata-modal"
|
|
114
|
-
>
|
|
115
|
-
<Box sx={{
|
|
116
|
-
position: 'absolute',
|
|
117
|
-
top: '50%',
|
|
118
|
-
left: '50%',
|
|
119
|
-
transform: 'translate(-50%, -50%)',
|
|
120
|
-
width: 400,
|
|
121
|
-
bgcolor: 'background.paper',
|
|
122
|
-
boxShadow: 24,
|
|
123
|
-
p: 4,
|
|
124
|
-
borderRadius: 1,
|
|
125
|
-
}}>
|
|
126
|
-
<Typography variant="h6" gutterBottom>
|
|
127
|
-
Correction Process Details
|
|
128
|
-
</Typography>
|
|
129
|
-
<Box sx={{ mb: 2 }}>
|
|
130
|
-
<Typography variant="subtitle2" color="text.secondary">
|
|
131
|
-
Total Words
|
|
132
|
-
</Typography>
|
|
133
|
-
<Typography>
|
|
134
|
-
{data.metadata.total_words}
|
|
135
|
-
</Typography>
|
|
136
|
-
</Box>
|
|
137
|
-
<Box sx={{ mb: 2 }}>
|
|
138
|
-
<Typography variant="subtitle2" color="text.secondary">
|
|
139
|
-
Gap Sequences
|
|
140
|
-
</Typography>
|
|
141
|
-
<Typography>
|
|
142
|
-
{data.metadata.gap_sequences_count}
|
|
143
|
-
</Typography>
|
|
144
|
-
</Box>
|
|
145
|
-
<Box sx={{ mb: 2 }}>
|
|
146
|
-
<Typography variant="subtitle2" color="text.secondary">
|
|
147
|
-
Corrections Made
|
|
148
|
-
</Typography>
|
|
149
|
-
<Typography>
|
|
150
|
-
{data.corrections_made}
|
|
151
|
-
</Typography>
|
|
152
|
-
</Box>
|
|
153
|
-
<Box sx={{ mb: 2 }}>
|
|
154
|
-
<Typography variant="subtitle2" color="text.secondary">
|
|
155
|
-
Correction Ratio
|
|
156
|
-
</Typography>
|
|
157
|
-
<Typography>
|
|
158
|
-
{(data.metadata.correction_ratio * 100).toFixed(1)}%
|
|
159
|
-
</Typography>
|
|
160
|
-
</Box>
|
|
161
|
-
{/* Add any other metadata fields that are available */}
|
|
162
|
-
</Box>
|
|
163
|
-
</Modal>
|
|
164
|
-
)
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
if (!data) {
|
|
168
|
-
return (
|
|
169
|
-
<ThemeProvider theme={theme}>
|
|
170
|
-
<CssBaseline />
|
|
171
|
-
<AppHeader isDarkMode={isDarkMode} onToggleTheme={handleToggleTheme} />
|
|
172
|
-
<Box sx={{ p: 3 }}>
|
|
173
|
-
{error && (
|
|
174
|
-
<Alert severity="error" sx={{ mb: 2 }} onClose={() => setError(null)}>
|
|
175
|
-
{error}
|
|
176
|
-
</Alert>
|
|
177
|
-
)}
|
|
178
|
-
{isReadOnly ? (
|
|
179
|
-
<>
|
|
180
|
-
<Alert severity="info" sx={{ mb: 2 }}>
|
|
181
|
-
Running in read-only mode. Connect to an API to enable editing.
|
|
182
|
-
</Alert>
|
|
183
|
-
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 3 }}>
|
|
184
|
-
<Typography variant="h4">
|
|
185
|
-
Lyrics Correction Review
|
|
186
|
-
</Typography>
|
|
187
|
-
<Button
|
|
188
|
-
variant="outlined"
|
|
189
|
-
startIcon={<UploadFileIcon />}
|
|
190
|
-
onClick={handleFileLoad}
|
|
191
|
-
>
|
|
192
|
-
Load File
|
|
193
|
-
</Button>
|
|
194
|
-
</Box>
|
|
195
|
-
<Box sx={{ mb: 3 }}>
|
|
196
|
-
<CorrectionMetrics />
|
|
197
|
-
</Box>
|
|
198
|
-
</>
|
|
199
|
-
) : (
|
|
200
|
-
<Box sx={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '50vh' }}>
|
|
201
|
-
<Typography variant="h6" color="text.secondary">
|
|
202
|
-
Loading Lyrics Transcription Review...
|
|
203
|
-
</Typography>
|
|
204
|
-
</Box>
|
|
205
|
-
)}
|
|
206
|
-
</Box>
|
|
207
|
-
</ThemeProvider>
|
|
208
|
-
)
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
return (
|
|
212
|
-
<ThemeProvider theme={theme}>
|
|
213
|
-
<CssBaseline />
|
|
214
|
-
<AppHeader isDarkMode={isDarkMode} onToggleTheme={handleToggleTheme} />
|
|
215
|
-
<Box sx={{
|
|
216
|
-
p: 1.5,
|
|
217
|
-
pb: 3,
|
|
218
|
-
maxWidth: '100%',
|
|
219
|
-
overflowX: 'hidden'
|
|
220
|
-
}}>
|
|
221
|
-
{error && (
|
|
222
|
-
<Alert severity="error" sx={{ mb: 1 }} onClose={() => setError(null)}>
|
|
223
|
-
{error}
|
|
224
|
-
</Alert>
|
|
225
|
-
)}
|
|
226
|
-
{isReadOnly && (
|
|
227
|
-
<Alert severity="info" sx={{ mb: 1 }}>
|
|
228
|
-
Running in read-only mode. Connect to an API to enable editing.
|
|
229
|
-
</Alert>
|
|
230
|
-
)}
|
|
231
|
-
<LyricsAnalyzer
|
|
232
|
-
data={data}
|
|
233
|
-
onFileLoad={handleFileLoad}
|
|
234
|
-
onShowMetadata={() => setShowMetadata(true)}
|
|
235
|
-
apiClient={apiClient}
|
|
236
|
-
isReadOnly={isReadOnly}
|
|
237
|
-
audioHash={audioHash}
|
|
238
|
-
/>
|
|
239
|
-
{renderMetadataModal()}
|
|
240
|
-
</Box>
|
|
241
|
-
</ThemeProvider>
|
|
242
|
-
)
|
|
243
|
-
}
|
|
@@ -1,262 +0,0 @@
|
|
|
1
|
-
import { CorrectionData, CorrectionAnnotation } from './types';
|
|
2
|
-
import { validateCorrectionData } from './validation';
|
|
3
|
-
|
|
4
|
-
// New file to handle API communication
|
|
5
|
-
export interface ApiClient {
|
|
6
|
-
getCorrectionData: () => Promise<CorrectionData>;
|
|
7
|
-
submitCorrections: (data: CorrectionData) => Promise<void>;
|
|
8
|
-
getAudioUrl: (audioHash: string) => string;
|
|
9
|
-
generatePreviewVideo: (data: CorrectionData, options?: PreviewOptions) => Promise<PreviewVideoResponse>;
|
|
10
|
-
getPreviewVideoUrl: (previewHash: string) => string;
|
|
11
|
-
updateHandlers: (enabledHandlers: string[]) => Promise<CorrectionData>;
|
|
12
|
-
isUpdatingHandlers?: boolean;
|
|
13
|
-
addLyrics: (source: string, lyrics: string) => Promise<CorrectionData>;
|
|
14
|
-
submitAnnotations: (annotations: Omit<CorrectionAnnotation, 'annotation_id' | 'timestamp'>[]) => Promise<void>;
|
|
15
|
-
getAnnotationStats: () => Promise<any>;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// Add new interface for the minimal update payload
|
|
19
|
-
interface CorrectionUpdate {
|
|
20
|
-
corrections: CorrectionData['corrections'];
|
|
21
|
-
corrected_segments: CorrectionData['corrected_segments'];
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// Add interface for preview generation options
|
|
25
|
-
export interface PreviewOptions {
|
|
26
|
-
use_background_image?: boolean;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// Add new interface for preview response
|
|
30
|
-
interface PreviewVideoResponse {
|
|
31
|
-
status: "success" | "error";
|
|
32
|
-
preview_hash?: string;
|
|
33
|
-
message?: string;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// Add new interface for adding lyrics
|
|
37
|
-
interface AddLyricsRequest {
|
|
38
|
-
source: string;
|
|
39
|
-
lyrics: string;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export class LiveApiClient implements ApiClient {
|
|
43
|
-
private reviewToken?: string;
|
|
44
|
-
|
|
45
|
-
constructor(private baseUrl: string, reviewToken?: string) {
|
|
46
|
-
this.baseUrl = baseUrl.replace(/\/$/, '')
|
|
47
|
-
this.reviewToken = reviewToken
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
public isUpdatingHandlers = false;
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Build URL with reviewToken query parameter if available
|
|
54
|
-
*/
|
|
55
|
-
private buildUrl(path: string): string {
|
|
56
|
-
const url = `${this.baseUrl}${path}`
|
|
57
|
-
if (this.reviewToken) {
|
|
58
|
-
const separator = url.includes('?') ? '&' : '?'
|
|
59
|
-
return `${url}${separator}review_token=${encodeURIComponent(this.reviewToken)}`
|
|
60
|
-
}
|
|
61
|
-
return url
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
async getCorrectionData(): Promise<CorrectionData> {
|
|
65
|
-
const response = await fetch(this.buildUrl('/correction-data'));
|
|
66
|
-
if (!response.ok) {
|
|
67
|
-
throw new Error(`API error: ${response.statusText}`);
|
|
68
|
-
}
|
|
69
|
-
const rawData = await response.json();
|
|
70
|
-
|
|
71
|
-
try {
|
|
72
|
-
// This will throw if validation fails
|
|
73
|
-
return validateCorrectionData(rawData);
|
|
74
|
-
} catch (error) {
|
|
75
|
-
console.error('Data validation failed:', error);
|
|
76
|
-
throw new Error('Invalid data received from server: missing or incorrect fields');
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
async submitCorrections(data: CorrectionData): Promise<void> {
|
|
81
|
-
// Extract only the needed fields
|
|
82
|
-
const updatePayload: CorrectionUpdate = {
|
|
83
|
-
corrections: data.corrections,
|
|
84
|
-
corrected_segments: data.corrected_segments
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
const response = await fetch(this.buildUrl('/complete'), {
|
|
88
|
-
method: 'POST',
|
|
89
|
-
headers: {
|
|
90
|
-
'Content-Type': 'application/json',
|
|
91
|
-
},
|
|
92
|
-
body: JSON.stringify(updatePayload)
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
if (!response.ok) {
|
|
96
|
-
throw new Error(`API error: ${response.statusText}`);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
getAudioUrl(audioHash: string): string {
|
|
101
|
-
return this.buildUrl(`/audio/${audioHash}`)
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
async generatePreviewVideo(data: CorrectionData, options?: PreviewOptions): Promise<PreviewVideoResponse> {
|
|
105
|
-
// Extract only the needed fields, just like in submitCorrections
|
|
106
|
-
// Include use_background_image option (defaults to false for fast black background)
|
|
107
|
-
const updatePayload = {
|
|
108
|
-
corrections: data.corrections,
|
|
109
|
-
corrected_segments: data.corrected_segments,
|
|
110
|
-
use_background_image: options?.use_background_image ?? false,
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
const response = await fetch(this.buildUrl('/preview-video'), {
|
|
114
|
-
method: 'POST',
|
|
115
|
-
headers: {
|
|
116
|
-
'Content-Type': 'application/json',
|
|
117
|
-
},
|
|
118
|
-
body: JSON.stringify(updatePayload)
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
if (!response.ok) {
|
|
122
|
-
return {
|
|
123
|
-
status: 'error',
|
|
124
|
-
message: `API error: ${response.statusText}`
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
return await response.json();
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
getPreviewVideoUrl(previewHash: string): string {
|
|
132
|
-
return this.buildUrl(`/preview-video/${previewHash}`);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
async updateHandlers(enabledHandlers: string[]): Promise<CorrectionData> {
|
|
136
|
-
console.log('API: Starting handler update...');
|
|
137
|
-
this.isUpdatingHandlers = true;
|
|
138
|
-
console.log('API: Set isUpdatingHandlers to', this.isUpdatingHandlers);
|
|
139
|
-
|
|
140
|
-
try {
|
|
141
|
-
const response = await fetch(this.buildUrl('/handlers'), {
|
|
142
|
-
method: 'POST',
|
|
143
|
-
headers: {
|
|
144
|
-
'Content-Type': 'application/json',
|
|
145
|
-
},
|
|
146
|
-
body: JSON.stringify(enabledHandlers)
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
if (!response.ok) {
|
|
150
|
-
throw new Error(`API error: ${response.statusText}`);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
const data = await response.json();
|
|
154
|
-
if (data.status === 'error') {
|
|
155
|
-
throw new Error(data.message || 'Failed to update handlers');
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
console.log('API: Handler update successful');
|
|
159
|
-
return validateCorrectionData(data.data);
|
|
160
|
-
} finally {
|
|
161
|
-
this.isUpdatingHandlers = false;
|
|
162
|
-
console.log('API: Set isUpdatingHandlers to', this.isUpdatingHandlers);
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
async addLyrics(source: string, lyrics: string): Promise<CorrectionData> {
|
|
167
|
-
const payload: AddLyricsRequest = {
|
|
168
|
-
source,
|
|
169
|
-
lyrics
|
|
170
|
-
};
|
|
171
|
-
|
|
172
|
-
const response = await fetch(this.buildUrl('/add-lyrics'), {
|
|
173
|
-
method: 'POST',
|
|
174
|
-
headers: {
|
|
175
|
-
'Content-Type': 'application/json',
|
|
176
|
-
},
|
|
177
|
-
body: JSON.stringify(payload)
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
if (!response.ok) {
|
|
181
|
-
throw new Error(`API error: ${response.statusText}`);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
const data = await response.json();
|
|
185
|
-
if (data.status === 'error') {
|
|
186
|
-
throw new Error(data.message || 'Failed to add lyrics');
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
return validateCorrectionData(data.data);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
async submitAnnotations(annotations: Omit<CorrectionAnnotation, 'annotation_id' | 'timestamp'>[]): Promise<void> {
|
|
193
|
-
// Submit each annotation to the backend
|
|
194
|
-
for (const annotation of annotations) {
|
|
195
|
-
const response = await fetch(this.buildUrl('/v1/annotations'), {
|
|
196
|
-
method: 'POST',
|
|
197
|
-
headers: {
|
|
198
|
-
'Content-Type': 'application/json',
|
|
199
|
-
},
|
|
200
|
-
body: JSON.stringify(annotation)
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
if (!response.ok) {
|
|
204
|
-
console.error(`Failed to submit annotation:`, annotation);
|
|
205
|
-
// Continue with other annotations even if one fails
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
async getAnnotationStats(): Promise<any> {
|
|
211
|
-
const response = await fetch(this.buildUrl('/v1/annotations/stats'));
|
|
212
|
-
if (!response.ok) {
|
|
213
|
-
throw new Error(`API error: ${response.statusText}`);
|
|
214
|
-
}
|
|
215
|
-
return await response.json();
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
export class FileOnlyClient implements ApiClient {
|
|
220
|
-
async getCorrectionData(): Promise<CorrectionData> {
|
|
221
|
-
throw new Error('Not supported in file-only mode');
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
225
|
-
async submitCorrections(_data: CorrectionData): Promise<void> {
|
|
226
|
-
throw new Error('Not supported in file-only mode');
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
230
|
-
getAudioUrl(_audioHash: string): string {
|
|
231
|
-
throw new Error('Not supported in file-only mode');
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
235
|
-
async generatePreviewVideo(_data: CorrectionData, _options?: PreviewOptions): Promise<PreviewVideoResponse> {
|
|
236
|
-
throw new Error('Not supported in file-only mode');
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
240
|
-
getPreviewVideoUrl(_previewHash: string): string {
|
|
241
|
-
throw new Error('Not supported in file-only mode');
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
245
|
-
async updateHandlers(_enabledHandlers: string[]): Promise<CorrectionData> {
|
|
246
|
-
throw new Error('Not supported in file-only mode');
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
async addLyrics(): Promise<CorrectionData> {
|
|
250
|
-
throw new Error('Not supported in file-only mode');
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
254
|
-
async submitAnnotations(_annotations: Omit<CorrectionAnnotation, 'annotation_id' | 'timestamp'>[]): Promise<void> {
|
|
255
|
-
throw new Error('Not supported in file-only mode');
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
async getAnnotationStats(): Promise<any> {
|
|
259
|
-
throw new Error('Not supported in file-only mode');
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
|