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,383 +0,0 @@
1
- import { Box, styled } from '@mui/material'
2
- import { Word } from '../types'
3
- import { useRef, useState } from 'react'
4
-
5
- interface TimelineEditorProps {
6
- words: Word[]
7
- startTime: number
8
- endTime: number
9
- onWordUpdate: (index: number, updates: Partial<Word>) => void
10
- onUnsyncWord?: (index: number) => void
11
- currentTime?: number
12
- onPlaySegment?: (time: number) => void
13
- showPlaybackIndicator?: boolean
14
- }
15
-
16
- const TimelineContainer = styled(Box)(({ theme }) => ({
17
- position: 'relative',
18
- height: '75px',
19
- backgroundColor: theme.palette.mode === 'dark'
20
- ? theme.palette.background.paper // Dark mode: use card background
21
- : theme.palette.grey[100], // Light mode: subtle gray
22
- borderRadius: theme.shape.borderRadius,
23
- margin: theme.spacing(1, 0),
24
- padding: theme.spacing(0, 1),
25
- border: `1px solid ${theme.palette.divider}`,
26
- }))
27
-
28
- const TimelineRuler = styled(Box)(({ theme }) => ({
29
- position: 'absolute',
30
- top: 0,
31
- left: 0,
32
- right: 0,
33
- height: '40px',
34
- borderBottom: `1px solid ${theme.palette.divider}`,
35
- cursor: 'pointer',
36
- }))
37
-
38
- const TimelineMark = styled(Box)(({ theme }) => ({
39
- position: 'absolute',
40
- top: '20px',
41
- width: '1px',
42
- height: '18px',
43
- backgroundColor: theme.palette.text.secondary,
44
- '&.subsecond': {
45
- top: '25px',
46
- height: '13px',
47
- backgroundColor: theme.palette.text.disabled,
48
- }
49
- }))
50
-
51
- const TimelineLabel = styled(Box)(({ theme }) => ({
52
- position: 'absolute',
53
- top: '5px',
54
- transform: 'translateX(-50%)',
55
- fontSize: '0.8rem',
56
- color: theme.palette.text.primary,
57
- fontWeight: 700,
58
- backgroundColor: theme.palette.mode === 'dark'
59
- ? theme.palette.background.paper
60
- : theme.palette.grey[100],
61
- padding: '0 4px',
62
- borderRadius: '2px',
63
- }))
64
-
65
- const TimelineWord = styled(Box)(({ theme }) => ({
66
- position: 'absolute',
67
- height: '30px',
68
- top: '40px',
69
- backgroundColor: theme.palette.primary.main,
70
- borderRadius: theme.shape.borderRadius,
71
- color: theme.palette.primary.contrastText,
72
- padding: theme.spacing(0.5, 1),
73
- cursor: 'move',
74
- userSelect: 'none',
75
- display: 'flex',
76
- alignItems: 'center',
77
- fontSize: '0.875rem',
78
- fontFamily: 'sans-serif',
79
- transition: 'background-color 0.1s ease',
80
- boxSizing: 'border-box',
81
- '&.highlighted': {
82
- backgroundColor: theme.palette.secondary.main,
83
- }
84
- }))
85
-
86
- const ResizeHandle = styled(Box)(({ theme }) => ({
87
- position: 'absolute',
88
- top: 0,
89
- width: 10,
90
- height: '100%',
91
- cursor: 'col-resize',
92
- '&:hover': {
93
- backgroundColor: theme.palette.primary.light,
94
- opacity: 0.8,
95
- boxShadow: `0 0 0 1px ${theme.palette.primary.dark}`,
96
- },
97
- '&.left': {
98
- left: 0,
99
- right: 'auto',
100
- paddingRight: 0,
101
- borderTopLeftRadius: theme.shape.borderRadius,
102
- borderBottomLeftRadius: theme.shape.borderRadius,
103
- },
104
- '&.right': {
105
- right: 0,
106
- left: 'auto',
107
- paddingLeft: 0,
108
- borderTopRightRadius: theme.shape.borderRadius,
109
- borderBottomRightRadius: theme.shape.borderRadius,
110
- }
111
- }))
112
-
113
- // Add new styled component for the cursor
114
- const TimelineCursor = styled(Box)(({ theme }) => ({
115
- position: 'absolute',
116
- top: 0,
117
- width: '2px',
118
- height: '100%', // Full height of container
119
- backgroundColor: theme.palette.error.main, // Red color
120
- pointerEvents: 'none', // Ensure it doesn't interfere with clicks
121
- transition: 'left 0.1s linear', // Smooth movement
122
- zIndex: 1, // Ensure it's above other elements
123
- }))
124
-
125
- export default function TimelineEditor({ words, startTime, endTime, onWordUpdate, onUnsyncWord, currentTime = 0, onPlaySegment, showPlaybackIndicator = true }: TimelineEditorProps) {
126
- const containerRef = useRef<HTMLDivElement>(null)
127
- const [dragState, setDragState] = useState<{
128
- wordIndex: number
129
- type: 'move' | 'resize-left' | 'resize-right'
130
- initialX: number
131
- initialTime: number
132
- word: Word
133
- } | null>(null)
134
-
135
- const MIN_DURATION = 0.1 // Minimum word duration in seconds
136
-
137
- const checkCollision = (
138
- proposedStart: number,
139
- proposedEnd: number,
140
- currentIndex: number,
141
- isResize: boolean
142
- ): boolean => {
143
- if (isResize) {
144
- if (currentIndex === words.length - 1) return false;
145
-
146
- const nextWord = words[currentIndex + 1]
147
- if (!nextWord || nextWord.start_time === null) return false
148
- return proposedEnd > nextWord.start_time
149
- }
150
-
151
- return words.some((word, index) => {
152
- if (index === currentIndex) return false
153
- if (word.start_time === null || word.end_time === null) return false
154
-
155
- return (
156
- (proposedStart >= word.start_time && proposedStart <= word.end_time) ||
157
- (proposedEnd >= word.start_time && proposedEnd <= word.end_time) ||
158
- (proposedStart <= word.start_time && proposedEnd >= word.end_time)
159
- )
160
- })
161
- }
162
-
163
- const timeToPosition = (time: number): number => {
164
- const duration = endTime - startTime
165
- const position = ((time - startTime) / duration) * 100
166
- return Math.max(0, Math.min(100, position))
167
- }
168
- const generateTimelineMarks = () => {
169
- const marks = []
170
- const startSecond = Math.floor(startTime)
171
- const endSecond = Math.ceil(endTime)
172
-
173
- // Generate marks for each second
174
- for (let time = startSecond; time <= endSecond; time++) {
175
- if (time >= startTime && time <= endTime) {
176
- const position = timeToPosition(time)
177
- marks.push(
178
- <Box key={time}>
179
- <TimelineMark sx={{ left: `${position}%` }} />
180
- <TimelineLabel sx={{ left: `${position}%` }}>
181
- {time}s
182
- </TimelineLabel>
183
- </Box>
184
- )
185
- }
186
- }
187
- return marks
188
- }
189
-
190
- const handleMouseDown = (e: React.MouseEvent, wordIndex: number, type: 'move' | 'resize-left' | 'resize-right') => {
191
- const rect = containerRef.current?.getBoundingClientRect()
192
- if (!rect) return
193
-
194
- const word = words[wordIndex]
195
- if (word.start_time === null || word.end_time === null) return
196
-
197
- const initialX = e.clientX - rect.left
198
- const initialTime = ((initialX / rect.width) * (endTime - startTime))
199
-
200
- setDragState({
201
- wordIndex,
202
- type,
203
- initialX,
204
- initialTime,
205
- word
206
- })
207
- }
208
-
209
- const handleMouseMove = (e: React.MouseEvent) => {
210
- if (!dragState || !containerRef.current) return
211
-
212
- const rect = containerRef.current.getBoundingClientRect()
213
- const x = e.clientX - rect.left
214
- const width = rect.width
215
-
216
- const currentWord = words[dragState.wordIndex]
217
- if (currentWord.start_time === null || currentWord.end_time === null ||
218
- dragState.word.start_time === null || dragState.word.end_time === null) return
219
-
220
- if (dragState.type === 'resize-right') {
221
- const initialWordDuration = dragState.word.end_time - dragState.word.start_time
222
- const initialWordWidth = (initialWordDuration / (endTime - startTime)) * width
223
- const pixelDelta = x - dragState.initialX
224
- const percentageMoved = pixelDelta / initialWordWidth
225
- const timeDelta = initialWordDuration * percentageMoved
226
-
227
- const proposedEnd = Math.max(
228
- currentWord.start_time + MIN_DURATION,
229
- dragState.word.end_time + timeDelta
230
- )
231
-
232
- if (checkCollision(currentWord.start_time, proposedEnd, dragState.wordIndex, true)) return
233
-
234
- onWordUpdate(dragState.wordIndex, {
235
- start_time: currentWord.start_time,
236
- end_time: proposedEnd
237
- })
238
- } else if (dragState.type === 'resize-left') {
239
- const initialWordDuration = dragState.word.end_time - dragState.word.start_time
240
- const initialWordWidth = (initialWordDuration / (endTime - startTime)) * width
241
- const pixelDelta = x - dragState.initialX
242
- const percentageMoved = pixelDelta / initialWordWidth
243
- const timeDelta = initialWordDuration * percentageMoved
244
-
245
- const proposedStart = Math.min(
246
- currentWord.end_time - MIN_DURATION,
247
- dragState.word.start_time + timeDelta
248
- )
249
-
250
- if (checkCollision(proposedStart, currentWord.end_time, dragState.wordIndex, true)) return
251
-
252
- onWordUpdate(dragState.wordIndex, {
253
- start_time: proposedStart,
254
- end_time: currentWord.end_time
255
- })
256
- } else if (dragState.type === 'move') {
257
- const pixelsPerSecond = width / (endTime - startTime)
258
- const pixelDelta = x - dragState.initialX
259
- const timeDelta = pixelDelta / pixelsPerSecond
260
-
261
- const wordDuration = currentWord.end_time - currentWord.start_time
262
- const proposedStart = dragState.word.start_time + timeDelta
263
- const proposedEnd = proposedStart + wordDuration
264
-
265
- if (proposedStart < startTime || proposedEnd > endTime) return
266
- if (checkCollision(proposedStart, proposedEnd, dragState.wordIndex, false)) return
267
-
268
- onWordUpdate(dragState.wordIndex, {
269
- start_time: proposedStart,
270
- end_time: proposedEnd
271
- })
272
- }
273
- }
274
-
275
- const handleMouseUp = () => {
276
- setDragState(null)
277
- }
278
-
279
- const handleContextMenu = (e: React.MouseEvent, wordIndex: number) => {
280
- e.preventDefault()
281
- e.stopPropagation()
282
-
283
- // Only unsync synced words
284
- const word = words[wordIndex]
285
- if (word.start_time === null || word.end_time === null) return
286
-
287
- // Directly unsync the word without showing a menu
288
- if (onUnsyncWord) {
289
- console.log('TimelineEditor - Right-click unsync word', {
290
- wordIndex,
291
- wordText: word.text
292
- })
293
- onUnsyncWord(wordIndex)
294
- }
295
- }
296
-
297
- const isWordHighlighted = (word: Word): boolean => {
298
- if (!currentTime || word.start_time === null || word.end_time === null) return false
299
- return currentTime >= word.start_time && currentTime <= word.end_time
300
- }
301
-
302
- const handleTimelineClick = (e: React.MouseEvent) => {
303
- const rect = containerRef.current?.getBoundingClientRect()
304
- if (!rect || !onPlaySegment) return
305
-
306
- const x = e.clientX - rect.left
307
- const clickedPosition = (x / rect.width) * (endTime - startTime) + startTime
308
-
309
- console.log('Timeline clicked:', {
310
- x,
311
- width: rect.width,
312
- clickedTime: clickedPosition
313
- })
314
-
315
- onPlaySegment(clickedPosition)
316
- }
317
-
318
- return (
319
- <TimelineContainer
320
- ref={containerRef}
321
- onMouseMove={handleMouseMove}
322
- onMouseUp={handleMouseUp}
323
- onMouseLeave={handleMouseUp}
324
- >
325
- <TimelineRuler onClick={handleTimelineClick}>
326
- {generateTimelineMarks()}
327
- </TimelineRuler>
328
-
329
- {/* Add cursor line */}
330
- {showPlaybackIndicator && (
331
- <TimelineCursor
332
- sx={{
333
- left: `${timeToPosition(currentTime)}%`,
334
- display: currentTime >= startTime && currentTime <= endTime ? 'block' : 'none'
335
- }}
336
- />
337
- )}
338
-
339
- {words.map((word, index) => {
340
- // Only render synced words on the timeline
341
- if (word.start_time === null || word.end_time === null) return null;
342
-
343
- const leftPosition = timeToPosition(word.start_time)
344
- const rightPosition = timeToPosition(word.end_time)
345
- const width = rightPosition - leftPosition
346
- const adjustedWidth = width
347
-
348
- return (
349
- <TimelineWord
350
- key={index}
351
- className={isWordHighlighted(word) ? 'highlighted' : ''}
352
- sx={{
353
- left: `${leftPosition}%`,
354
- width: `${adjustedWidth}%`,
355
- maxWidth: `calc(${100 - leftPosition}%)`,
356
- }}
357
- onMouseDown={(e) => {
358
- e.stopPropagation()
359
- handleMouseDown(e, index, 'move')
360
- }}
361
- onContextMenu={(e) => handleContextMenu(e, index)}
362
- >
363
- <ResizeHandle
364
- className="left"
365
- onMouseDown={(e) => {
366
- e.stopPropagation()
367
- handleMouseDown(e, index, 'resize-left')
368
- }}
369
- />
370
- {word.text}
371
- <ResizeHandle
372
- className="right"
373
- onMouseDown={(e) => {
374
- e.stopPropagation()
375
- handleMouseDown(e, index, 'resize-right')
376
- }}
377
- />
378
- </TimelineWord>
379
- )
380
- })}
381
- </TimelineContainer>
382
- )
383
- }
@@ -1,131 +0,0 @@
1
- import {
2
- Dialog,
3
- DialogTitle,
4
- DialogContent,
5
- DialogActions,
6
- Button,
7
- TextField,
8
- Box,
9
- Typography,
10
- ButtonGroup,
11
- IconButton,
12
- } from '@mui/material';
13
- import CloseIcon from '@mui/icons-material/Close';
14
- import { useState, useEffect } from 'react';
15
-
16
- interface TimingOffsetModalProps {
17
- open: boolean;
18
- onClose: () => void;
19
- currentOffset: number;
20
- onApply: (offsetMs: number) => void;
21
- }
22
-
23
- export default function TimingOffsetModal({
24
- open,
25
- onClose,
26
- currentOffset,
27
- onApply,
28
- }: TimingOffsetModalProps) {
29
- const [offsetMs, setOffsetMs] = useState(currentOffset);
30
-
31
- // Reset the offset value when the modal opens
32
- useEffect(() => {
33
- if (open) {
34
- setOffsetMs(currentOffset);
35
- }
36
- }, [open, currentOffset]);
37
-
38
- // Handle preset buttons click
39
- const handlePresetClick = (value: number) => {
40
- setOffsetMs((prev) => prev + value);
41
- };
42
-
43
- // Handle direct input change
44
- const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
45
- const value = e.target.value === '' ? 0 : parseInt(e.target.value, 10);
46
- if (!isNaN(value)) {
47
- setOffsetMs(value);
48
- }
49
- };
50
-
51
- // Apply the offset
52
- const handleApply = () => {
53
- onApply(offsetMs);
54
- onClose();
55
- };
56
-
57
- return (
58
- <Dialog
59
- open={open}
60
- onClose={onClose}
61
- maxWidth="sm"
62
- fullWidth
63
- PaperProps={{
64
- sx: {
65
- overflowY: 'visible',
66
- }
67
- }}
68
- >
69
- <DialogTitle sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
70
- Adjust Global Timing Offset
71
- <IconButton onClick={onClose} size="small">
72
- <CloseIcon />
73
- </IconButton>
74
- </DialogTitle>
75
- <DialogContent>
76
- <Box sx={{ mb: 3, mt: 1 }}>
77
- <Typography variant="body2" sx={{ mb: 1 }}>
78
- Adjust the timing of all words in the transcription. Positive values delay the timing, negative values advance it.
79
- </Typography>
80
-
81
- <Typography variant="body2" sx={{ fontStyle: 'italic', mb: 2 }}>
82
- Note: This offset is applied globally but doesn't modify the original timestamps.
83
- </Typography>
84
-
85
- <Box sx={{ display: 'flex', alignItems: 'center', mb: 2 }}>
86
- <Typography variant="body1" sx={{ mr: 2 }}>
87
- Offset:
88
- </Typography>
89
- <TextField
90
- value={offsetMs}
91
- onChange={handleInputChange}
92
- type="number"
93
- variant="outlined"
94
- size="small"
95
- InputProps={{
96
- endAdornment: <Typography variant="body2" sx={{ ml: 1 }}>ms</Typography>,
97
- }}
98
- sx={{ width: 120 }}
99
- />
100
- </Box>
101
-
102
- <Box sx={{ display: 'flex', flexDirection: 'column', gap: 1 }}>
103
- <Typography variant="body2">Quick adjust:</Typography>
104
- <Box sx={{ display: 'flex', justifyContent: 'center', gap: 1 }}>
105
- <ButtonGroup size="small">
106
- <Button onClick={() => handlePresetClick(-100)}>-100ms</Button>
107
- <Button onClick={() => handlePresetClick(-50)}>-50ms</Button>
108
- <Button onClick={() => handlePresetClick(-10)}>-10ms</Button>
109
- </ButtonGroup>
110
- <ButtonGroup size="small">
111
- <Button onClick={() => handlePresetClick(10)}>+10ms</Button>
112
- <Button onClick={() => handlePresetClick(50)}>+50ms</Button>
113
- <Button onClick={() => handlePresetClick(100)}>+100ms</Button>
114
- </ButtonGroup>
115
- </Box>
116
- </Box>
117
- </Box>
118
- </DialogContent>
119
- <DialogActions>
120
- <Button onClick={onClose}>Cancel</Button>
121
- <Button
122
- onClick={handleApply}
123
- variant="contained"
124
- color="primary"
125
- >
126
- {offsetMs === 0 ? "Remove Offset" : "Apply Offset"}
127
- </Button>
128
- </DialogActions>
129
- </Dialog>
130
- );
131
- }