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,48 +0,0 @@
1
- {
2
- "name": "lyrics-transcriber-frontend",
3
- "private": true,
4
- "homepage": "https://nomadkaraoke.github.io/lyrics-transcriber-frontend",
5
- "version": "0.86.0",
6
- "type": "module",
7
- "scripts": {
8
- "dev": "vite",
9
- "build": "tsc -b && vite build --mode development",
10
- "build-prod": "tsc -b && vite build",
11
- "lint": "eslint .",
12
- "preview": "vite preview",
13
- "predeploy": "npm run build-prod",
14
- "deploy": "gh-pages -d dist",
15
- "test": "playwright test",
16
- "test:ui": "playwright test --ui",
17
- "test:headed": "playwright test --headed"
18
- },
19
- "dependencies": {
20
- "@emotion/react": "^11.14.0",
21
- "@emotion/styled": "^11.14.0",
22
- "@mui/icons-material": "^6.3.0",
23
- "@mui/material": "^6.3.0",
24
- "@mui/system": "^6.4.3",
25
- "lucide-react": "^0.562.0",
26
- "nanoid": "^5.0.9",
27
- "react": "^18.3.1",
28
- "react-dom": "^18.3.1",
29
- "zod": "^3.24.1"
30
- },
31
- "devDependencies": {
32
- "@eslint/js": "^9.17.0",
33
- "@playwright/test": "^1.57.0",
34
- "@types/react": "^18.3.18",
35
- "@types/react-dom": "^18.3.5",
36
- "@vitejs/plugin-react": "^4.3.4",
37
- "eslint": "^9.17.0",
38
- "eslint-plugin-react-hooks": "^5.0.0",
39
- "eslint-plugin-react-refresh": "^0.4.16",
40
- "gh-pages": "^6.3.0",
41
- "globals": "^15.14.0",
42
- "playwright": "^1.57.0",
43
- "typescript": "~5.6.2",
44
- "typescript-eslint": "^8.18.2",
45
- "vite": "^6.0.5"
46
- },
47
- "packageManager": "yarn@4.7.0"
48
- }
@@ -1,69 +0,0 @@
1
- import { defineConfig, devices } from '@playwright/test';
2
-
3
- /**
4
- * Playwright configuration for lyrics-transcriber frontend E2E tests.
5
- * Tests run against the local dev server (localhost:5173) served by vite.
6
- */
7
- export default defineConfig({
8
- testDir: './e2e',
9
-
10
- // Run tests sequentially for now
11
- fullyParallel: false,
12
-
13
- // Fail the build on CI if you accidentally left test.only in the source code
14
- forbidOnly: !!process.env.CI,
15
-
16
- // Retry on CI only
17
- retries: process.env.CI ? 2 : 0,
18
-
19
- // Single worker
20
- workers: 1,
21
-
22
- // Reporter to use
23
- reporter: [
24
- ['html', { open: 'never' }],
25
- ['list'],
26
- ],
27
-
28
- // Shared settings for all tests
29
- use: {
30
- // Base URL for the local dev server
31
- baseURL: 'http://localhost:5173',
32
-
33
- // Collect trace on failure for debugging
34
- trace: 'on-first-retry',
35
-
36
- // Screenshot on failure
37
- screenshot: 'only-on-failure',
38
-
39
- // Video on failure
40
- video: 'on-first-retry',
41
-
42
- // Increase timeout for complex interactions
43
- actionTimeout: 30000,
44
- },
45
-
46
- // Longer timeout for tests
47
- timeout: 120000, // 2 minutes per test
48
-
49
- // Expect timeout for assertions
50
- expect: {
51
- timeout: 30000, // 30 seconds for expects
52
- },
53
-
54
- // Configure projects (browsers)
55
- projects: [
56
- {
57
- name: 'chromium',
58
- use: { ...devices['Desktop Chrome'] },
59
- },
60
- ],
61
-
62
- // Run local dev server before starting tests
63
- webServer: {
64
- command: 'npm run dev',
65
- url: 'http://localhost:5173',
66
- reuseExistingServer: !process.env.CI,
67
- timeout: 120000,
68
- },
69
- });
@@ -1,243 +0,0 @@
1
- import UploadFileIcon from '@mui/icons-material/UploadFile'
2
- import { Alert, Box, Button, Modal, Typography } from '@mui/material'
3
- import { ThemeProvider } from '@mui/material/styles'
4
- import CssBaseline from '@mui/material/CssBaseline'
5
- import { useEffect, useState, useMemo } from 'react'
6
- import { ApiClient, FileOnlyClient, LiveApiClient } from './api'
7
- import CorrectionMetrics from './components/CorrectionMetrics'
8
- import LyricsAnalyzer from './components/LyricsAnalyzer'
9
- import AppHeader from './components/AppHeader'
10
- import { CorrectionData } from './types'
11
- import { createAppTheme } from './theme'
12
-
13
- const THEME_STORAGE_KEY = 'nomad-karaoke-lyrics-theme'
14
-
15
- export default function App() {
16
- const [isDarkMode, setIsDarkMode] = useState(() => {
17
- // Initialize from localStorage
18
- const stored = localStorage.getItem(THEME_STORAGE_KEY)
19
- return stored !== 'light' // Default to dark
20
- })
21
- const [data, setData] = useState<CorrectionData | null>(null)
22
- const [showMetadata, setShowMetadata] = useState(false)
23
- const [error, setError] = useState<string | null>(null)
24
- const [apiClient, setApiClient] = useState<ApiClient | null>(null)
25
- const [isReadOnly, setIsReadOnly] = useState(true)
26
- const [audioHash, setAudioHash] = useState<string>('')
27
-
28
- // Create theme based on mode
29
- const theme = useMemo(() => createAppTheme(isDarkMode ? 'dark' : 'light'), [isDarkMode])
30
-
31
- // Handle theme toggle
32
- const handleToggleTheme = () => {
33
- const newIsDark = !isDarkMode
34
- setIsDarkMode(newIsDark)
35
- localStorage.setItem(THEME_STORAGE_KEY, newIsDark ? 'dark' : 'light')
36
- }
37
-
38
- useEffect(() => {
39
- // Parse query parameters
40
- const params = new URLSearchParams(window.location.search)
41
- const encodedApiUrl = params.get('baseApiUrl')
42
- const audioHashParam = params.get('audioHash')
43
- const reviewTokenParam = params.get('reviewToken')
44
-
45
- if (encodedApiUrl) {
46
- const baseApiUrl = decodeURIComponent(encodedApiUrl)
47
- // Pass reviewToken to LiveApiClient for authentication
48
- setApiClient(new LiveApiClient(baseApiUrl, reviewTokenParam || undefined))
49
- setIsReadOnly(false)
50
- if (audioHashParam) {
51
- setAudioHash(audioHashParam)
52
- }
53
- // Fetch initial data
54
- fetchData(baseApiUrl, reviewTokenParam || undefined)
55
- } else {
56
- setApiClient(new FileOnlyClient())
57
- setIsReadOnly(true)
58
- }
59
- }, [])
60
-
61
- const fetchData = async (baseUrl: string, reviewToken?: string) => {
62
- try {
63
- const client = new LiveApiClient(baseUrl, reviewToken)
64
- const data = await client.getCorrectionData()
65
- // console.log('Full correction data from API:', data)
66
- setData(data)
67
- } catch (err) {
68
- const error = err as Error
69
- setError(`Failed to fetch data: ${error.message}`)
70
- }
71
- }
72
-
73
- const handleFileLoad = async () => {
74
- const input = document.createElement('input')
75
- input.type = 'file'
76
- input.accept = '.json'
77
-
78
- input.onchange = async (e) => {
79
- const file = (e.target as HTMLInputElement).files?.[0]
80
- if (!file) return
81
-
82
- try {
83
- const text = await file.text()
84
- const parsedData = JSON.parse(text) as CorrectionData
85
- console.log('File data loaded:', {
86
- sampleGap: parsedData.gap_sequences?.[0],
87
- sampleWord: parsedData.corrected_segments?.[0]?.words?.[0],
88
- sampleCorrection: parsedData.corrections?.[0]
89
- })
90
-
91
- // Validate the structure
92
- if (!parsedData.corrected_segments || !parsedData.gap_sequences) {
93
- throw new Error('Invalid file format: missing required fields')
94
- }
95
-
96
- setData(parsedData)
97
- } catch (err) {
98
- const error = err as Error
99
- setError(`Error loading file: ${error.message}. Please make sure it is a valid JSON file.`)
100
- }
101
- }
102
-
103
- input.click()
104
- }
105
-
106
- const renderMetadataModal = () => {
107
- if (!data) return null
108
-
109
- return (
110
- <Modal
111
- open={showMetadata}
112
- onClose={() => setShowMetadata(false)}
113
- aria-labelledby="metadata-modal"
114
- >
115
- <Box sx={{
116
- position: 'absolute',
117
- top: '50%',
118
- left: '50%',
119
- transform: 'translate(-50%, -50%)',
120
- width: 400,
121
- bgcolor: 'background.paper',
122
- boxShadow: 24,
123
- p: 4,
124
- borderRadius: 1,
125
- }}>
126
- <Typography variant="h6" gutterBottom>
127
- Correction Process Details
128
- </Typography>
129
- <Box sx={{ mb: 2 }}>
130
- <Typography variant="subtitle2" color="text.secondary">
131
- Total Words
132
- </Typography>
133
- <Typography>
134
- {data.metadata.total_words}
135
- </Typography>
136
- </Box>
137
- <Box sx={{ mb: 2 }}>
138
- <Typography variant="subtitle2" color="text.secondary">
139
- Gap Sequences
140
- </Typography>
141
- <Typography>
142
- {data.metadata.gap_sequences_count}
143
- </Typography>
144
- </Box>
145
- <Box sx={{ mb: 2 }}>
146
- <Typography variant="subtitle2" color="text.secondary">
147
- Corrections Made
148
- </Typography>
149
- <Typography>
150
- {data.corrections_made}
151
- </Typography>
152
- </Box>
153
- <Box sx={{ mb: 2 }}>
154
- <Typography variant="subtitle2" color="text.secondary">
155
- Correction Ratio
156
- </Typography>
157
- <Typography>
158
- {(data.metadata.correction_ratio * 100).toFixed(1)}%
159
- </Typography>
160
- </Box>
161
- {/* Add any other metadata fields that are available */}
162
- </Box>
163
- </Modal>
164
- )
165
- }
166
-
167
- if (!data) {
168
- return (
169
- <ThemeProvider theme={theme}>
170
- <CssBaseline />
171
- <AppHeader isDarkMode={isDarkMode} onToggleTheme={handleToggleTheme} />
172
- <Box sx={{ p: 3 }}>
173
- {error && (
174
- <Alert severity="error" sx={{ mb: 2 }} onClose={() => setError(null)}>
175
- {error}
176
- </Alert>
177
- )}
178
- {isReadOnly ? (
179
- <>
180
- <Alert severity="info" sx={{ mb: 2 }}>
181
- Running in read-only mode. Connect to an API to enable editing.
182
- </Alert>
183
- <Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 3 }}>
184
- <Typography variant="h4">
185
- Lyrics Correction Review
186
- </Typography>
187
- <Button
188
- variant="outlined"
189
- startIcon={<UploadFileIcon />}
190
- onClick={handleFileLoad}
191
- >
192
- Load File
193
- </Button>
194
- </Box>
195
- <Box sx={{ mb: 3 }}>
196
- <CorrectionMetrics />
197
- </Box>
198
- </>
199
- ) : (
200
- <Box sx={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '50vh' }}>
201
- <Typography variant="h6" color="text.secondary">
202
- Loading Lyrics Transcription Review...
203
- </Typography>
204
- </Box>
205
- )}
206
- </Box>
207
- </ThemeProvider>
208
- )
209
- }
210
-
211
- return (
212
- <ThemeProvider theme={theme}>
213
- <CssBaseline />
214
- <AppHeader isDarkMode={isDarkMode} onToggleTheme={handleToggleTheme} />
215
- <Box sx={{
216
- p: 1.5,
217
- pb: 3,
218
- maxWidth: '100%',
219
- overflowX: 'hidden'
220
- }}>
221
- {error && (
222
- <Alert severity="error" sx={{ mb: 1 }} onClose={() => setError(null)}>
223
- {error}
224
- </Alert>
225
- )}
226
- {isReadOnly && (
227
- <Alert severity="info" sx={{ mb: 1 }}>
228
- Running in read-only mode. Connect to an API to enable editing.
229
- </Alert>
230
- )}
231
- <LyricsAnalyzer
232
- data={data}
233
- onFileLoad={handleFileLoad}
234
- onShowMetadata={() => setShowMetadata(true)}
235
- apiClient={apiClient}
236
- isReadOnly={isReadOnly}
237
- audioHash={audioHash}
238
- />
239
- {renderMetadataModal()}
240
- </Box>
241
- </ThemeProvider>
242
- )
243
- }
@@ -1,262 +0,0 @@
1
- import { CorrectionData, CorrectionAnnotation } from './types';
2
- import { validateCorrectionData } from './validation';
3
-
4
- // New file to handle API communication
5
- export interface ApiClient {
6
- getCorrectionData: () => Promise<CorrectionData>;
7
- submitCorrections: (data: CorrectionData) => Promise<void>;
8
- getAudioUrl: (audioHash: string) => string;
9
- generatePreviewVideo: (data: CorrectionData, options?: PreviewOptions) => Promise<PreviewVideoResponse>;
10
- getPreviewVideoUrl: (previewHash: string) => string;
11
- updateHandlers: (enabledHandlers: string[]) => Promise<CorrectionData>;
12
- isUpdatingHandlers?: boolean;
13
- addLyrics: (source: string, lyrics: string) => Promise<CorrectionData>;
14
- submitAnnotations: (annotations: Omit<CorrectionAnnotation, 'annotation_id' | 'timestamp'>[]) => Promise<void>;
15
- getAnnotationStats: () => Promise<any>;
16
- }
17
-
18
- // Add new interface for the minimal update payload
19
- interface CorrectionUpdate {
20
- corrections: CorrectionData['corrections'];
21
- corrected_segments: CorrectionData['corrected_segments'];
22
- }
23
-
24
- // Add interface for preview generation options
25
- export interface PreviewOptions {
26
- use_background_image?: boolean;
27
- }
28
-
29
- // Add new interface for preview response
30
- interface PreviewVideoResponse {
31
- status: "success" | "error";
32
- preview_hash?: string;
33
- message?: string;
34
- }
35
-
36
- // Add new interface for adding lyrics
37
- interface AddLyricsRequest {
38
- source: string;
39
- lyrics: string;
40
- }
41
-
42
- export class LiveApiClient implements ApiClient {
43
- private reviewToken?: string;
44
-
45
- constructor(private baseUrl: string, reviewToken?: string) {
46
- this.baseUrl = baseUrl.replace(/\/$/, '')
47
- this.reviewToken = reviewToken
48
- }
49
-
50
- public isUpdatingHandlers = false;
51
-
52
- /**
53
- * Build URL with reviewToken query parameter if available
54
- */
55
- private buildUrl(path: string): string {
56
- const url = `${this.baseUrl}${path}`
57
- if (this.reviewToken) {
58
- const separator = url.includes('?') ? '&' : '?'
59
- return `${url}${separator}review_token=${encodeURIComponent(this.reviewToken)}`
60
- }
61
- return url
62
- }
63
-
64
- async getCorrectionData(): Promise<CorrectionData> {
65
- const response = await fetch(this.buildUrl('/correction-data'));
66
- if (!response.ok) {
67
- throw new Error(`API error: ${response.statusText}`);
68
- }
69
- const rawData = await response.json();
70
-
71
- try {
72
- // This will throw if validation fails
73
- return validateCorrectionData(rawData);
74
- } catch (error) {
75
- console.error('Data validation failed:', error);
76
- throw new Error('Invalid data received from server: missing or incorrect fields');
77
- }
78
- }
79
-
80
- async submitCorrections(data: CorrectionData): Promise<void> {
81
- // Extract only the needed fields
82
- const updatePayload: CorrectionUpdate = {
83
- corrections: data.corrections,
84
- corrected_segments: data.corrected_segments
85
- };
86
-
87
- const response = await fetch(this.buildUrl('/complete'), {
88
- method: 'POST',
89
- headers: {
90
- 'Content-Type': 'application/json',
91
- },
92
- body: JSON.stringify(updatePayload)
93
- });
94
-
95
- if (!response.ok) {
96
- throw new Error(`API error: ${response.statusText}`);
97
- }
98
- }
99
-
100
- getAudioUrl(audioHash: string): string {
101
- return this.buildUrl(`/audio/${audioHash}`)
102
- }
103
-
104
- async generatePreviewVideo(data: CorrectionData, options?: PreviewOptions): Promise<PreviewVideoResponse> {
105
- // Extract only the needed fields, just like in submitCorrections
106
- // Include use_background_image option (defaults to false for fast black background)
107
- const updatePayload = {
108
- corrections: data.corrections,
109
- corrected_segments: data.corrected_segments,
110
- use_background_image: options?.use_background_image ?? false,
111
- };
112
-
113
- const response = await fetch(this.buildUrl('/preview-video'), {
114
- method: 'POST',
115
- headers: {
116
- 'Content-Type': 'application/json',
117
- },
118
- body: JSON.stringify(updatePayload)
119
- });
120
-
121
- if (!response.ok) {
122
- return {
123
- status: 'error',
124
- message: `API error: ${response.statusText}`
125
- };
126
- }
127
-
128
- return await response.json();
129
- }
130
-
131
- getPreviewVideoUrl(previewHash: string): string {
132
- return this.buildUrl(`/preview-video/${previewHash}`);
133
- }
134
-
135
- async updateHandlers(enabledHandlers: string[]): Promise<CorrectionData> {
136
- console.log('API: Starting handler update...');
137
- this.isUpdatingHandlers = true;
138
- console.log('API: Set isUpdatingHandlers to', this.isUpdatingHandlers);
139
-
140
- try {
141
- const response = await fetch(this.buildUrl('/handlers'), {
142
- method: 'POST',
143
- headers: {
144
- 'Content-Type': 'application/json',
145
- },
146
- body: JSON.stringify(enabledHandlers)
147
- });
148
-
149
- if (!response.ok) {
150
- throw new Error(`API error: ${response.statusText}`);
151
- }
152
-
153
- const data = await response.json();
154
- if (data.status === 'error') {
155
- throw new Error(data.message || 'Failed to update handlers');
156
- }
157
-
158
- console.log('API: Handler update successful');
159
- return validateCorrectionData(data.data);
160
- } finally {
161
- this.isUpdatingHandlers = false;
162
- console.log('API: Set isUpdatingHandlers to', this.isUpdatingHandlers);
163
- }
164
- }
165
-
166
- async addLyrics(source: string, lyrics: string): Promise<CorrectionData> {
167
- const payload: AddLyricsRequest = {
168
- source,
169
- lyrics
170
- };
171
-
172
- const response = await fetch(this.buildUrl('/add-lyrics'), {
173
- method: 'POST',
174
- headers: {
175
- 'Content-Type': 'application/json',
176
- },
177
- body: JSON.stringify(payload)
178
- });
179
-
180
- if (!response.ok) {
181
- throw new Error(`API error: ${response.statusText}`);
182
- }
183
-
184
- const data = await response.json();
185
- if (data.status === 'error') {
186
- throw new Error(data.message || 'Failed to add lyrics');
187
- }
188
-
189
- return validateCorrectionData(data.data);
190
- }
191
-
192
- async submitAnnotations(annotations: Omit<CorrectionAnnotation, 'annotation_id' | 'timestamp'>[]): Promise<void> {
193
- // Submit each annotation to the backend
194
- for (const annotation of annotations) {
195
- const response = await fetch(this.buildUrl('/v1/annotations'), {
196
- method: 'POST',
197
- headers: {
198
- 'Content-Type': 'application/json',
199
- },
200
- body: JSON.stringify(annotation)
201
- });
202
-
203
- if (!response.ok) {
204
- console.error(`Failed to submit annotation:`, annotation);
205
- // Continue with other annotations even if one fails
206
- }
207
- }
208
- }
209
-
210
- async getAnnotationStats(): Promise<any> {
211
- const response = await fetch(this.buildUrl('/v1/annotations/stats'));
212
- if (!response.ok) {
213
- throw new Error(`API error: ${response.statusText}`);
214
- }
215
- return await response.json();
216
- }
217
- }
218
-
219
- export class FileOnlyClient implements ApiClient {
220
- async getCorrectionData(): Promise<CorrectionData> {
221
- throw new Error('Not supported in file-only mode');
222
- }
223
-
224
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
225
- async submitCorrections(_data: CorrectionData): Promise<void> {
226
- throw new Error('Not supported in file-only mode');
227
- }
228
-
229
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
230
- getAudioUrl(_audioHash: string): string {
231
- throw new Error('Not supported in file-only mode');
232
- }
233
-
234
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
235
- async generatePreviewVideo(_data: CorrectionData, _options?: PreviewOptions): Promise<PreviewVideoResponse> {
236
- throw new Error('Not supported in file-only mode');
237
- }
238
-
239
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
240
- getPreviewVideoUrl(_previewHash: string): string {
241
- throw new Error('Not supported in file-only mode');
242
- }
243
-
244
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
245
- async updateHandlers(_enabledHandlers: string[]): Promise<CorrectionData> {
246
- throw new Error('Not supported in file-only mode');
247
- }
248
-
249
- async addLyrics(): Promise<CorrectionData> {
250
- throw new Error('Not supported in file-only mode');
251
- }
252
-
253
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
254
- async submitAnnotations(_annotations: Omit<CorrectionAnnotation, 'annotation_id' | 'timestamp'>[]): Promise<void> {
255
- throw new Error('Not supported in file-only mode');
256
- }
257
-
258
- async getAnnotationStats(): Promise<any> {
259
- throw new Error('Not supported in file-only mode');
260
- }
261
- }
262
-