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
|
@@ -13,6 +13,7 @@ from .models.schemas import CorrectionProposal, GapClassification, GapCategory
|
|
|
13
13
|
from .workflows.correction_graph import build_correction_graph
|
|
14
14
|
from .prompts.classifier import build_classification_prompt
|
|
15
15
|
from .handlers.registry import HandlerRegistry
|
|
16
|
+
from lyrics_transcriber.utils.tracing import create_span, add_span_attribute
|
|
16
17
|
|
|
17
18
|
logger = logging.getLogger(__name__)
|
|
18
19
|
|
|
@@ -211,72 +212,94 @@ class AgenticCorrector:
|
|
|
211
212
|
Returns:
|
|
212
213
|
List of CorrectionProposal objects
|
|
213
214
|
"""
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
reference_contexts=reference_contexts,
|
|
222
|
-
artist=artist,
|
|
223
|
-
title=title
|
|
224
|
-
)
|
|
225
|
-
|
|
226
|
-
if not classification:
|
|
227
|
-
# Classification failed, flag for human review
|
|
228
|
-
logger.warning(f"🤖 Classification failed for gap {gap_id}, flagging for review")
|
|
229
|
-
return [CorrectionProposal(
|
|
230
|
-
word_ids=[w['id'] for w in gap_words],
|
|
231
|
-
action="Flag",
|
|
232
|
-
confidence=0.0,
|
|
233
|
-
reason="Classification failed - unable to categorize gap",
|
|
234
|
-
requires_human_review=True,
|
|
235
|
-
artist=artist,
|
|
236
|
-
title=title
|
|
237
|
-
)]
|
|
238
|
-
|
|
239
|
-
# Step 2: Route to appropriate handler based on category
|
|
240
|
-
try:
|
|
241
|
-
handler = HandlerRegistry.get_handler(
|
|
242
|
-
category=classification.category,
|
|
243
|
-
artist=artist,
|
|
244
|
-
title=title
|
|
245
|
-
)
|
|
246
|
-
|
|
247
|
-
proposals = handler.handle(
|
|
215
|
+
with create_span("agentic.propose_for_gap", {
|
|
216
|
+
"gap_id": gap_id,
|
|
217
|
+
"word_count": len(gap_words),
|
|
218
|
+
}) as span:
|
|
219
|
+
# Step 1: Classify the gap
|
|
220
|
+
gap_text = ' '.join(w.get('text', '') for w in gap_words)
|
|
221
|
+
classification = self.classify_gap(
|
|
248
222
|
gap_id=gap_id,
|
|
249
|
-
|
|
223
|
+
gap_text=gap_text,
|
|
250
224
|
preceding_words=preceding_words,
|
|
251
225
|
following_words=following_words,
|
|
252
226
|
reference_contexts=reference_contexts,
|
|
253
|
-
classification_reasoning=classification.reasoning
|
|
254
|
-
)
|
|
255
|
-
|
|
256
|
-
# Add classification metadata to proposals
|
|
257
|
-
for proposal in proposals:
|
|
258
|
-
if not proposal.gap_category:
|
|
259
|
-
proposal.gap_category = classification.category
|
|
260
|
-
if not proposal.artist:
|
|
261
|
-
proposal.artist = artist
|
|
262
|
-
if not proposal.title:
|
|
263
|
-
proposal.title = title
|
|
264
|
-
|
|
265
|
-
return proposals
|
|
266
|
-
|
|
267
|
-
except Exception as e:
|
|
268
|
-
logger.error(f"🤖 Handler failed for gap {gap_id} (category: {classification.category}): {e}")
|
|
269
|
-
# Handler failed, flag for human review
|
|
270
|
-
return [CorrectionProposal(
|
|
271
|
-
word_ids=[w['id'] for w in gap_words],
|
|
272
|
-
action="Flag",
|
|
273
|
-
confidence=0.0,
|
|
274
|
-
reason=f"Handler error for category {classification.category}: {str(e)}",
|
|
275
|
-
gap_category=classification.category,
|
|
276
|
-
requires_human_review=True,
|
|
277
227
|
artist=artist,
|
|
278
228
|
title=title
|
|
279
|
-
)
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
if not classification:
|
|
232
|
+
# Classification failed, flag for human review
|
|
233
|
+
logger.warning(f"🤖 Classification failed for gap {gap_id}, flagging for review")
|
|
234
|
+
if span:
|
|
235
|
+
span.set_attribute("classification_failed", True)
|
|
236
|
+
# Safely extract word IDs, filtering out any missing/None values
|
|
237
|
+
word_ids = [w.get('id') for w in gap_words if w.get('id') is not None]
|
|
238
|
+
return [CorrectionProposal(
|
|
239
|
+
word_ids=word_ids,
|
|
240
|
+
action="Flag",
|
|
241
|
+
confidence=0.0,
|
|
242
|
+
reason="Classification failed - unable to categorize gap",
|
|
243
|
+
requires_human_review=True,
|
|
244
|
+
artist=artist,
|
|
245
|
+
title=title
|
|
246
|
+
)]
|
|
247
|
+
|
|
248
|
+
if span:
|
|
249
|
+
span.set_attribute("gap_category", classification.category.value if hasattr(classification.category, 'value') else str(classification.category))
|
|
250
|
+
|
|
251
|
+
# Step 2: Route to appropriate handler based on category
|
|
252
|
+
try:
|
|
253
|
+
handler = HandlerRegistry.get_handler(
|
|
254
|
+
category=classification.category,
|
|
255
|
+
artist=artist,
|
|
256
|
+
title=title
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
proposals = handler.handle(
|
|
260
|
+
gap_id=gap_id,
|
|
261
|
+
gap_words=gap_words,
|
|
262
|
+
preceding_words=preceding_words,
|
|
263
|
+
following_words=following_words,
|
|
264
|
+
reference_contexts=reference_contexts,
|
|
265
|
+
classification_reasoning=classification.reasoning
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
# Add classification metadata to proposals
|
|
269
|
+
for proposal in proposals:
|
|
270
|
+
if not proposal.gap_category:
|
|
271
|
+
proposal.gap_category = classification.category
|
|
272
|
+
if not proposal.artist:
|
|
273
|
+
proposal.artist = artist
|
|
274
|
+
if not proposal.title:
|
|
275
|
+
proposal.title = title
|
|
276
|
+
|
|
277
|
+
if span:
|
|
278
|
+
span.set_attribute("proposal_count", len(proposals))
|
|
279
|
+
|
|
280
|
+
return proposals
|
|
281
|
+
|
|
282
|
+
except Exception as e:
|
|
283
|
+
# Sanitize error message - use exception class name and truncated message
|
|
284
|
+
error_type = type(e).__name__
|
|
285
|
+
error_msg_truncated = str(e)[:50] if str(e) else "Unknown error"
|
|
286
|
+
sanitized_error = f"{error_type}: {error_msg_truncated}"
|
|
287
|
+
logger.error(f"🤖 Handler failed for gap {gap_id} (category: {classification.category}): {sanitized_error}")
|
|
288
|
+
if span:
|
|
289
|
+
span.set_attribute("handler_error", sanitized_error)
|
|
290
|
+
# Safely extract word IDs, filtering out any missing/None values
|
|
291
|
+
word_ids = [w.get('id') for w in gap_words if w.get('id') is not None]
|
|
292
|
+
# Handler failed, flag for human review
|
|
293
|
+
return [CorrectionProposal(
|
|
294
|
+
word_ids=word_ids,
|
|
295
|
+
action="Flag",
|
|
296
|
+
confidence=0.0,
|
|
297
|
+
reason=f"Handler error for category {classification.category} ({error_type})",
|
|
298
|
+
gap_category=classification.category,
|
|
299
|
+
requires_human_review=True,
|
|
300
|
+
artist=artist,
|
|
301
|
+
title=title
|
|
302
|
+
)]
|
|
280
303
|
|
|
281
304
|
def propose(self, prompt: str) -> List[CorrectionProposal]:
|
|
282
305
|
"""Generate correction proposals using LangGraph + LangChain.
|
|
@@ -8,6 +8,9 @@ from pathlib import Path
|
|
|
8
8
|
import json
|
|
9
9
|
import hashlib
|
|
10
10
|
|
|
11
|
+
# Tracing utilities (optional - gracefully handles missing dependency)
|
|
12
|
+
from lyrics_transcriber.utils.tracing import create_span, add_span_attribute, add_span_event
|
|
13
|
+
|
|
11
14
|
from lyrics_transcriber.types import LyricsData, PhraseScore, PhraseType, AnchorSequence, GapSequence, ScoredAnchor, TranscriptionResult, Word
|
|
12
15
|
from lyrics_transcriber.correction.phrase_analyzer import PhraseAnalyzer
|
|
13
16
|
from lyrics_transcriber.correction.text_utils import clean_text
|
|
@@ -381,7 +384,24 @@ class AnchorSequenceFinder:
|
|
|
381
384
|
) -> List[ScoredAnchor]:
|
|
382
385
|
"""Find anchor sequences that appear in both transcription and references with timeout protection."""
|
|
383
386
|
start_time = time.time()
|
|
384
|
-
|
|
387
|
+
|
|
388
|
+
# Wrap entire operation in a tracing span
|
|
389
|
+
with create_span("anchor_search.find_anchors", {
|
|
390
|
+
"transcription.text_length": len(transcribed),
|
|
391
|
+
"reference.source_count": len(references),
|
|
392
|
+
"timeout_seconds": self.timeout_seconds,
|
|
393
|
+
}) as span:
|
|
394
|
+
return self._find_anchors_impl(transcribed, references, transcription_result, start_time, span)
|
|
395
|
+
|
|
396
|
+
def _find_anchors_impl(
|
|
397
|
+
self,
|
|
398
|
+
transcribed: str,
|
|
399
|
+
references: Dict[str, LyricsData],
|
|
400
|
+
transcription_result: TranscriptionResult,
|
|
401
|
+
start_time: float,
|
|
402
|
+
span,
|
|
403
|
+
) -> List[ScoredAnchor]:
|
|
404
|
+
"""Internal implementation of find_anchors wrapped in tracing span."""
|
|
385
405
|
try:
|
|
386
406
|
self.logger.info(f"🔍 ANCHOR SEARCH: Starting find_anchors with timeout {self.timeout_seconds}s")
|
|
387
407
|
self.logger.info(f"🔍 ANCHOR SEARCH: Transcribed text length: {len(transcribed)}")
|
|
@@ -395,6 +415,10 @@ class AnchorSequenceFinder:
|
|
|
395
415
|
self.logger.info(f"🔍 ANCHOR SEARCH: Checking cache at {cache_path}")
|
|
396
416
|
if cached_data := self._load_from_cache(cache_path):
|
|
397
417
|
self.logger.info("🔍 ANCHOR SEARCH: ✅ Cache hit! Loading anchors from cache")
|
|
418
|
+
if span:
|
|
419
|
+
span.set_attribute("cache_hit", True)
|
|
420
|
+
span.set_attribute("cached_anchors", len(cached_data))
|
|
421
|
+
span.set_attribute("duration_seconds", time.time() - start_time)
|
|
398
422
|
try:
|
|
399
423
|
# Convert cached_data to dictionary before logging
|
|
400
424
|
if cached_data:
|
|
@@ -504,10 +528,24 @@ class AnchorSequenceFinder:
|
|
|
504
528
|
}
|
|
505
529
|
|
|
506
530
|
completed = 0
|
|
531
|
+
last_progress_log_time = time.time()
|
|
532
|
+
progress_log_interval = 30 # Log every 30 seconds
|
|
533
|
+
|
|
507
534
|
for future in as_completed(future_to_n):
|
|
508
535
|
n = future_to_n[future]
|
|
509
536
|
completed += 1
|
|
510
537
|
|
|
538
|
+
# Time-based progress logging (every 30 seconds)
|
|
539
|
+
current_time = time.time()
|
|
540
|
+
if current_time - last_progress_log_time >= progress_log_interval:
|
|
541
|
+
elapsed = current_time - start_time
|
|
542
|
+
progress_pct = (completed / len(n_gram_lengths)) * 100
|
|
543
|
+
self.logger.info(
|
|
544
|
+
f"🔍 ANCHOR SEARCH: Progress {completed}/{len(n_gram_lengths)} "
|
|
545
|
+
f"({progress_pct:.1f}%) - {elapsed:.1f}s elapsed"
|
|
546
|
+
)
|
|
547
|
+
last_progress_log_time = current_time
|
|
548
|
+
|
|
511
549
|
# Check timeout periodically
|
|
512
550
|
if self.timeout_seconds > 0:
|
|
513
551
|
elapsed_time = time.time() - start_time
|
|
@@ -577,7 +615,14 @@ class AnchorSequenceFinder:
|
|
|
577
615
|
|
|
578
616
|
total_time = time.time() - start_time
|
|
579
617
|
self.logger.info(f"🔍 ANCHOR SEARCH: 🎉 Anchor sequence computation completed successfully in {total_time:.1f}s")
|
|
580
|
-
|
|
618
|
+
|
|
619
|
+
# Add span attributes for metrics
|
|
620
|
+
if span:
|
|
621
|
+
span.set_attribute("candidate_anchors", len(candidate_anchors))
|
|
622
|
+
span.set_attribute("filtered_anchors", len(filtered_anchors))
|
|
623
|
+
span.set_attribute("duration_seconds", total_time)
|
|
624
|
+
span.set_attribute("cache_hit", False)
|
|
625
|
+
|
|
581
626
|
return filtered_anchors
|
|
582
627
|
|
|
583
628
|
except AnchorSequenceTimeoutError:
|
|
@@ -592,7 +637,7 @@ class AnchorSequenceFinder:
|
|
|
592
637
|
self.logger.error(f"🔍 ANCHOR SEARCH: Traceback: {traceback.format_exc()}")
|
|
593
638
|
raise
|
|
594
639
|
finally:
|
|
595
|
-
# No cleanup needed
|
|
640
|
+
# No cleanup needed - span is managed by context manager in find_anchors()
|
|
596
641
|
pass
|
|
597
642
|
|
|
598
643
|
def _score_sequence(self, words: List[str], context: str) -> PhraseScore:
|
|
@@ -27,6 +27,7 @@ from lyrics_transcriber.correction.anchor_sequence import AnchorSequenceFinder
|
|
|
27
27
|
from lyrics_transcriber.correction.handlers.base import GapCorrectionHandler
|
|
28
28
|
from lyrics_transcriber.correction.handlers.extend_anchor import ExtendAnchorHandler
|
|
29
29
|
from lyrics_transcriber.utils.word_utils import WordUtils
|
|
30
|
+
from lyrics_transcriber.utils.tracing import create_span, add_span_attribute, add_span_event
|
|
30
31
|
|
|
31
32
|
|
|
32
33
|
class LyricsCorrector:
|
|
@@ -126,66 +127,91 @@ class LyricsCorrector:
|
|
|
126
127
|
wrap this method with an outer timeout (e.g., asyncio.wait_for) as a safety
|
|
127
128
|
net for hung operations.
|
|
128
129
|
"""
|
|
130
|
+
start_time = time.time()
|
|
131
|
+
|
|
129
132
|
# Optional agentic routing flag from environment; default off for safety
|
|
130
133
|
agentic_enabled = os.getenv("USE_AGENTIC_AI", "").lower() in {"1", "true", "yes"}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
134
|
+
|
|
135
|
+
with create_span("lyrics_corrector.run", {
|
|
136
|
+
"agentic_enabled": agentic_enabled,
|
|
137
|
+
"reference_sources": len(lyrics_results),
|
|
138
|
+
"transcription_count": len(transcription_results),
|
|
139
|
+
}) as span:
|
|
140
|
+
self.logger.info(f"🤖 AGENTIC MODE: {'ENABLED' if agentic_enabled else 'DISABLED'} (USE_AGENTIC_AI={os.getenv('USE_AGENTIC_AI', 'NOT_SET')})")
|
|
141
|
+
if not transcription_results:
|
|
142
|
+
self.logger.error("No transcription results available")
|
|
143
|
+
raise ValueError("No primary transcription data available")
|
|
144
|
+
|
|
145
|
+
# Store reference lyrics for use in word map
|
|
146
|
+
self.reference_lyrics = lyrics_results
|
|
147
|
+
|
|
148
|
+
# Get primary transcription
|
|
149
|
+
primary_transcription_result = sorted(transcription_results, key=lambda x: x.priority)[0]
|
|
150
|
+
primary_transcription = primary_transcription_result.result
|
|
151
|
+
transcribed_text = " ".join(" ".join(w.text for w in segment.words) for segment in primary_transcription.segments)
|
|
152
|
+
|
|
153
|
+
# Find anchor sequences and gaps
|
|
154
|
+
self.logger.debug("Finding anchor sequences and gaps")
|
|
155
|
+
with create_span("lyrics_corrector.find_anchors_and_gaps") as anchor_span:
|
|
156
|
+
anchor_sequences = self.anchor_finder.find_anchors(transcribed_text, lyrics_results, primary_transcription_result)
|
|
157
|
+
gap_sequences = self.anchor_finder.find_gaps(transcribed_text, anchor_sequences, lyrics_results, primary_transcription_result)
|
|
158
|
+
if anchor_span:
|
|
159
|
+
anchor_span.set_attribute("anchor_count", len(anchor_sequences))
|
|
160
|
+
anchor_span.set_attribute("gap_count", len(gap_sequences))
|
|
161
|
+
|
|
162
|
+
# Store anchor sequences for use in correction handlers
|
|
163
|
+
self._anchor_sequences = anchor_sequences
|
|
164
|
+
|
|
165
|
+
# Process corrections with metadata and optional deadline for agentic timeout
|
|
166
|
+
with create_span("lyrics_corrector.process_corrections", {
|
|
167
|
+
"gap_count": len(gap_sequences),
|
|
168
|
+
"agentic_enabled": agentic_enabled,
|
|
169
|
+
}) as process_span:
|
|
170
|
+
corrections, corrected_segments, correction_steps, word_id_map, segment_id_map = self._process_corrections(
|
|
171
|
+
primary_transcription.segments, gap_sequences, metadata=metadata, deadline=agentic_deadline
|
|
172
|
+
)
|
|
173
|
+
if process_span:
|
|
174
|
+
process_span.set_attribute("corrections_count", len(corrections))
|
|
175
|
+
|
|
176
|
+
# Calculate correction ratio
|
|
177
|
+
total_words = sum(len(segment.words) for segment in corrected_segments)
|
|
178
|
+
corrections_made = len(corrections)
|
|
179
|
+
correction_ratio = 1 - (corrections_made / total_words if total_words > 0 else 0)
|
|
180
|
+
|
|
181
|
+
# Get the currently enabled handler IDs using the handler's name attribute if available
|
|
182
|
+
enabled_handlers = [getattr(handler, "name", handler.__class__.__name__) for handler in self.handlers]
|
|
183
|
+
|
|
184
|
+
# Add final span attributes
|
|
185
|
+
if span:
|
|
186
|
+
span.set_attribute("total_words", total_words)
|
|
187
|
+
span.set_attribute("corrections_made", corrections_made)
|
|
188
|
+
span.set_attribute("correction_ratio", correction_ratio)
|
|
189
|
+
span.set_attribute("duration_seconds", time.time() - start_time)
|
|
190
|
+
|
|
191
|
+
result = CorrectionResult(
|
|
192
|
+
original_segments=primary_transcription.segments,
|
|
193
|
+
corrected_segments=corrected_segments,
|
|
194
|
+
corrections=corrections,
|
|
195
|
+
corrections_made=corrections_made,
|
|
196
|
+
confidence=correction_ratio,
|
|
197
|
+
reference_lyrics=lyrics_results,
|
|
198
|
+
anchor_sequences=anchor_sequences,
|
|
199
|
+
resized_segments=[],
|
|
200
|
+
gap_sequences=gap_sequences,
|
|
201
|
+
metadata={
|
|
202
|
+
"anchor_sequences_count": len(anchor_sequences),
|
|
203
|
+
"gap_sequences_count": len(gap_sequences),
|
|
204
|
+
"total_words": total_words,
|
|
205
|
+
"correction_ratio": correction_ratio,
|
|
206
|
+
"available_handlers": self.all_handlers,
|
|
207
|
+
"enabled_handlers": enabled_handlers,
|
|
208
|
+
"agentic_routing": "agentic" if agentic_enabled else "rule-based",
|
|
209
|
+
},
|
|
210
|
+
correction_steps=correction_steps,
|
|
211
|
+
word_id_map=word_id_map,
|
|
212
|
+
segment_id_map=segment_id_map,
|
|
213
|
+
)
|
|
214
|
+
return result
|
|
189
215
|
|
|
190
216
|
def _preserve_formatting(self, original: str, new_word: str) -> str:
|
|
191
217
|
"""Preserve original word's formatting when applying correction."""
|
|
@@ -465,6 +491,9 @@ class LyricsCorrector:
|
|
|
465
491
|
# Get parallel processing config
|
|
466
492
|
_config = ProviderConfig.from_env()
|
|
467
493
|
max_workers = _config.max_parallel_gaps
|
|
494
|
+
|
|
495
|
+
# Wrap agentic processing in a tracing span
|
|
496
|
+
add_span_event("agentic_processing_started", {"gap_count": len(gap_sequences), "max_workers": max_workers})
|
|
468
497
|
self.logger.info(f"🤖 Processing {len(gap_sequences)} gaps in parallel (max_workers={max_workers})")
|
|
469
498
|
|
|
470
499
|
# Pre-compute shared data structures once (not per-gap)
|
|
@@ -585,6 +614,11 @@ class LyricsCorrector:
|
|
|
585
614
|
self.logger.info(f"🤖 Gap {result['index']}/{len(gap_sequences)} completed ({proposal_count} proposals)")
|
|
586
615
|
|
|
587
616
|
self.logger.info(f"🤖 Parallel processing complete: {completed_count}/{len(gap_sequences)} gaps processed")
|
|
617
|
+
add_span_event("agentic_processing_completed", {
|
|
618
|
+
"gaps_processed": completed_count,
|
|
619
|
+
"gaps_total": len(gap_sequences),
|
|
620
|
+
"errors": len(errors),
|
|
621
|
+
})
|
|
588
622
|
|
|
589
623
|
# If any errors occurred, fail fast
|
|
590
624
|
if errors:
|