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.
Files changed (339) hide show
  1. backend/Dockerfile.base +1 -0
  2. backend/api/routes/admin.py +226 -3
  3. backend/api/routes/push.py +238 -0
  4. backend/api/routes/users.py +14 -3
  5. backend/config.py +12 -1
  6. backend/main.py +2 -1
  7. backend/models/job.py +4 -0
  8. backend/models/user.py +20 -2
  9. backend/services/encoding_interface.py +4 -0
  10. backend/services/gce_encoding/main.py +22 -8
  11. backend/services/job_manager.py +68 -11
  12. backend/services/job_notification_service.py +4 -21
  13. backend/services/push_notification_service.py +409 -0
  14. backend/services/stripe_service.py +2 -2
  15. backend/tests/conftest.py +2 -1
  16. backend/tests/test_admin_delete_outputs.py +352 -0
  17. backend/tests/test_gce_encoding_worker.py +229 -0
  18. backend/tests/test_impersonation.py +18 -3
  19. backend/tests/test_job_notification_service.py +24 -58
  20. backend/tests/test_push_notification_service.py +460 -0
  21. backend/tests/test_push_routes.py +357 -0
  22. backend/tests/test_stripe_service.py +205 -0
  23. backend/tests/test_video_worker_orchestrator.py +189 -0
  24. backend/workers/video_worker_orchestrator.py +23 -0
  25. karaoke_gen/instrumental_review/server.py +145 -35
  26. karaoke_gen/nextjs_frontend/__init__.py +98 -0
  27. karaoke_gen/nextjs_frontend/out/404/index.html +1 -0
  28. karaoke_gen/nextjs_frontend/out/404.html +1 -0
  29. karaoke_gen/nextjs_frontend/out/__next.__PAGE__.txt +9 -0
  30. karaoke_gen/nextjs_frontend/out/__next._full.txt +22 -0
  31. karaoke_gen/nextjs_frontend/out/__next._head.txt +8 -0
  32. karaoke_gen/nextjs_frontend/out/__next._index.txt +9 -0
  33. karaoke_gen/nextjs_frontend/out/__next._tree.txt +2 -0
  34. karaoke_gen/nextjs_frontend/out/_next/static/chunks/01a7f8fe40f1ff47.js +1 -0
  35. karaoke_gen/nextjs_frontend/out/_next/static/chunks/112f346e31f991df.js +4 -0
  36. karaoke_gen/nextjs_frontend/out/_next/static/chunks/16d1a4dd9d8a873a.js +3 -0
  37. karaoke_gen/nextjs_frontend/out/_next/static/chunks/1ab85c362b8b0e86.js +9 -0
  38. karaoke_gen/nextjs_frontend/out/_next/static/chunks/247eb132b7f7b574.js +1 -0
  39. karaoke_gen/nextjs_frontend/out/_next/static/chunks/2b80d15cc95e4818.js +1 -0
  40. karaoke_gen/nextjs_frontend/out/_next/static/chunks/32c7eba5cd46c1bc.js +7 -0
  41. karaoke_gen/nextjs_frontend/out/_next/static/chunks/483f26794eae53d0.js +1 -0
  42. karaoke_gen/nextjs_frontend/out/_next/static/chunks/550c3b02e85f196a.js +1 -0
  43. karaoke_gen/nextjs_frontend/out/_next/static/chunks/55c5ade44387bef8.js +1 -0
  44. karaoke_gen/nextjs_frontend/out/_next/static/chunks/5628d92b5893add2.css +1 -0
  45. karaoke_gen/nextjs_frontend/out/_next/static/chunks/56ebf7665e4341c8.js +7 -0
  46. karaoke_gen/nextjs_frontend/out/_next/static/chunks/5997132b61dec430.js +1 -0
  47. karaoke_gen/nextjs_frontend/out/_next/static/chunks/5ea55255bce3eb9e.js +5 -0
  48. karaoke_gen/nextjs_frontend/out/_next/static/chunks/5eda89a57490b3cd.js +1 -0
  49. karaoke_gen/nextjs_frontend/out/_next/static/chunks/692f5d9e0d700c76.js +3 -0
  50. karaoke_gen/nextjs_frontend/out/_next/static/chunks/71d7a05b14f9f0f4.js +1 -0
  51. karaoke_gen/nextjs_frontend/out/_next/static/chunks/81ac355749ef3302.js +1 -0
  52. karaoke_gen/nextjs_frontend/out/_next/static/chunks/95f7e5934dbb0e5d.js +1 -0
  53. karaoke_gen/nextjs_frontend/out/_next/static/chunks/9bce8f19eaa46940.js +1 -0
  54. karaoke_gen/nextjs_frontend/out/_next/static/chunks/a6dad97d9634a72d.js +1 -0
  55. karaoke_gen/nextjs_frontend/out/_next/static/chunks/a9ed54eed3e14c92.js +2 -0
  56. karaoke_gen/nextjs_frontend/out/_next/static/chunks/b35cd41238ecfb17.js +1 -0
  57. karaoke_gen/nextjs_frontend/out/_next/static/chunks/b5bc3c3d5ebd49eb.js +1 -0
  58. karaoke_gen/nextjs_frontend/out/_next/static/chunks/b5c078c08db5ae32.js +5 -0
  59. karaoke_gen/nextjs_frontend/out/_next/static/chunks/be9c44a178104187.js +1 -0
  60. karaoke_gen/nextjs_frontend/out/_next/static/chunks/c4c840e18cb4861c.js +1 -0
  61. karaoke_gen/nextjs_frontend/out/_next/static/chunks/c645af7d6b65f73e.js +1 -0
  62. karaoke_gen/nextjs_frontend/out/_next/static/chunks/d2c5e2575df784d4.js +1 -0
  63. karaoke_gen/nextjs_frontend/out/_next/static/chunks/d30af02b96d81462.js +1 -0
  64. karaoke_gen/nextjs_frontend/out/_next/static/chunks/d9bdf64f4ec1e9b7.js +7 -0
  65. karaoke_gen/nextjs_frontend/out/_next/static/chunks/dcde6ed684dacd0e.js +5 -0
  66. karaoke_gen/nextjs_frontend/out/_next/static/chunks/e422cbe931246000.js +1 -0
  67. karaoke_gen/nextjs_frontend/out/_next/static/chunks/e483af34fc792d38.js +1 -0
  68. karaoke_gen/nextjs_frontend/out/_next/static/chunks/e57422aad6b897da.js +1 -0
  69. karaoke_gen/nextjs_frontend/out/_next/static/chunks/ef02697fb404726a.js +1 -0
  70. karaoke_gen/nextjs_frontend/out/_next/static/chunks/ff1a16fafef87110.js +1 -0
  71. karaoke_gen/nextjs_frontend/out/_next/static/chunks/turbopack-2d9ca3017a9deedf.js +3 -0
  72. karaoke_gen/nextjs_frontend/out/_next/static/zpw_-rjFIDV5tlPPtnvRI/_buildManifest.js +11 -0
  73. karaoke_gen/nextjs_frontend/out/_next/static/zpw_-rjFIDV5tlPPtnvRI/_clientMiddlewareManifest.json +1 -0
  74. karaoke_gen/nextjs_frontend/out/_next/static/zpw_-rjFIDV5tlPPtnvRI/_ssgManifest.js +1 -0
  75. karaoke_gen/nextjs_frontend/out/_not-found/__next._full.txt +18 -0
  76. karaoke_gen/nextjs_frontend/out/_not-found/__next._head.txt +8 -0
  77. karaoke_gen/nextjs_frontend/out/_not-found/__next._index.txt +9 -0
  78. karaoke_gen/nextjs_frontend/out/_not-found/__next._not-found.__PAGE__.txt +5 -0
  79. karaoke_gen/nextjs_frontend/out/_not-found/__next._not-found.txt +4 -0
  80. karaoke_gen/nextjs_frontend/out/_not-found/__next._tree.txt +2 -0
  81. karaoke_gen/nextjs_frontend/out/_not-found/index.html +1 -0
  82. karaoke_gen/nextjs_frontend/out/_not-found/index.txt +18 -0
  83. karaoke_gen/nextjs_frontend/out/admin/__next._full.txt +25 -0
  84. karaoke_gen/nextjs_frontend/out/admin/__next._head.txt +8 -0
  85. karaoke_gen/nextjs_frontend/out/admin/__next._index.txt +9 -0
  86. karaoke_gen/nextjs_frontend/out/admin/__next._tree.txt +2 -0
  87. karaoke_gen/nextjs_frontend/out/admin/__next.admin.__PAGE__.txt +9 -0
  88. karaoke_gen/nextjs_frontend/out/admin/__next.admin.txt +7 -0
  89. karaoke_gen/nextjs_frontend/out/admin/beta/__next._full.txt +25 -0
  90. karaoke_gen/nextjs_frontend/out/admin/beta/__next._head.txt +8 -0
  91. karaoke_gen/nextjs_frontend/out/admin/beta/__next._index.txt +9 -0
  92. karaoke_gen/nextjs_frontend/out/admin/beta/__next._tree.txt +2 -0
  93. karaoke_gen/nextjs_frontend/out/admin/beta/__next.admin.beta.__PAGE__.txt +9 -0
  94. karaoke_gen/nextjs_frontend/out/admin/beta/__next.admin.beta.txt +4 -0
  95. karaoke_gen/nextjs_frontend/out/admin/beta/__next.admin.txt +7 -0
  96. karaoke_gen/nextjs_frontend/out/admin/beta/index.html +1 -0
  97. karaoke_gen/nextjs_frontend/out/admin/beta/index.txt +25 -0
  98. karaoke_gen/nextjs_frontend/out/admin/index.html +1 -0
  99. karaoke_gen/nextjs_frontend/out/admin/index.txt +25 -0
  100. karaoke_gen/nextjs_frontend/out/admin/jobs/__next._full.txt +25 -0
  101. karaoke_gen/nextjs_frontend/out/admin/jobs/__next._head.txt +8 -0
  102. karaoke_gen/nextjs_frontend/out/admin/jobs/__next._index.txt +9 -0
  103. karaoke_gen/nextjs_frontend/out/admin/jobs/__next._tree.txt +2 -0
  104. karaoke_gen/nextjs_frontend/out/admin/jobs/__next.admin.jobs.__PAGE__.txt +9 -0
  105. karaoke_gen/nextjs_frontend/out/admin/jobs/__next.admin.jobs.txt +4 -0
  106. karaoke_gen/nextjs_frontend/out/admin/jobs/__next.admin.txt +7 -0
  107. karaoke_gen/nextjs_frontend/out/admin/jobs/index.html +1 -0
  108. karaoke_gen/nextjs_frontend/out/admin/jobs/index.txt +25 -0
  109. karaoke_gen/nextjs_frontend/out/admin/rate-limits/__next._full.txt +25 -0
  110. karaoke_gen/nextjs_frontend/out/admin/rate-limits/__next._head.txt +8 -0
  111. karaoke_gen/nextjs_frontend/out/admin/rate-limits/__next._index.txt +9 -0
  112. karaoke_gen/nextjs_frontend/out/admin/rate-limits/__next._tree.txt +2 -0
  113. karaoke_gen/nextjs_frontend/out/admin/rate-limits/__next.admin.rate-limits.__PAGE__.txt +9 -0
  114. karaoke_gen/nextjs_frontend/out/admin/rate-limits/__next.admin.rate-limits.txt +4 -0
  115. karaoke_gen/nextjs_frontend/out/admin/rate-limits/__next.admin.txt +7 -0
  116. karaoke_gen/nextjs_frontend/out/admin/rate-limits/index.html +1 -0
  117. karaoke_gen/nextjs_frontend/out/admin/rate-limits/index.txt +25 -0
  118. karaoke_gen/nextjs_frontend/out/admin/searches/__next._full.txt +25 -0
  119. karaoke_gen/nextjs_frontend/out/admin/searches/__next._head.txt +8 -0
  120. karaoke_gen/nextjs_frontend/out/admin/searches/__next._index.txt +9 -0
  121. karaoke_gen/nextjs_frontend/out/admin/searches/__next._tree.txt +2 -0
  122. karaoke_gen/nextjs_frontend/out/admin/searches/__next.admin.searches.__PAGE__.txt +9 -0
  123. karaoke_gen/nextjs_frontend/out/admin/searches/__next.admin.searches.txt +4 -0
  124. karaoke_gen/nextjs_frontend/out/admin/searches/__next.admin.txt +7 -0
  125. karaoke_gen/nextjs_frontend/out/admin/searches/index.html +1 -0
  126. karaoke_gen/nextjs_frontend/out/admin/searches/index.txt +25 -0
  127. karaoke_gen/nextjs_frontend/out/admin/users/__next._full.txt +25 -0
  128. karaoke_gen/nextjs_frontend/out/admin/users/__next._head.txt +8 -0
  129. karaoke_gen/nextjs_frontend/out/admin/users/__next._index.txt +9 -0
  130. karaoke_gen/nextjs_frontend/out/admin/users/__next._tree.txt +2 -0
  131. karaoke_gen/nextjs_frontend/out/admin/users/__next.admin.txt +7 -0
  132. karaoke_gen/nextjs_frontend/out/admin/users/__next.admin.users.__PAGE__.txt +9 -0
  133. karaoke_gen/nextjs_frontend/out/admin/users/__next.admin.users.txt +4 -0
  134. karaoke_gen/nextjs_frontend/out/admin/users/detail/__next._full.txt +25 -0
  135. karaoke_gen/nextjs_frontend/out/admin/users/detail/__next._head.txt +8 -0
  136. karaoke_gen/nextjs_frontend/out/admin/users/detail/__next._index.txt +9 -0
  137. karaoke_gen/nextjs_frontend/out/admin/users/detail/__next._tree.txt +2 -0
  138. karaoke_gen/nextjs_frontend/out/admin/users/detail/__next.admin.txt +7 -0
  139. karaoke_gen/nextjs_frontend/out/admin/users/detail/__next.admin.users.detail.__PAGE__.txt +9 -0
  140. karaoke_gen/nextjs_frontend/out/admin/users/detail/__next.admin.users.detail.txt +4 -0
  141. karaoke_gen/nextjs_frontend/out/admin/users/detail/__next.admin.users.txt +4 -0
  142. karaoke_gen/nextjs_frontend/out/admin/users/detail/index.html +1 -0
  143. karaoke_gen/nextjs_frontend/out/admin/users/detail/index.txt +25 -0
  144. karaoke_gen/nextjs_frontend/out/admin/users/index.html +1 -0
  145. karaoke_gen/nextjs_frontend/out/admin/users/index.txt +25 -0
  146. karaoke_gen/nextjs_frontend/out/app/__next._full.txt +22 -0
  147. karaoke_gen/nextjs_frontend/out/app/__next._head.txt +8 -0
  148. karaoke_gen/nextjs_frontend/out/app/__next._index.txt +9 -0
  149. karaoke_gen/nextjs_frontend/out/app/__next._tree.txt +2 -0
  150. karaoke_gen/nextjs_frontend/out/app/__next.app.__PAGE__.txt +9 -0
  151. karaoke_gen/nextjs_frontend/out/app/__next.app.txt +4 -0
  152. karaoke_gen/nextjs_frontend/out/app/index.html +1 -0
  153. karaoke_gen/nextjs_frontend/out/app/index.txt +22 -0
  154. karaoke_gen/nextjs_frontend/out/app/jobs/__next._full.txt +19 -0
  155. karaoke_gen/nextjs_frontend/out/app/jobs/__next._head.txt +8 -0
  156. karaoke_gen/nextjs_frontend/out/app/jobs/__next._index.txt +9 -0
  157. karaoke_gen/nextjs_frontend/out/app/jobs/__next._tree.txt +2 -0
  158. karaoke_gen/nextjs_frontend/out/app/jobs/__next.app.jobs.$oc$slug.__PAGE__.txt +6 -0
  159. karaoke_gen/nextjs_frontend/out/app/jobs/__next.app.jobs.$oc$slug.txt +4 -0
  160. karaoke_gen/nextjs_frontend/out/app/jobs/__next.app.jobs.txt +4 -0
  161. karaoke_gen/nextjs_frontend/out/app/jobs/__next.app.txt +4 -0
  162. karaoke_gen/nextjs_frontend/out/app/jobs/index.html +1 -0
  163. karaoke_gen/nextjs_frontend/out/app/jobs/index.txt +19 -0
  164. karaoke_gen/nextjs_frontend/out/app/jobs/local/instrumental/__next._full.txt +19 -0
  165. karaoke_gen/nextjs_frontend/out/app/jobs/local/instrumental/__next._head.txt +8 -0
  166. karaoke_gen/nextjs_frontend/out/app/jobs/local/instrumental/__next._index.txt +9 -0
  167. karaoke_gen/nextjs_frontend/out/app/jobs/local/instrumental/__next._tree.txt +2 -0
  168. karaoke_gen/nextjs_frontend/out/app/jobs/local/instrumental/__next.app.jobs.$oc$slug.__PAGE__.txt +6 -0
  169. karaoke_gen/nextjs_frontend/out/app/jobs/local/instrumental/__next.app.jobs.$oc$slug.txt +4 -0
  170. karaoke_gen/nextjs_frontend/out/app/jobs/local/instrumental/__next.app.jobs.txt +4 -0
  171. karaoke_gen/nextjs_frontend/out/app/jobs/local/instrumental/__next.app.txt +4 -0
  172. karaoke_gen/nextjs_frontend/out/app/jobs/local/instrumental/index.html +1 -0
  173. karaoke_gen/nextjs_frontend/out/app/jobs/local/instrumental/index.txt +19 -0
  174. karaoke_gen/nextjs_frontend/out/app/jobs/local/review/__next._full.txt +19 -0
  175. karaoke_gen/nextjs_frontend/out/app/jobs/local/review/__next._head.txt +8 -0
  176. karaoke_gen/nextjs_frontend/out/app/jobs/local/review/__next._index.txt +9 -0
  177. karaoke_gen/nextjs_frontend/out/app/jobs/local/review/__next._tree.txt +2 -0
  178. karaoke_gen/nextjs_frontend/out/app/jobs/local/review/__next.app.jobs.$oc$slug.__PAGE__.txt +6 -0
  179. karaoke_gen/nextjs_frontend/out/app/jobs/local/review/__next.app.jobs.$oc$slug.txt +4 -0
  180. karaoke_gen/nextjs_frontend/out/app/jobs/local/review/__next.app.jobs.txt +4 -0
  181. karaoke_gen/nextjs_frontend/out/app/jobs/local/review/__next.app.txt +4 -0
  182. karaoke_gen/nextjs_frontend/out/app/jobs/local/review/index.html +1 -0
  183. karaoke_gen/nextjs_frontend/out/app/jobs/local/review/index.txt +19 -0
  184. karaoke_gen/nextjs_frontend/out/auth/verify/__next._full.txt +22 -0
  185. karaoke_gen/nextjs_frontend/out/auth/verify/__next._head.txt +8 -0
  186. karaoke_gen/nextjs_frontend/out/auth/verify/__next._index.txt +9 -0
  187. karaoke_gen/nextjs_frontend/out/auth/verify/__next._tree.txt +2 -0
  188. karaoke_gen/nextjs_frontend/out/auth/verify/__next.auth.txt +4 -0
  189. karaoke_gen/nextjs_frontend/out/auth/verify/__next.auth.verify.__PAGE__.txt +9 -0
  190. karaoke_gen/nextjs_frontend/out/auth/verify/__next.auth.verify.txt +4 -0
  191. karaoke_gen/nextjs_frontend/out/auth/verify/index.html +1 -0
  192. karaoke_gen/nextjs_frontend/out/auth/verify/index.txt +22 -0
  193. karaoke_gen/nextjs_frontend/out/index.html +1 -0
  194. karaoke_gen/nextjs_frontend/out/index.txt +22 -0
  195. karaoke_gen/nextjs_frontend/out/manifest.webmanifest +31 -0
  196. karaoke_gen/nextjs_frontend/out/order/success/__next._full.txt +22 -0
  197. karaoke_gen/nextjs_frontend/out/order/success/__next._head.txt +8 -0
  198. karaoke_gen/nextjs_frontend/out/order/success/__next._index.txt +9 -0
  199. karaoke_gen/nextjs_frontend/out/order/success/__next._tree.txt +2 -0
  200. karaoke_gen/nextjs_frontend/out/order/success/__next.order.success.__PAGE__.txt +9 -0
  201. karaoke_gen/nextjs_frontend/out/order/success/__next.order.success.txt +4 -0
  202. karaoke_gen/nextjs_frontend/out/order/success/__next.order.txt +4 -0
  203. karaoke_gen/nextjs_frontend/out/order/success/index.html +1 -0
  204. karaoke_gen/nextjs_frontend/out/order/success/index.txt +22 -0
  205. karaoke_gen/nextjs_frontend/out/payment/success/__next._full.txt +22 -0
  206. karaoke_gen/nextjs_frontend/out/payment/success/__next._head.txt +8 -0
  207. karaoke_gen/nextjs_frontend/out/payment/success/__next._index.txt +9 -0
  208. karaoke_gen/nextjs_frontend/out/payment/success/__next._tree.txt +2 -0
  209. karaoke_gen/nextjs_frontend/out/payment/success/__next.payment.success.__PAGE__.txt +9 -0
  210. karaoke_gen/nextjs_frontend/out/payment/success/__next.payment.success.txt +4 -0
  211. karaoke_gen/nextjs_frontend/out/payment/success/__next.payment.txt +4 -0
  212. karaoke_gen/nextjs_frontend/out/payment/success/index.html +1 -0
  213. karaoke_gen/nextjs_frontend/out/payment/success/index.txt +22 -0
  214. karaoke_gen/nextjs_frontend/out/screenshots/email-action_reminder.png +0 -0
  215. karaoke_gen/nextjs_frontend/out/screenshots/email-beta_welcome.png +0 -0
  216. karaoke_gen/nextjs_frontend/out/screenshots/email-job_completion.png +0 -0
  217. karaoke_gen/nextjs_frontend/out/screenshots/example-output.avif +0 -0
  218. karaoke_gen/nextjs_frontend/out/screenshots/homepage-full.png +0 -0
  219. karaoke_gen/nextjs_frontend/out/screenshots/homepage-hero.png +0 -0
  220. karaoke_gen/nextjs_frontend/out/screenshots/instrumental-review.avif +0 -0
  221. karaoke_gen/nextjs_frontend/out/screenshots/instrumental-review.png +0 -0
  222. karaoke_gen/nextjs_frontend/out/screenshots/job-dashboard.avif +0 -0
  223. karaoke_gen/nextjs_frontend/out/screenshots/lyrics-review.avif +0 -0
  224. karaoke_gen/nextjs_frontend/out/screenshots/lyrics-review.png +0 -0
  225. karaoke_gen/nextjs_frontend/out/sw.js +183 -0
  226. karaoke_gen/utils/cli_args.py +3 -3
  227. karaoke_gen/utils/gen_cli.py +4 -0
  228. karaoke_gen/utils/remote_cli.py +8 -40
  229. {karaoke_gen-0.103.1.dist-info → karaoke_gen-0.107.0.dist-info}/METADATA +2 -1
  230. {karaoke_gen-0.103.1.dist-info → karaoke_gen-0.107.0.dist-info}/RECORD +244 -131
  231. {karaoke_gen-0.103.1.dist-info → karaoke_gen-0.107.0.dist-info}/WHEEL +1 -1
  232. lyrics_transcriber/correction/agentic/agent.py +83 -60
  233. lyrics_transcriber/correction/anchor_sequence.py +48 -3
  234. lyrics_transcriber/correction/corrector.py +92 -58
  235. lyrics_transcriber/review/server.py +165 -33
  236. lyrics_transcriber/utils/tracing.py +214 -0
  237. karaoke_gen/instrumental_review/static/index.html +0 -1695
  238. lyrics_transcriber/frontend/.gitignore +0 -24
  239. lyrics_transcriber/frontend/.yarn/releases/yarn-4.7.0.cjs +0 -935
  240. lyrics_transcriber/frontend/.yarnrc.yml +0 -3
  241. lyrics_transcriber/frontend/README.md +0 -50
  242. lyrics_transcriber/frontend/REPLACE_ALL_FUNCTIONALITY.md +0 -210
  243. lyrics_transcriber/frontend/__init__.py +0 -25
  244. lyrics_transcriber/frontend/e2e/agentic-corrections.spec.ts +0 -207
  245. lyrics_transcriber/frontend/e2e/fixtures/agentic-correction-data.json +0 -226
  246. lyrics_transcriber/frontend/eslint.config.js +0 -28
  247. lyrics_transcriber/frontend/index.html +0 -22
  248. lyrics_transcriber/frontend/package-lock.json +0 -4553
  249. lyrics_transcriber/frontend/package.json +0 -48
  250. lyrics_transcriber/frontend/playwright.config.ts +0 -69
  251. lyrics_transcriber/frontend/public/android-chrome-192x192.png +0 -0
  252. lyrics_transcriber/frontend/public/android-chrome-512x512.png +0 -0
  253. lyrics_transcriber/frontend/src/App.tsx +0 -243
  254. lyrics_transcriber/frontend/src/api.ts +0 -262
  255. lyrics_transcriber/frontend/src/components/AIFeedbackModal.tsx +0 -111
  256. lyrics_transcriber/frontend/src/components/AddLyricsModal.tsx +0 -114
  257. lyrics_transcriber/frontend/src/components/AgenticCorrectionMetrics.tsx +0 -204
  258. lyrics_transcriber/frontend/src/components/AppHeader.tsx +0 -65
  259. lyrics_transcriber/frontend/src/components/AudioPlayer.tsx +0 -180
  260. lyrics_transcriber/frontend/src/components/CorrectedWordWithActions.tsx +0 -175
  261. lyrics_transcriber/frontend/src/components/CorrectionAnnotationModal.tsx +0 -359
  262. lyrics_transcriber/frontend/src/components/CorrectionDetailCard.tsx +0 -281
  263. lyrics_transcriber/frontend/src/components/CorrectionMetrics.tsx +0 -162
  264. lyrics_transcriber/frontend/src/components/DurationTimelineView.tsx +0 -257
  265. lyrics_transcriber/frontend/src/components/EditActionBar.tsx +0 -94
  266. lyrics_transcriber/frontend/src/components/EditModal.tsx +0 -720
  267. lyrics_transcriber/frontend/src/components/EditTimelineSection.tsx +0 -592
  268. lyrics_transcriber/frontend/src/components/EditWordList.tsx +0 -431
  269. lyrics_transcriber/frontend/src/components/FileUpload.tsx +0 -77
  270. lyrics_transcriber/frontend/src/components/FindReplaceModal.tsx +0 -467
  271. lyrics_transcriber/frontend/src/components/Header.tsx +0 -520
  272. lyrics_transcriber/frontend/src/components/LyricsAnalyzer.tsx +0 -1526
  273. lyrics_transcriber/frontend/src/components/LyricsSynchronizer/SyncControls.tsx +0 -216
  274. lyrics_transcriber/frontend/src/components/LyricsSynchronizer/TimelineCanvas.tsx +0 -721
  275. lyrics_transcriber/frontend/src/components/LyricsSynchronizer/UpcomingWordsBar.tsx +0 -80
  276. lyrics_transcriber/frontend/src/components/LyricsSynchronizer/index.tsx +0 -999
  277. lyrics_transcriber/frontend/src/components/MetricsDashboard.tsx +0 -51
  278. lyrics_transcriber/frontend/src/components/ModeSelectionModal.tsx +0 -127
  279. lyrics_transcriber/frontend/src/components/ModeSelector.tsx +0 -67
  280. lyrics_transcriber/frontend/src/components/ModelSelector.tsx +0 -23
  281. lyrics_transcriber/frontend/src/components/PreviewVideoSection.tsx +0 -177
  282. lyrics_transcriber/frontend/src/components/ReferenceView.tsx +0 -268
  283. lyrics_transcriber/frontend/src/components/ReplaceAllLyricsModal.tsx +0 -336
  284. lyrics_transcriber/frontend/src/components/ReviewChangesModal.tsx +0 -354
  285. lyrics_transcriber/frontend/src/components/SegmentDetailsModal.tsx +0 -64
  286. lyrics_transcriber/frontend/src/components/TimelineEditor.tsx +0 -383
  287. lyrics_transcriber/frontend/src/components/TimingOffsetModal.tsx +0 -131
  288. lyrics_transcriber/frontend/src/components/TranscriptionView.tsx +0 -266
  289. lyrics_transcriber/frontend/src/components/WordDivider.tsx +0 -191
  290. lyrics_transcriber/frontend/src/components/shared/components/HighlightedText.tsx +0 -466
  291. lyrics_transcriber/frontend/src/components/shared/components/SourceSelector.tsx +0 -56
  292. lyrics_transcriber/frontend/src/components/shared/components/Word.tsx +0 -89
  293. lyrics_transcriber/frontend/src/components/shared/constants.ts +0 -30
  294. lyrics_transcriber/frontend/src/components/shared/hooks/useWordClick.ts +0 -180
  295. lyrics_transcriber/frontend/src/components/shared/styles.ts +0 -13
  296. lyrics_transcriber/frontend/src/components/shared/types.js +0 -2
  297. lyrics_transcriber/frontend/src/components/shared/types.ts +0 -135
  298. lyrics_transcriber/frontend/src/components/shared/utils/keyboardHandlers.ts +0 -177
  299. lyrics_transcriber/frontend/src/components/shared/utils/localStorage.ts +0 -78
  300. lyrics_transcriber/frontend/src/components/shared/utils/referenceLineCalculator.ts +0 -75
  301. lyrics_transcriber/frontend/src/components/shared/utils/segmentOperations.ts +0 -360
  302. lyrics_transcriber/frontend/src/components/shared/utils/timingUtils.ts +0 -110
  303. lyrics_transcriber/frontend/src/components/shared/utils/wordUtils.ts +0 -22
  304. lyrics_transcriber/frontend/src/hooks/useManualSync.ts +0 -537
  305. lyrics_transcriber/frontend/src/main.tsx +0 -11
  306. lyrics_transcriber/frontend/src/theme.ts +0 -406
  307. lyrics_transcriber/frontend/src/types/global.d.ts +0 -9
  308. lyrics_transcriber/frontend/src/types.js +0 -2
  309. lyrics_transcriber/frontend/src/types.ts +0 -199
  310. lyrics_transcriber/frontend/src/validation.ts +0 -132
  311. lyrics_transcriber/frontend/src/vite-env.d.ts +0 -1
  312. lyrics_transcriber/frontend/tsconfig.app.json +0 -26
  313. lyrics_transcriber/frontend/tsconfig.json +0 -25
  314. lyrics_transcriber/frontend/tsconfig.node.json +0 -23
  315. lyrics_transcriber/frontend/tsconfig.tsbuildinfo +0 -1
  316. lyrics_transcriber/frontend/update_version.js +0 -11
  317. lyrics_transcriber/frontend/vite.config.d.ts +0 -2
  318. lyrics_transcriber/frontend/vite.config.js +0 -15
  319. lyrics_transcriber/frontend/vite.config.ts +0 -16
  320. lyrics_transcriber/frontend/web_assets/android-chrome-192x192.png +0 -0
  321. lyrics_transcriber/frontend/web_assets/android-chrome-512x512.png +0 -0
  322. lyrics_transcriber/frontend/web_assets/apple-touch-icon.png +0 -0
  323. lyrics_transcriber/frontend/web_assets/assets/index-BSMgOq4Z.js +0 -44465
  324. lyrics_transcriber/frontend/web_assets/assets/index-BSMgOq4Z.js.map +0 -1
  325. lyrics_transcriber/frontend/web_assets/favicon-16x16.png +0 -0
  326. lyrics_transcriber/frontend/web_assets/favicon-32x32.png +0 -0
  327. lyrics_transcriber/frontend/web_assets/favicon.ico +0 -0
  328. lyrics_transcriber/frontend/web_assets/index.html +0 -22
  329. lyrics_transcriber/frontend/web_assets/nomad-karaoke-logo.png +0 -0
  330. lyrics_transcriber/frontend/web_assets/nomad-karaoke-logo.svg +0 -5
  331. lyrics_transcriber/frontend/yarn.lock +0 -3711
  332. {lyrics_transcriber/frontend/public → karaoke_gen/nextjs_frontend/out}/apple-touch-icon.png +0 -0
  333. {lyrics_transcriber/frontend/public → karaoke_gen/nextjs_frontend/out}/favicon-16x16.png +0 -0
  334. {lyrics_transcriber/frontend/public → karaoke_gen/nextjs_frontend/out}/favicon-32x32.png +0 -0
  335. {lyrics_transcriber/frontend/public → karaoke_gen/nextjs_frontend/out}/favicon.ico +0 -0
  336. {lyrics_transcriber/frontend/public → karaoke_gen/nextjs_frontend/out}/nomad-karaoke-logo.svg +0 -0
  337. /lyrics_transcriber/frontend/public/nomad-karaoke-logo.png → /karaoke_gen/nextjs_frontend/out/nomad-logo.png +0 -0
  338. {karaoke_gen-0.103.1.dist-info → karaoke_gen-0.107.0.dist-info}/entry_points.txt +0 -0
  339. {karaoke_gen-0.103.1.dist-info → karaoke_gen-0.107.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,175 +0,0 @@
1
- import { Box, IconButton, Tooltip, useMediaQuery, useTheme } from '@mui/material'
2
- import UndoIcon from '@mui/icons-material/Undo'
3
- import EditIcon from '@mui/icons-material/Edit'
4
- import CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutline'
5
- import { COLORS } from './shared/constants'
6
- import { styled } from '@mui/material/styles'
7
-
8
- interface CorrectionInfo {
9
- originalWord: string
10
- handler: string
11
- confidence: number
12
- source: string
13
- reason?: string
14
- }
15
-
16
- interface CorrectedWordWithActionsProps {
17
- word: string
18
- originalWord: string
19
- correction: CorrectionInfo
20
- onRevert: () => void
21
- onEdit: () => void
22
- onAccept: () => void
23
- onClick?: () => void
24
- backgroundColor?: string
25
- shouldFlash?: boolean
26
- showActions?: boolean // Controls whether inline action buttons are visible
27
- }
28
-
29
- const WordContainer = styled(Box, {
30
- shouldForwardProp: (prop) => !['shouldFlash'].includes(prop as string)
31
- })<{ shouldFlash?: boolean }>(({ shouldFlash }) => ({
32
- display: 'inline-flex',
33
- alignItems: 'center',
34
- gap: '2px',
35
- padding: '1px 3px',
36
- borderRadius: '2px',
37
- cursor: 'pointer',
38
- position: 'relative',
39
- backgroundColor: COLORS.corrected,
40
- animation: shouldFlash ? 'flash 1s ease-in-out infinite' : 'none',
41
- '@keyframes flash': {
42
- '0%, 100%': { opacity: 1 },
43
- '50%': { opacity: 0.5 }
44
- },
45
- '&:hover': {
46
- backgroundColor: 'rgba(34, 197, 94, 0.35)' // green tint hover - works for both modes
47
- }
48
- }))
49
-
50
- const OriginalWordLabel = styled(Box)(({ theme }) => ({
51
- position: 'absolute',
52
- top: '-14px',
53
- left: '0',
54
- fontSize: '0.6rem',
55
- color: theme.palette.text.secondary, // Theme-aware text color
56
- textDecoration: 'line-through',
57
- opacity: 0.7,
58
- whiteSpace: 'nowrap',
59
- pointerEvents: 'none'
60
- }))
61
-
62
- const ActionsContainer = styled(Box)({
63
- display: 'inline-flex',
64
- alignItems: 'center',
65
- gap: '1px',
66
- marginLeft: '2px'
67
- })
68
-
69
- const ActionButton = styled(IconButton)(({ theme }) => ({
70
- padding: '2px',
71
- minWidth: '20px',
72
- minHeight: '20px',
73
- width: '20px',
74
- height: '20px',
75
- backgroundColor: theme.palette.mode === 'dark'
76
- ? 'rgba(30, 41, 59, 0.9)' // slate-800 with opacity for dark mode
77
- : 'rgba(241, 245, 249, 0.9)', // slate-100 for light mode
78
- border: `1px solid ${theme.palette.divider}`,
79
- '&:hover': {
80
- backgroundColor: theme.palette.mode === 'dark'
81
- ? 'rgba(51, 65, 85, 1)' // slate-700 for dark mode
82
- : 'rgba(226, 232, 240, 1)', // slate-200 for light mode
83
- transform: 'scale(1.1)'
84
- },
85
- '& .MuiSvgIcon-root': {
86
- fontSize: '0.875rem'
87
- },
88
- // Ensure minimum touch target on mobile
89
- [theme.breakpoints.down('sm')]: {
90
- minWidth: '28px',
91
- minHeight: '28px',
92
- width: '28px',
93
- height: '28px',
94
- padding: '4px'
95
- }
96
- }))
97
-
98
- export default function CorrectedWordWithActions({
99
- word,
100
- originalWord,
101
- onRevert,
102
- onEdit,
103
- onAccept,
104
- onClick,
105
- backgroundColor,
106
- shouldFlash,
107
- showActions = true
108
- }: CorrectedWordWithActionsProps) {
109
- const theme = useTheme()
110
- const isMobile = useMediaQuery(theme.breakpoints.down('sm'))
111
-
112
- const handleAction = (e: React.MouseEvent, action: () => void) => {
113
- e.stopPropagation()
114
- action()
115
- }
116
-
117
- return (
118
- <WordContainer
119
- shouldFlash={shouldFlash}
120
- sx={{ backgroundColor: backgroundColor || COLORS.corrected }}
121
- onClick={onClick}
122
- >
123
- <OriginalWordLabel>{originalWord}</OriginalWordLabel>
124
-
125
- <Box
126
- component="span"
127
- sx={{
128
- fontSize: '0.85rem',
129
- lineHeight: 1.2,
130
- fontWeight: 600
131
- }}
132
- >
133
- {word}
134
- </Box>
135
-
136
- {showActions && (
137
- <ActionsContainer>
138
- <Tooltip title="Revert to original" placement="top" arrow>
139
- <ActionButton
140
- size="small"
141
- onClick={(e) => handleAction(e, onRevert)}
142
- aria-label="revert correction"
143
- >
144
- <UndoIcon />
145
- </ActionButton>
146
- </Tooltip>
147
-
148
- <Tooltip title="Edit correction" placement="top" arrow>
149
- <ActionButton
150
- size="small"
151
- onClick={(e) => handleAction(e, onEdit)}
152
- aria-label="edit correction"
153
- >
154
- <EditIcon />
155
- </ActionButton>
156
- </Tooltip>
157
-
158
- {!isMobile && (
159
- <Tooltip title="Accept correction" placement="top" arrow>
160
- <ActionButton
161
- size="small"
162
- onClick={(e) => handleAction(e, onAccept)}
163
- aria-label="accept correction"
164
- sx={{ color: 'success.main' }}
165
- >
166
- <CheckCircleOutlineIcon />
167
- </ActionButton>
168
- </Tooltip>
169
- )}
170
- </ActionsContainer>
171
- )}
172
- </WordContainer>
173
- )
174
- }
175
-
@@ -1,359 +0,0 @@
1
- import { useState, useEffect } from 'react'
2
- import {
3
- Dialog,
4
- DialogTitle,
5
- DialogContent,
6
- DialogActions,
7
- Button,
8
- FormControl,
9
- InputLabel,
10
- Select,
11
- MenuItem,
12
- TextField,
13
- Slider,
14
- Typography,
15
- Box,
16
- Paper,
17
- Chip,
18
- Alert,
19
- SelectChangeEvent
20
- } from '@mui/material'
21
- import { CorrectionAnnotation, CorrectionAnnotationType, CorrectionAction } from '../types'
22
-
23
- interface CorrectionAnnotationModalProps {
24
- open: boolean
25
- onClose: () => void
26
- onSave: (annotation: Omit<CorrectionAnnotation, 'annotation_id' | 'timestamp'>) => void
27
- onSkip: () => void
28
- // Context about the correction being made
29
- originalText: string
30
- correctedText: string
31
- wordIdsAffected: string[]
32
- // Optional: What the AI suggested
33
- agenticProposal?: {
34
- action: string
35
- replacement_text?: string
36
- confidence: number
37
- reason: string
38
- gap_category?: string
39
- }
40
- // Reference lyrics that were consulted
41
- referenceSources: string[]
42
- // Song metadata
43
- audioHash: string
44
- artist: string
45
- title: string
46
- sessionId: string
47
- gapId?: string
48
- }
49
-
50
- const ANNOTATION_TYPES: { value: CorrectionAnnotationType; label: string; description: string }[] = [
51
- {
52
- value: 'SOUND_ALIKE' as CorrectionAnnotationType,
53
- label: 'Sound-Alike Error',
54
- description: 'Homophones or similar-sounding words (e.g., "out" vs "now")'
55
- },
56
- {
57
- value: 'BACKGROUND_VOCALS' as CorrectionAnnotationType,
58
- label: 'Background Vocals',
59
- description: 'Backing vocals that should be removed from karaoke'
60
- },
61
- {
62
- value: 'EXTRA_WORDS' as CorrectionAnnotationType,
63
- label: 'Extra Filler Words',
64
- description: 'Transcription added words like "And", "But", "Well"'
65
- },
66
- {
67
- value: 'PUNCTUATION_ONLY' as CorrectionAnnotationType,
68
- label: 'Punctuation/Style Only',
69
- description: 'Only punctuation or capitalization differences'
70
- },
71
- {
72
- value: 'REPEATED_SECTION' as CorrectionAnnotationType,
73
- label: 'Repeated Section',
74
- description: 'Chorus or verse repetition not in condensed references'
75
- },
76
- {
77
- value: 'COMPLEX_MULTI_ERROR' as CorrectionAnnotationType,
78
- label: 'Complex Multi-Error',
79
- description: 'Multiple different error types in one section'
80
- },
81
- {
82
- value: 'AMBIGUOUS' as CorrectionAnnotationType,
83
- label: 'Ambiguous',
84
- description: 'Unclear without listening to audio'
85
- },
86
- {
87
- value: 'NO_ERROR' as CorrectionAnnotationType,
88
- label: 'No Error',
89
- description: 'Transcription matches at least one reference source'
90
- },
91
- {
92
- value: 'MANUAL_EDIT' as CorrectionAnnotationType,
93
- label: 'Manual Edit',
94
- description: 'Human-initiated correction not from detected gap'
95
- }
96
- ]
97
-
98
- const CONFIDENCE_LABELS: { [key: number]: string } = {
99
- 1: '1 - Very Uncertain',
100
- 2: '2 - Somewhat Uncertain',
101
- 3: '3 - Neutral',
102
- 4: '4 - Fairly Confident',
103
- 5: '5 - Very Confident'
104
- }
105
-
106
- export default function CorrectionAnnotationModal({
107
- open,
108
- onClose,
109
- onSave,
110
- onSkip,
111
- originalText,
112
- correctedText,
113
- wordIdsAffected,
114
- agenticProposal,
115
- referenceSources,
116
- audioHash,
117
- artist,
118
- title,
119
- sessionId,
120
- gapId
121
- }: CorrectionAnnotationModalProps) {
122
- const [annotationType, setAnnotationType] = useState<CorrectionAnnotationType>('MANUAL_EDIT' as CorrectionAnnotationType)
123
- const [actionTaken, setActionTaken] = useState<CorrectionAction>('REPLACE' as CorrectionAction)
124
- const [confidence, setConfidence] = useState<number>(3)
125
- const [reasoning, setReasoning] = useState<string>('')
126
- const [agenticAgreed, setAgenticAgreed] = useState<boolean>(false)
127
- const [error, setError] = useState<string>('')
128
-
129
- // Pre-fill if we have an agentic proposal
130
- useEffect(() => {
131
- if (agenticProposal && agenticProposal.gap_category) {
132
- setAnnotationType(agenticProposal.gap_category as CorrectionAnnotationType)
133
- // Check if human correction matches AI suggestion
134
- const agreed = agenticProposal.replacement_text
135
- ? correctedText.toLowerCase().includes(agenticProposal.replacement_text.toLowerCase())
136
- : false
137
- setAgenticAgreed(agreed)
138
- }
139
- }, [agenticProposal, correctedText])
140
-
141
- // Determine action type based on correction
142
- useEffect(() => {
143
- if (originalText === correctedText) {
144
- setActionTaken('NO_ACTION' as CorrectionAction)
145
- } else if (correctedText === '') {
146
- setActionTaken('DELETE' as CorrectionAction)
147
- } else if (originalText === '') {
148
- setActionTaken('INSERT' as CorrectionAction)
149
- } else {
150
- setActionTaken('REPLACE' as CorrectionAction)
151
- }
152
- }, [originalText, correctedText])
153
-
154
- const handleSave = () => {
155
- // Validate
156
- if (reasoning.length < 10) {
157
- setError('Reasoning must be at least 10 characters')
158
- return
159
- }
160
-
161
- const annotation: Omit<CorrectionAnnotation, 'annotation_id' | 'timestamp'> = {
162
- audio_hash: audioHash,
163
- gap_id: gapId || null,
164
- annotation_type: annotationType,
165
- action_taken: actionTaken,
166
- original_text: originalText,
167
- corrected_text: correctedText,
168
- confidence,
169
- reasoning,
170
- word_ids_affected: wordIdsAffected,
171
- agentic_proposal: agenticProposal || null,
172
- agentic_category: agenticProposal?.gap_category || null,
173
- agentic_agreed: agenticAgreed,
174
- reference_sources_consulted: referenceSources,
175
- artist,
176
- title,
177
- session_id: sessionId
178
- }
179
-
180
- onSave(annotation)
181
- handleClose()
182
- }
183
-
184
- const handleClose = () => {
185
- // Reset form
186
- setAnnotationType('MANUAL_EDIT' as CorrectionAnnotationType)
187
- setConfidence(3)
188
- setReasoning('')
189
- setError('')
190
- setAgenticAgreed(false)
191
- onClose()
192
- }
193
-
194
- const handleSkipAndClose = () => {
195
- handleClose()
196
- onSkip()
197
- }
198
-
199
- return (
200
- <Dialog
201
- open={open}
202
- onClose={handleClose}
203
- maxWidth="md"
204
- fullWidth
205
- >
206
- <DialogTitle>
207
- <Typography variant="h6">Annotate Your Correction</Typography>
208
- <Typography variant="caption" color="text.secondary">
209
- Help improve the AI by explaining your correction
210
- </Typography>
211
- </DialogTitle>
212
-
213
- <DialogContent dividers>
214
- {/* Show what changed */}
215
- <Paper elevation={0} sx={{ p: 2, mb: 3, bgcolor: 'grey.50' }}>
216
- <Typography variant="subtitle2" gutterBottom>
217
- Your Correction:
218
- </Typography>
219
- <Box sx={{ display: 'flex', gap: 2, alignItems: 'center' }}>
220
- <Box sx={{ flex: 1 }}>
221
- <Typography variant="caption" color="error">Original:</Typography>
222
- <Typography
223
- sx={{
224
- textDecoration: 'line-through',
225
- color: 'error.main',
226
- fontFamily: 'monospace'
227
- }}
228
- >
229
- {originalText || '(empty)'}
230
- </Typography>
231
- </Box>
232
- <Typography variant="h6">→</Typography>
233
- <Box sx={{ flex: 1 }}>
234
- <Typography variant="caption" color="success.main">Corrected:</Typography>
235
- <Typography
236
- sx={{
237
- color: 'success.main',
238
- fontWeight: 'bold',
239
- fontFamily: 'monospace'
240
- }}
241
- >
242
- {correctedText || '(empty)'}
243
- </Typography>
244
- </Box>
245
- </Box>
246
- </Paper>
247
-
248
- {/* Show AI suggestion if available */}
249
- {agenticProposal && (
250
- <Alert
251
- severity={agenticAgreed ? "success" : "info"}
252
- sx={{ mb: 3 }}
253
- >
254
- <Typography variant="subtitle2" gutterBottom>
255
- AI Suggestion:
256
- </Typography>
257
- <Typography variant="body2">
258
- Category: <strong>{agenticProposal.gap_category}</strong>
259
- </Typography>
260
- <Typography variant="body2">
261
- Action: <strong>{agenticProposal.action}</strong>
262
- {agenticProposal.replacement_text && ` → "${agenticProposal.replacement_text}"`}
263
- </Typography>
264
- <Typography variant="body2">
265
- Reason: {agenticProposal.reason}
266
- </Typography>
267
- <Typography variant="body2" sx={{ mt: 1 }}>
268
- {agenticAgreed
269
- ? '✓ Your correction matches the AI suggestion'
270
- : '✗ Your correction differs from the AI suggestion'}
271
- </Typography>
272
- </Alert>
273
- )}
274
-
275
- {/* Reference sources */}
276
- {referenceSources.length > 0 && (
277
- <Box sx={{ mb: 3 }}>
278
- <Typography variant="subtitle2" gutterBottom>
279
- Reference Sources Consulted:
280
- </Typography>
281
- <Box sx={{ display: 'flex', gap: 1, flexWrap: 'wrap' }}>
282
- {referenceSources.map(source => (
283
- <Chip key={source} label={source} size="small" />
284
- ))}
285
- </Box>
286
- </Box>
287
- )}
288
-
289
- {/* Annotation type */}
290
- <FormControl fullWidth sx={{ mb: 3 }}>
291
- <InputLabel>Correction Type *</InputLabel>
292
- <Select
293
- value={annotationType}
294
- label="Correction Type *"
295
- onChange={(e: SelectChangeEvent) => setAnnotationType(e.target.value as CorrectionAnnotationType)}
296
- >
297
- {ANNOTATION_TYPES.map(type => (
298
- <MenuItem key={type.value} value={type.value}>
299
- <Box>
300
- <Typography variant="body1">{type.label}</Typography>
301
- <Typography variant="caption" color="text.secondary">
302
- {type.description}
303
- </Typography>
304
- </Box>
305
- </MenuItem>
306
- ))}
307
- </Select>
308
- </FormControl>
309
-
310
- {/* Confidence slider */}
311
- <Box sx={{ mb: 3 }}>
312
- <Typography variant="subtitle2" gutterBottom>
313
- Confidence in Your Correction *
314
- </Typography>
315
- <Slider
316
- value={confidence}
317
- onChange={(_, newValue) => setConfidence(newValue as number)}
318
- min={1}
319
- max={5}
320
- step={1}
321
- marks
322
- valueLabelDisplay="auto"
323
- valueLabelFormat={(value) => CONFIDENCE_LABELS[value]}
324
- />
325
- <Typography variant="caption" color="text.secondary">
326
- {CONFIDENCE_LABELS[confidence]}
327
- </Typography>
328
- </Box>
329
-
330
- {/* Reasoning text area */}
331
- <TextField
332
- fullWidth
333
- multiline
334
- rows={4}
335
- label="Reasoning *"
336
- placeholder="Explain why this correction is needed (minimum 10 characters)..."
337
- value={reasoning}
338
- onChange={(e) => {
339
- setReasoning(e.target.value)
340
- setError('')
341
- }}
342
- error={!!error}
343
- helperText={error || `${reasoning.length}/10 minimum characters`}
344
- required
345
- />
346
- </DialogContent>
347
-
348
- <DialogActions>
349
- <Button onClick={handleSkipAndClose} color="inherit">
350
- Skip
351
- </Button>
352
- <Button onClick={handleSave} variant="contained" color="primary">
353
- Save & Continue
354
- </Button>
355
- </DialogActions>
356
- </Dialog>
357
- )
358
- }
359
-