voxflow 1.15.0 → 1.15.2

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 (453) hide show
  1. package/README.md +34 -0
  2. package/bin/voxflow.js +27 -0
  3. package/dist/index.js +1 -1
  4. package/dist/remotion-bundle/02a2fb2eb80bc7bf.woff2 +0 -0
  5. package/dist/remotion-bundle/052ca5351e5e06ba.woff2 +0 -0
  6. package/dist/remotion-bundle/05853dd28f4019cb.woff2 +0 -0
  7. package/dist/remotion-bundle/072ead3737f7c0d0.woff2 +0 -0
  8. package/dist/remotion-bundle/07d4248613c86a2e.woff2 +0 -0
  9. package/dist/remotion-bundle/0884a5c2d1d2d99b.woff2 +0 -0
  10. package/dist/remotion-bundle/0b0e185b2752095e.woff2 +0 -0
  11. package/dist/remotion-bundle/0e66c11bde067d91.woff2 +0 -0
  12. package/dist/remotion-bundle/0f7794cfba2c5d21.woff2 +0 -0
  13. package/dist/remotion-bundle/0fdbae5a4365783a.woff2 +0 -0
  14. package/dist/remotion-bundle/112.bundle.js +11 -0
  15. package/dist/remotion-bundle/112.bundle.js.map +1 -0
  16. package/dist/remotion-bundle/113.bundle.js +11 -0
  17. package/dist/remotion-bundle/113.bundle.js.map +1 -0
  18. package/dist/remotion-bundle/119cae0c4c16f7ed.woff2 +0 -0
  19. package/dist/remotion-bundle/14725f649fd1e78c.woff2 +0 -0
  20. package/dist/remotion-bundle/14abe9e3f95f7888.woff2 +0 -0
  21. package/dist/remotion-bundle/163.bundle.js +14678 -0
  22. package/dist/remotion-bundle/163.bundle.js.map +1 -0
  23. package/dist/remotion-bundle/1808c54072bf6d14.woff2 +0 -0
  24. package/dist/remotion-bundle/18948bec3e3012fe.woff2 +0 -0
  25. package/dist/remotion-bundle/1a661c60d0fc84fc.woff2 +0 -0
  26. package/dist/remotion-bundle/1af94941e1bc7e1e.woff2 +0 -0
  27. package/dist/remotion-bundle/1bee0219595f606c.woff2 +0 -0
  28. package/dist/remotion-bundle/1bfd5da7ce9d4ec4.woff2 +0 -0
  29. package/dist/remotion-bundle/1c158d56f1884f3f.woff2 +0 -0
  30. package/dist/remotion-bundle/1cf5e88e667610eb.woff2 +0 -0
  31. package/dist/remotion-bundle/1d431bd10f53c481.woff2 +0 -0
  32. package/dist/remotion-bundle/1d701a81a7670db2.woff2 +0 -0
  33. package/dist/remotion-bundle/1da0fecad4240f16.woff2 +0 -0
  34. package/dist/remotion-bundle/1ed14d3d0c5c63fe.woff2 +0 -0
  35. package/dist/remotion-bundle/1edfecf40e586f53.woff2 +0 -0
  36. package/dist/remotion-bundle/1f479711bc34b054.woff +0 -0
  37. package/dist/remotion-bundle/1f86e54a0ff5fcd1.woff2 +0 -0
  38. package/dist/remotion-bundle/2043ea87d9aabd11.woff2 +0 -0
  39. package/dist/remotion-bundle/20563c39ee8a0e40.woff2 +0 -0
  40. package/dist/remotion-bundle/20c231590fd12c44.woff2 +0 -0
  41. package/dist/remotion-bundle/20ce61713f754c07.woff2 +0 -0
  42. package/dist/remotion-bundle/21eb9306fce24bb1.woff2 +0 -0
  43. package/dist/remotion-bundle/244bf71c0cc851af.woff2 +0 -0
  44. package/dist/remotion-bundle/274d4cfc02bffbcb.woff2 +0 -0
  45. package/dist/remotion-bundle/275.bundle.js +21 -0
  46. package/dist/remotion-bundle/275.bundle.js.map +1 -0
  47. package/dist/remotion-bundle/2958f540b39513dc.woff2 +0 -0
  48. package/dist/remotion-bundle/2a168b98fd97722e.woff2 +0 -0
  49. package/dist/remotion-bundle/2d1f6373937ab55f.woff2 +0 -0
  50. package/dist/remotion-bundle/2d213ae47ff6daa9.woff2 +0 -0
  51. package/dist/remotion-bundle/2e4b1f04fcd05047.woff2 +0 -0
  52. package/dist/remotion-bundle/304170d98f4c4563.woff2 +0 -0
  53. package/dist/remotion-bundle/30d02e136e7a5642.woff2 +0 -0
  54. package/dist/remotion-bundle/3135562b52a714cd.woff2 +0 -0
  55. package/dist/remotion-bundle/313713af2c8144e9.woff2 +0 -0
  56. package/dist/remotion-bundle/325fa4108d2285b9.woff2 +0 -0
  57. package/dist/remotion-bundle/338e927ed3345e0c.woff2 +0 -0
  58. package/dist/remotion-bundle/35fc6b190365bc17.woff2 +0 -0
  59. package/dist/remotion-bundle/37a51f1122d4efc5.woff2 +0 -0
  60. package/dist/remotion-bundle/39a4d63e02736f5e.woff2 +0 -0
  61. package/dist/remotion-bundle/3a00e0d62dfc4171.woff2 +0 -0
  62. package/dist/remotion-bundle/3a6955e6561affe1.woff2 +0 -0
  63. package/dist/remotion-bundle/3c573945aef49b89.woff2 +0 -0
  64. package/dist/remotion-bundle/3cdbfbfa23b516a5.woff2 +0 -0
  65. package/dist/remotion-bundle/3e42f85a9e64ca8a.woff2 +0 -0
  66. package/dist/remotion-bundle/3e83eaf1ec859415.woff2 +0 -0
  67. package/dist/remotion-bundle/3f3c8c90de1250ee.woff2 +0 -0
  68. package/dist/remotion-bundle/434.bundle.js +205 -0
  69. package/dist/remotion-bundle/434.bundle.js.map +1 -0
  70. package/dist/remotion-bundle/44ffc6ca4d781692.woff2 +0 -0
  71. package/dist/remotion-bundle/4670d9c4580b09eb.woff2 +0 -0
  72. package/dist/remotion-bundle/479756881b302824.woff2 +0 -0
  73. package/dist/remotion-bundle/481b82134bfa9c82.woff2 +0 -0
  74. package/dist/remotion-bundle/48d27029626f4328.woff2 +0 -0
  75. package/dist/remotion-bundle/49b7b2a30329c511.woff2 +0 -0
  76. package/dist/remotion-bundle/4c8b25a1a9337045.woff2 +0 -0
  77. package/dist/remotion-bundle/4cba14788ca9259b.woff2 +0 -0
  78. package/dist/remotion-bundle/4cd6c589c004a6a7.woff2 +0 -0
  79. package/dist/remotion-bundle/4cd8d79c1021608d.woff2 +0 -0
  80. package/dist/remotion-bundle/4d8fa99b3f00f9f0.woff2 +0 -0
  81. package/dist/remotion-bundle/4e7805a643f86d53.woff2 +0 -0
  82. package/dist/remotion-bundle/4ff91be454542e3f.woff2 +0 -0
  83. package/dist/remotion-bundle/504cbcba1f63591b.woff2 +0 -0
  84. package/dist/remotion-bundle/5202d792e5791d6c.woff2 +0 -0
  85. package/dist/remotion-bundle/534db5ad4770cc1d.woff2 +0 -0
  86. package/dist/remotion-bundle/53b9568eb85f866b.woff2 +0 -0
  87. package/dist/remotion-bundle/543ad386ca171de9.woff2 +0 -0
  88. package/dist/remotion-bundle/54798e55bbf7976e.woff2 +0 -0
  89. package/dist/remotion-bundle/580.bundle.js +11 -0
  90. package/dist/remotion-bundle/580.bundle.js.map +1 -0
  91. package/dist/remotion-bundle/58d174d1193af6d1.woff2 +0 -0
  92. package/dist/remotion-bundle/591d29ff3ff53c80.woff2 +0 -0
  93. package/dist/remotion-bundle/5c28c4f4824383c6.woff2 +0 -0
  94. package/dist/remotion-bundle/5da9740d2ce894c8.woff2 +0 -0
  95. package/dist/remotion-bundle/6197735364642360.woff2 +0 -0
  96. package/dist/remotion-bundle/6265a4335724080f.woff2 +0 -0
  97. package/dist/remotion-bundle/633f5e4f6394daa7.woff2 +0 -0
  98. package/dist/remotion-bundle/637d95ace6a69c49.woff2 +0 -0
  99. package/dist/remotion-bundle/648e04a04dacff8f.woff2 +0 -0
  100. package/dist/remotion-bundle/64a6e83045a008b2.woff2 +0 -0
  101. package/dist/remotion-bundle/651.bundle.js +11 -0
  102. package/dist/remotion-bundle/651.bundle.js.map +1 -0
  103. package/dist/remotion-bundle/65e2a988c070facc.woff2 +0 -0
  104. package/dist/remotion-bundle/66a2f6ce5cc69105.woff2 +0 -0
  105. package/dist/remotion-bundle/690.bundle.js +3479 -0
  106. package/dist/remotion-bundle/690.bundle.js.map +1 -0
  107. package/dist/remotion-bundle/690ff55252ca715d.woff2 +0 -0
  108. package/dist/remotion-bundle/6a01a1cff49314fc.woff2 +0 -0
  109. package/dist/remotion-bundle/6cbc32670982986c.woff2 +0 -0
  110. package/dist/remotion-bundle/6d3cc42ae547f454.woff2 +0 -0
  111. package/dist/remotion-bundle/6d8f4cfa1ddc0830.woff2 +0 -0
  112. package/dist/remotion-bundle/6e4d7c6ae65e2dc3.woff2 +0 -0
  113. package/dist/remotion-bundle/6e86418bbcefb2e8.woff2 +0 -0
  114. package/dist/remotion-bundle/6ee02884b29cf7fb.woff2 +0 -0
  115. package/dist/remotion-bundle/6f436a74c9e3252c.woff2 +0 -0
  116. package/dist/remotion-bundle/78c8022f1657618b.woff2 +0 -0
  117. package/dist/remotion-bundle/7c5444169792bca4.woff2 +0 -0
  118. package/dist/remotion-bundle/7c86bddd9d997212.woff2 +0 -0
  119. package/dist/remotion-bundle/7e1284684767f584.woff2 +0 -0
  120. package/dist/remotion-bundle/7e81c17522d182b2.woff2 +0 -0
  121. package/dist/remotion-bundle/7eb87be198f7858c.woff2 +0 -0
  122. package/dist/remotion-bundle/8060c928f948aab5.woff2 +0 -0
  123. package/dist/remotion-bundle/80bc9dfbea2b35ae.woff2 +0 -0
  124. package/dist/remotion-bundle/811b83f69963bb48.woff2 +0 -0
  125. package/dist/remotion-bundle/813.bundle.js +117511 -0
  126. package/dist/remotion-bundle/813.bundle.js.map +1 -0
  127. package/dist/remotion-bundle/84df492e349f82e9.woff2 +0 -0
  128. package/dist/remotion-bundle/8501bfd73eb36f2b.woff2 +0 -0
  129. package/dist/remotion-bundle/854236a8376093fe.woff2 +0 -0
  130. package/dist/remotion-bundle/8571d74529082753.woff2 +0 -0
  131. package/dist/remotion-bundle/860bf44f8e6f4b5d.woff2 +0 -0
  132. package/dist/remotion-bundle/879.bundle.js +64 -0
  133. package/dist/remotion-bundle/879.bundle.js.map +1 -0
  134. package/dist/remotion-bundle/887dd482f848d56f.woff2 +0 -0
  135. package/dist/remotion-bundle/89b2132e85fbbb5a.woff2 +0 -0
  136. package/dist/remotion-bundle/8ba60d6c306010c2.woff2 +0 -0
  137. package/dist/remotion-bundle/8c7c4dadea897806.woff2 +0 -0
  138. package/dist/remotion-bundle/8c943f9999706f61.woff2 +0 -0
  139. package/dist/remotion-bundle/8f2a718c90575cc9.woff2 +0 -0
  140. package/dist/remotion-bundle/906b6edb3e1772c9.woff2 +0 -0
  141. package/dist/remotion-bundle/930ff9daccdf14eb.woff2 +0 -0
  142. package/dist/remotion-bundle/934db2f1c403c4d0.woff2 +0 -0
  143. package/dist/remotion-bundle/938.bundle.js +451 -0
  144. package/dist/remotion-bundle/938.bundle.js.map +1 -0
  145. package/dist/remotion-bundle/967.bundle.js +4462 -0
  146. package/dist/remotion-bundle/967.bundle.js.map +1 -0
  147. package/dist/remotion-bundle/9684a1093d3c02ce.woff2 +0 -0
  148. package/dist/remotion-bundle/973dcd0faa6116cc.woff2 +0 -0
  149. package/dist/remotion-bundle/9745400694e76cd8.woff2 +0 -0
  150. package/dist/remotion-bundle/999ef957bed3bdca.woff2 +0 -0
  151. package/dist/remotion-bundle/99a3d67c8b0f43e3.woff2 +0 -0
  152. package/dist/remotion-bundle/a0586c3e03127283.woff2 +0 -0
  153. package/dist/remotion-bundle/a0eb654fdae46269.woff2 +0 -0
  154. package/dist/remotion-bundle/a20e35d3b08f7994.woff2 +0 -0
  155. package/dist/remotion-bundle/a2dcaced7c8c25ab.woff2 +0 -0
  156. package/dist/remotion-bundle/a79255a972a2681a.woff2 +0 -0
  157. package/dist/remotion-bundle/a804b352cb9fec1a.woff2 +0 -0
  158. package/dist/remotion-bundle/aae7117164e1eabc.woff2 +0 -0
  159. package/dist/remotion-bundle/affd121385d0442d.woff2 +0 -0
  160. package/dist/remotion-bundle/b19a6083987ee0d7.woff2 +0 -0
  161. package/dist/remotion-bundle/b1b2bd04d8637981.woff2 +0 -0
  162. package/dist/remotion-bundle/b2c07f341486be87.woff2 +0 -0
  163. package/dist/remotion-bundle/b33d8f82e575c4ce.woff2 +0 -0
  164. package/dist/remotion-bundle/b366c0bed35ef491.woff2 +0 -0
  165. package/dist/remotion-bundle/b41e857ec1b85642.woff2 +0 -0
  166. package/dist/remotion-bundle/b420bb34ccf23e7f.woff2 +0 -0
  167. package/dist/remotion-bundle/b4f7bf4efb0c0ccf.woff2 +0 -0
  168. package/dist/remotion-bundle/b60fe5eca03cff93.woff2 +0 -0
  169. package/dist/remotion-bundle/b6bd31a336e64bce.woff2 +0 -0
  170. package/dist/remotion-bundle/b6d2befba3dfefeb.woff2 +0 -0
  171. package/dist/remotion-bundle/b75f39ab06c43bf4.woff2 +0 -0
  172. package/dist/remotion-bundle/b77880e8c413d4fd.woff2 +0 -0
  173. package/dist/remotion-bundle/b7e38ec441e4a77a.woff2 +0 -0
  174. package/dist/remotion-bundle/b83baa383ff0bf2b.woff2 +0 -0
  175. package/dist/remotion-bundle/b9ad7b6c0a11450a.woff2 +0 -0
  176. package/dist/remotion-bundle/baf84486e8ae3aaf.woff2 +0 -0
  177. package/dist/remotion-bundle/bc047b1f6869cffa.woff2 +0 -0
  178. package/dist/remotion-bundle/bf4f3ac6e93f33aa.woff2 +0 -0
  179. package/dist/remotion-bundle/bf6835ffec5897a2.woff2 +0 -0
  180. package/dist/remotion-bundle/bf8885f581eb1724.woff2 +0 -0
  181. package/dist/remotion-bundle/bundle.js +83376 -0
  182. package/dist/remotion-bundle/bundle.js.map +1 -0
  183. package/dist/remotion-bundle/c03f046bccd789d0.woff2 +0 -0
  184. package/dist/remotion-bundle/c0bb1f8962b73bc3.woff2 +0 -0
  185. package/dist/remotion-bundle/c1003f9a7db6e1cf.woff2 +0 -0
  186. package/dist/remotion-bundle/c15d83fb1e199515.woff2 +0 -0
  187. package/dist/remotion-bundle/c28e7e5d310f73ef.woff2 +0 -0
  188. package/dist/remotion-bundle/c2b840274db78aea.woff2 +0 -0
  189. package/dist/remotion-bundle/c3000e3299d4e45f.woff2 +0 -0
  190. package/dist/remotion-bundle/c83ce886e5288510.woff2 +0 -0
  191. package/dist/remotion-bundle/c87a5a64d4ac0918.woff2 +0 -0
  192. package/dist/remotion-bundle/c8a7e0d049e965fa.woff2 +0 -0
  193. package/dist/remotion-bundle/c949a35d3a3b1faf.woff2 +0 -0
  194. package/dist/remotion-bundle/c9618c9b9ac2bc78.woff2 +0 -0
  195. package/dist/remotion-bundle/ca3add3b84152d5b.woff2 +0 -0
  196. package/dist/remotion-bundle/cad9dd036408d707.woff2 +0 -0
  197. package/dist/remotion-bundle/cbb24916619df439.woff2 +0 -0
  198. package/dist/remotion-bundle/cc054f0b5514e177.woff2 +0 -0
  199. package/dist/remotion-bundle/ccc248ed9312bc71.woff2 +0 -0
  200. package/dist/remotion-bundle/cd9d623aa07af925.woff2 +0 -0
  201. package/dist/remotion-bundle/ce2ba7a321bd1247.woff2 +0 -0
  202. package/dist/remotion-bundle/cf72455f79a29b14.woff2 +0 -0
  203. package/dist/remotion-bundle/d267cbfefab452ac.woff2 +0 -0
  204. package/dist/remotion-bundle/d435cff46a64955f.woff +0 -0
  205. package/dist/remotion-bundle/d494d07f67e363f6.woff2 +0 -0
  206. package/dist/remotion-bundle/d7aa0cc1fa47bf38.woff2 +0 -0
  207. package/dist/remotion-bundle/d7c5ca93d885160a.woff2 +0 -0
  208. package/dist/remotion-bundle/d855d3e252db74e2.woff2 +0 -0
  209. package/dist/remotion-bundle/d8f13d47f02f82c2.woff2 +0 -0
  210. package/dist/remotion-bundle/d9567cce2ee11019.woff2 +0 -0
  211. package/dist/remotion-bundle/db8d4456fc75dd86.woff +0 -0
  212. package/dist/remotion-bundle/dc274628378c47ee.woff2 +0 -0
  213. package/dist/remotion-bundle/dc3e06947bb69903.woff2 +0 -0
  214. package/dist/remotion-bundle/dd67040ac3b6d523.woff2 +0 -0
  215. package/dist/remotion-bundle/e0b04bd488f953f4.woff2 +0 -0
  216. package/dist/remotion-bundle/e2a572ff95089370.woff2 +0 -0
  217. package/dist/remotion-bundle/e2e18a86b1c2b0cc.woff2 +0 -0
  218. package/dist/remotion-bundle/e3a78ee2fc9c6931.woff2 +0 -0
  219. package/dist/remotion-bundle/e654c9d547605a9f.woff2 +0 -0
  220. package/dist/remotion-bundle/e67a3a64c129927c.woff2 +0 -0
  221. package/dist/remotion-bundle/e6be28b4203cd6ce.woff2 +0 -0
  222. package/dist/remotion-bundle/e841907ad9b0a191.woff +0 -0
  223. package/dist/remotion-bundle/e889d1541c69fffa.woff2 +0 -0
  224. package/dist/remotion-bundle/e88ef8c76373a9e2.woff2 +0 -0
  225. package/dist/remotion-bundle/e9c72f4bc37defef.woff2 +0 -0
  226. package/dist/remotion-bundle/e9e35f863403a255.woff2 +0 -0
  227. package/dist/remotion-bundle/eb23b37b009375da.woff2 +0 -0
  228. package/dist/remotion-bundle/ee1342b741625721.woff2 +0 -0
  229. package/dist/remotion-bundle/f07da88543a57ec9.woff2 +0 -0
  230. package/dist/remotion-bundle/f522982115306f8a.woff2 +0 -0
  231. package/dist/remotion-bundle/f8449bd864e6d8bc.woff2 +0 -0
  232. package/dist/remotion-bundle/f906dd5bd95ff9ab.woff2 +0 -0
  233. package/dist/remotion-bundle/f9e9e9413e3c38bb.woff2 +0 -0
  234. package/dist/remotion-bundle/fa5a5b16280994a8.woff2 +0 -0
  235. package/dist/remotion-bundle/favicon.ico +0 -0
  236. package/dist/remotion-bundle/fb19c0517725599b.woff2 +0 -0
  237. package/dist/remotion-bundle/fcaf24232f684b9b.woff2 +0 -0
  238. package/dist/remotion-bundle/fe09e084a3eea8cf.woff2 +0 -0
  239. package/dist/remotion-bundle/ff38d5317df7345a.woff2 +0 -0
  240. package/dist/remotion-bundle/ffe7ea1ea08f455a.woff2 +0 -0
  241. package/dist/remotion-bundle/index.html +49 -0
  242. package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaomei/communication/0.mp3 +0 -0
  243. package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaomei/communication/1.mp3 +0 -0
  244. package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaomei/communication/2.mp3 +0 -0
  245. package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaomei/communication/3.mp3 +0 -0
  246. package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaoxin/career/0.mp3 +0 -0
  247. package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaoxin/career/1.mp3 +0 -0
  248. package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaoxin/career/2.mp3 +0 -0
  249. package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaoxin/career/3.mp3 +0 -0
  250. package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaoyue/parenting/0.mp3 +0 -0
  251. package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaoyue/parenting/1.mp3 +0 -0
  252. package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaoyue/parenting/2.mp3 +0 -0
  253. package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaoyue/parenting/3.mp3 +0 -0
  254. package/dist/remotion-bundle/public/paper-slide/male-kefu-xiaoxu/time-trap/0.mp3 +0 -0
  255. package/dist/remotion-bundle/public/paper-slide/male-kefu-xiaoxu/time-trap/1.mp3 +0 -0
  256. package/dist/remotion-bundle/public/paper-slide/male-kefu-xiaoxu/time-trap/2.mp3 +0 -0
  257. package/dist/remotion-bundle/public/paper-slide/male-kefu-xiaoxu/time-trap/3.mp3 +0 -0
  258. package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/cognition/0.mp3 +0 -0
  259. package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/cognition/1.mp3 +0 -0
  260. package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/cognition/2.mp3 +0 -0
  261. package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/cognition/3.mp3 +0 -0
  262. package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/growth/0.mp3 +0 -0
  263. package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/growth/1.mp3 +0 -0
  264. package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/growth/2.mp3 +0 -0
  265. package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/growth/3.mp3 +0 -0
  266. package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/parenting/0.mp3 +0 -0
  267. package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/parenting/1.mp3 +0 -0
  268. package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/parenting/2.mp3 +0 -0
  269. package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/parenting/3.mp3 +0 -0
  270. package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/soothing/0.mp3 +0 -0
  271. package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/soothing/1.mp3 +0 -0
  272. package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/soothing/2.mp3 +0 -0
  273. package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/soothing/3.mp3 +0 -0
  274. package/dist/remotion-bundle/public/paper-slide/v-female-R2s4N9qJ/cognition/0.mp3 +0 -0
  275. package/dist/remotion-bundle/public/paper-slide/v-female-R2s4N9qJ/cognition/1.mp3 +0 -0
  276. package/dist/remotion-bundle/public/paper-slide/v-female-R2s4N9qJ/cognition/2.mp3 +0 -0
  277. package/dist/remotion-bundle/public/paper-slide/v-female-R2s4N9qJ/cognition/3.mp3 +0 -0
  278. package/dist/remotion-bundle/public/paper-slide/v-male-Bk7vD3xP/decision/0.mp3 +0 -0
  279. package/dist/remotion-bundle/public/paper-slide/v-male-Bk7vD3xP/decision/1.mp3 +0 -0
  280. package/dist/remotion-bundle/public/paper-slide/v-male-Bk7vD3xP/decision/2.mp3 +0 -0
  281. package/dist/remotion-bundle/public/paper-slide/v-male-Bk7vD3xP/decision/3.mp3 +0 -0
  282. package/dist/remotion-bundle/public/paper-slide/v-male-W1tH9jVc/manager/0.mp3 +0 -0
  283. package/dist/remotion-bundle/public/paper-slide/v-male-W1tH9jVc/manager/1.mp3 +0 -0
  284. package/dist/remotion-bundle/public/paper-slide/v-male-W1tH9jVc/manager/2.mp3 +0 -0
  285. package/dist/remotion-bundle/public/paper-slide/v-male-W1tH9jVc/manager/3.mp3 +0 -0
  286. package/dist/remotion-bundle/public/paper-slide/v-male-W1tH9jVc/manager/4.mp3 +0 -0
  287. package/dist/remotion-bundle/public/paper-slide/v-male-s5NqE0rZ/founder/0.mp3 +0 -0
  288. package/dist/remotion-bundle/public/paper-slide/v-male-s5NqE0rZ/founder/1.mp3 +0 -0
  289. package/dist/remotion-bundle/public/paper-slide/v-male-s5NqE0rZ/founder/2.mp3 +0 -0
  290. package/dist/remotion-bundle/public/paper-slide/v-male-s5NqE0rZ/founder/3.mp3 +0 -0
  291. package/dist/remotion-bundle/public/paper-slide-experiments/career-advice/0.mp3 +0 -0
  292. package/dist/remotion-bundle/public/paper-slide-experiments/career-advice/1.mp3 +0 -0
  293. package/dist/remotion-bundle/public/paper-slide-experiments/career-advice/2.mp3 +0 -0
  294. package/dist/remotion-bundle/public/paper-slide-experiments/career-advice/3.mp3 +0 -0
  295. package/dist/remotion-bundle/public/paper-slide-experiments/career-advice/4.mp3 +0 -0
  296. package/dist/remotion-bundle/public/paper-slide-experiments/founder-lesson/0.mp3 +0 -0
  297. package/dist/remotion-bundle/public/paper-slide-experiments/founder-lesson/1.mp3 +0 -0
  298. package/dist/remotion-bundle/public/paper-slide-experiments/founder-lesson/2.mp3 +0 -0
  299. package/dist/remotion-bundle/public/paper-slide-experiments/founder-lesson/3.mp3 +0 -0
  300. package/dist/remotion-bundle/public/paper-slide-experiments/founder-lesson/4.mp3 +0 -0
  301. package/dist/remotion-bundle/public/paper-slide-experiments/incident-review/0.mp3 +0 -0
  302. package/dist/remotion-bundle/public/paper-slide-experiments/incident-review/1.mp3 +0 -0
  303. package/dist/remotion-bundle/public/paper-slide-experiments/incident-review/2.mp3 +0 -0
  304. package/dist/remotion-bundle/public/paper-slide-experiments/incident-review/3.mp3 +0 -0
  305. package/dist/remotion-bundle/public/paper-slide-experiments/incident-review/4.mp3 +0 -0
  306. package/dist/remotion-bundle/public/paper-slide-experiments/learning-loop/0.mp3 +0 -0
  307. package/dist/remotion-bundle/public/paper-slide-experiments/learning-loop/1.mp3 +0 -0
  308. package/dist/remotion-bundle/public/paper-slide-experiments/learning-loop/2.mp3 +0 -0
  309. package/dist/remotion-bundle/public/paper-slide-experiments/learning-loop/3.mp3 +0 -0
  310. package/dist/remotion-bundle/public/paper-slide-experiments/learning-loop/4.mp3 +0 -0
  311. package/dist/remotion-bundle/public/paper-slide-experiments/meeting-closure/0.mp3 +0 -0
  312. package/dist/remotion-bundle/public/paper-slide-experiments/meeting-closure/1.mp3 +0 -0
  313. package/dist/remotion-bundle/public/paper-slide-experiments/meeting-closure/2.mp3 +0 -0
  314. package/dist/remotion-bundle/public/paper-slide-experiments/meeting-closure/3.mp3 +0 -0
  315. package/dist/remotion-bundle/public/paper-slide-experiments/product-update/0.mp3 +0 -0
  316. package/dist/remotion-bundle/public/paper-slide-experiments/product-update/1.mp3 +0 -0
  317. package/dist/remotion-bundle/public/paper-slide-experiments/product-update/2.mp3 +0 -0
  318. package/dist/remotion-bundle/public/paper-slide-experiments/product-update/3.mp3 +0 -0
  319. package/dist/remotion-bundle/public/paper-slide-experiments/research-reading/0.mp3 +0 -0
  320. package/dist/remotion-bundle/public/paper-slide-experiments/research-reading/1.mp3 +0 -0
  321. package/dist/remotion-bundle/public/paper-slide-experiments/research-reading/2.mp3 +0 -0
  322. package/dist/remotion-bundle/public/paper-slide-experiments/research-reading/3.mp3 +0 -0
  323. package/dist/remotion-bundle/public/paper-slide-experiments/sales-enablement/0.mp3 +0 -0
  324. package/dist/remotion-bundle/public/paper-slide-experiments/sales-enablement/1.mp3 +0 -0
  325. package/dist/remotion-bundle/public/paper-slide-experiments/sales-enablement/2.mp3 +0 -0
  326. package/dist/remotion-bundle/public/paper-slide-experiments/sales-enablement/3.mp3 +0 -0
  327. package/dist/remotion-bundle/public/paper-slide-experiments/sales-enablement/4.mp3 +0 -0
  328. package/dist/remotion-bundle/public/voiceover/ai-life/card-0.mp3 +0 -0
  329. package/dist/remotion-bundle/public/voiceover/ai-life/card-1.mp3 +0 -0
  330. package/dist/remotion-bundle/public/voiceover/ai-life/card-2.mp3 +0 -0
  331. package/dist/remotion-bundle/public/voiceover/ai-life/card-3.mp3 +0 -0
  332. package/dist/remotion-bundle/public/voiceover/ai-life/card-4.mp3 +0 -0
  333. package/dist/remotion-bundle/public/voiceover/ai-life/card-5.mp3 +0 -0
  334. package/dist/remotion-bundle/public/voiceover/coffee-science/card-0.mp3 +0 -0
  335. package/dist/remotion-bundle/public/voiceover/coffee-science/card-1.mp3 +0 -0
  336. package/dist/remotion-bundle/public/voiceover/coffee-science/card-2.mp3 +0 -0
  337. package/dist/remotion-bundle/public/voiceover/coffee-science/card-3.mp3 +0 -0
  338. package/dist/remotion-bundle/public/voiceover/coffee-science/card-4.mp3 +0 -0
  339. package/dist/remotion-bundle/public/voiceover/coffee-science/card-5.mp3 +0 -0
  340. package/dist/remotion-bundle/public/voiceover/coffee-science/card-6.mp3 +0 -0
  341. package/dist/remotion-bundle/public/voiceover/reading-secrets/card-0.mp3 +0 -0
  342. package/dist/remotion-bundle/public/voiceover/reading-secrets/card-1.mp3 +0 -0
  343. package/dist/remotion-bundle/public/voiceover/reading-secrets/card-2.mp3 +0 -0
  344. package/dist/remotion-bundle/public/voiceover/reading-secrets/card-3.mp3 +0 -0
  345. package/dist/remotion-bundle/public/voiceover/reading-secrets/card-4.mp3 +0 -0
  346. package/dist/remotion-bundle/public/voiceover/reading-secrets/card-5.mp3 +0 -0
  347. package/dist/remotion-bundle/public/voiceover/reading-secrets/card-6.mp3 +0 -0
  348. package/dist/remotion-bundle/public/voiceover/remote-work/card-0.mp3 +0 -0
  349. package/dist/remotion-bundle/public/voiceover/remote-work/card-1.mp3 +0 -0
  350. package/dist/remotion-bundle/public/voiceover/remote-work/card-2.mp3 +0 -0
  351. package/dist/remotion-bundle/public/voiceover/remote-work/card-3.mp3 +0 -0
  352. package/dist/remotion-bundle/public/voiceover/remote-work/card-4.mp3 +0 -0
  353. package/dist/remotion-bundle/public/voiceover/remote-work/card-5.mp3 +0 -0
  354. package/dist/remotion-bundle/source-map-helper.wasm +0 -0
  355. package/lib/cli.js +270 -0
  356. package/lib/commands/_registry.js +48 -0
  357. package/lib/commands/add.js +242 -0
  358. package/lib/commands/asr/azure-transcribe.js +336 -0
  359. package/lib/commands/asr/cloud-transcribe.js +384 -0
  360. package/lib/commands/asr/helpers.js +76 -0
  361. package/lib/commands/asr/index.js +236 -0
  362. package/lib/commands/asr/local-transcribe.js +125 -0
  363. package/lib/commands/asr-jobs.js +257 -0
  364. package/lib/commands/asr.js +11 -0
  365. package/lib/commands/auth-cmds.js +358 -0
  366. package/lib/commands/dub.js +542 -0
  367. package/lib/commands/explain.js +512 -0
  368. package/lib/commands/feedback.js +152 -0
  369. package/lib/commands/image.js +207 -0
  370. package/lib/commands/mcp-key.js +166 -0
  371. package/lib/commands/narrate.js +639 -0
  372. package/lib/commands/picstory-templates.js +276 -0
  373. package/lib/commands/picstory.js +547 -0
  374. package/lib/commands/podcast/dialogue.js +109 -0
  375. package/lib/commands/podcast/generate.js +127 -0
  376. package/lib/commands/podcast/index.js +561 -0
  377. package/lib/commands/podcast/synthesize.js +188 -0
  378. package/lib/commands/podcast.js +11 -0
  379. package/lib/commands/present.js +519 -0
  380. package/lib/commands/publish.js +415 -0
  381. package/lib/commands/skills.js +473 -0
  382. package/lib/commands/slice-render.js +282 -0
  383. package/lib/commands/slice-stage.js +264 -0
  384. package/lib/commands/slice.js +346 -0
  385. package/lib/commands/slides/constants.js +108 -0
  386. package/lib/commands/slides/html-renderer.js +338 -0
  387. package/lib/commands/slides/index.js +345 -0
  388. package/lib/commands/slides.js +11 -0
  389. package/lib/commands/story.js +302 -0
  390. package/lib/commands/summarize.js +532 -0
  391. package/lib/commands/synthesize.js +261 -0
  392. package/lib/commands/translate.js +593 -0
  393. package/lib/commands/upgrade.js +249 -0
  394. package/lib/commands/video-translate.js +577 -0
  395. package/lib/commands/voices.js +292 -0
  396. package/lib/core/agent-env.js +104 -0
  397. package/lib/core/args.js +107 -0
  398. package/lib/core/asr-client.js +448 -0
  399. package/lib/core/asr-jobs-client.js +126 -0
  400. package/lib/core/asr-jobs-store.js +105 -0
  401. package/lib/core/asr-r2-upload.js +181 -0
  402. package/lib/core/asr-upload.js +132 -0
  403. package/lib/core/audio-extract.js +150 -0
  404. package/lib/core/audio.js +219 -0
  405. package/lib/core/auth.js +880 -0
  406. package/lib/core/config.js +197 -0
  407. package/lib/core/feedback.js +64 -0
  408. package/lib/core/ffmpeg.js +476 -0
  409. package/lib/core/http.js +188 -0
  410. package/lib/core/image-client.js +55 -0
  411. package/lib/core/intent-params.js +11 -0
  412. package/lib/core/llm-client.js +76 -0
  413. package/lib/core/logger.js +208 -0
  414. package/lib/core/mic-recorder.js +182 -0
  415. package/lib/core/pause-markers.js +94 -0
  416. package/lib/core/podcast-pacing.js +118 -0
  417. package/lib/core/spinner.js +33 -0
  418. package/lib/core/srt.js +394 -0
  419. package/lib/core/telemetry.js +100 -0
  420. package/lib/core/timeline.js +92 -0
  421. package/lib/core/tts-synthesizer.js +70 -0
  422. package/lib/core/update-check.js +185 -0
  423. package/lib/core/url-download.js +148 -0
  424. package/lib/core/whisper-local.js +279 -0
  425. package/lib/internal/deck-validator.js +488 -0
  426. package/lib/internal/slice-themes.json +370 -0
  427. package/lib/stage-core/cloud-render.js +170 -0
  428. package/lib/stage-core/deck-format.js +133 -0
  429. package/lib/stage-core/edit-prompt.js +104 -0
  430. package/lib/stage-core/event-bus.js +31 -0
  431. package/lib/stage-core/port.js +46 -0
  432. package/lib/stage-core/server.js +352 -0
  433. package/lib/stage-core/snapshot-store.js +198 -0
  434. package/lib/stage-core/watcher.js +106 -0
  435. package/lib/stage-ui/slice/template.js +1672 -0
  436. package/package.json +9 -4
  437. package/skills/.claude-plugin/marketplace.json +22 -0
  438. package/skills/.claude-plugin/plugin.json +25 -0
  439. package/skills/LICENSE +21 -0
  440. package/skills/README.md +120 -0
  441. package/skills/hub/SKILL.md +317 -0
  442. package/skills/podcast/SKILL.md +146 -0
  443. package/skills/slice/SKILL.md +205 -0
  444. package/skills/slice/agents/openai.yaml +4 -0
  445. package/skills/slice/references/deck-schema.md +183 -0
  446. package/skills/slice/references/example-decks.md +108 -0
  447. package/skills/slice/references/themes.md +172 -0
  448. package/skills/transcribe/SKILL.md +473 -0
  449. package/skills/video/SKILL.md +261 -0
  450. package/skills/voxflow-slice/SKILL.md +271 -0
  451. package/skills/voxflow-slice/examples/article.md +13 -0
  452. package/skills/voxflow-slice/examples/expected-deck.json +39 -0
  453. package/skills/voxflow-slice/examples/validate.mjs +46 -0
@@ -0,0 +1,384 @@
1
+ /**
2
+ * ASR command — Tencent cloud transcription pipeline.
3
+ *
4
+ * Handles: input validation, audio extraction, upload, ASR API call,
5
+ * caption building, output formatting, and resume-polling.
6
+ */
7
+
8
+ 'use strict';
9
+
10
+ const fs = require('fs');
11
+ const path = require('path');
12
+ const { API_BASE, ASR_DEFAULTS } = require('../../core/config');
13
+ const { getMediaInfo, extractAudioForAsr } = require('../../core/audio-extract');
14
+ const { uploadAsrAudio } = require('../../core/asr-upload');
15
+ const { downloadUrlToTempFile } = require('../../core/url-download');
16
+ const {
17
+ recognize,
18
+ detectMode,
19
+ BASE64_MAX_BYTES,
20
+ TASK_STATUS,
21
+ } = require('../../core/asr-client');
22
+ const {
23
+ formatSrt,
24
+ formatPlainText,
25
+ formatJson,
26
+ buildCaptionsFromFlash,
27
+ buildCaptionsFromSentence,
28
+ buildCaptionsFromFile,
29
+ } = require('../../core/srt');
30
+ const { FORMAT_EXTENSIONS, LANG_LABELS, formatDuration, formatSize } = require('./helpers');
31
+
32
+ /**
33
+ * Cloud (Tencent) ASR pipeline.
34
+ *
35
+ * @param {object} opts - Same shape as asr() opts
36
+ * @param {string[]} tempFiles - Mutable array for SIGINT cleanup
37
+ * @returns {Promise<object>}
38
+ */
39
+ async function asrCloud(opts, tempFiles) {
40
+ const {
41
+ token,
42
+ api = API_BASE,
43
+ input,
44
+ url: remoteUrl,
45
+ mic = false,
46
+ mode: requestedMode = ASR_DEFAULTS.mode,
47
+ lang = ASR_DEFAULTS.lang,
48
+ format = ASR_DEFAULTS.format,
49
+ output: userOutput,
50
+ speakers = false,
51
+ speakerNumber = 0,
52
+ } = opts;
53
+
54
+ // ── Validate input source ────────────────────────────────────────────
55
+ const sources = [input, remoteUrl, mic].filter(Boolean).length;
56
+ if (sources === 0) {
57
+ throw new Error(
58
+ 'No input specified. Provide one of:\n' +
59
+ ' --input <file> Local audio/video file\n' +
60
+ ' --url <url> Remote audio URL\n' +
61
+ ' --mic Record from microphone'
62
+ );
63
+ }
64
+ if (sources > 1) {
65
+ throw new Error('Specify only one input source: --input, --url, or --mic');
66
+ }
67
+
68
+ console.log('\n=== VoxFlow ASR ===');
69
+
70
+ // ── Handle microphone input ──────────────────────────────────────────
71
+ let localFile = input ? path.resolve(input) : null;
72
+ let resolvedRemoteUrl = remoteUrl;
73
+
74
+ if (mic) {
75
+ localFile = await handleMicInput();
76
+ tempFiles.push(localFile);
77
+ }
78
+
79
+ // ── Fetch remote URL → temp file ─────────────────────────────────────
80
+ if (resolvedRemoteUrl && !localFile) {
81
+ console.log(`Input: ${resolvedRemoteUrl}`);
82
+ console.log(`\nFetching remote URL...`);
83
+ try {
84
+ const dl = await downloadUrlToTempFile(resolvedRemoteUrl, {
85
+ onProgress: (received, total) => {
86
+ const mb = (received / 1024 / 1024).toFixed(1);
87
+ if (total) {
88
+ const pct = Math.round((received / total) * 100);
89
+ process.stdout.write(`\r ${mb} MB / ${(total / 1024 / 1024).toFixed(1)} MB (${pct}%) `);
90
+ } else {
91
+ process.stdout.write(`\r ${mb} MB downloaded `);
92
+ }
93
+ },
94
+ });
95
+ process.stdout.write(`\n`);
96
+ console.log(` OK (${(dl.size / 1024 / 1024).toFixed(1)} MB → ${dl.filePath})`);
97
+ localFile = dl.filePath;
98
+ tempFiles.push(localFile);
99
+ resolvedRemoteUrl = null;
100
+ } catch (err) {
101
+ throw new Error(`Failed to fetch ${resolvedRemoteUrl}: ${err.message}`);
102
+ }
103
+ }
104
+
105
+ try {
106
+ // ── Validate local file ──────────────────────────────────────────────
107
+ if (localFile && !fs.existsSync(localFile)) {
108
+ throw new Error(`Input file not found: ${localFile}`);
109
+ }
110
+
111
+ // ── Probe media info ─────────────────────────────────────────────────
112
+ let durationMs = 0;
113
+ let fileSize = 0;
114
+ let audioUrl = resolvedRemoteUrl || null;
115
+
116
+ if (localFile) {
117
+ console.log(`Input: ${path.basename(localFile)}`);
118
+
119
+ const info = await getMediaInfo(localFile);
120
+ durationMs = info.durationMs;
121
+ fileSize = fs.statSync(localFile).size;
122
+
123
+ const durationStr = formatDuration(durationMs);
124
+ const sizeStr = formatSize(fileSize);
125
+ console.log(`Duration: ${durationStr}`);
126
+ console.log(`Size: ${sizeStr}`);
127
+
128
+ if (!info.hasAudio) {
129
+ throw new Error('Input file has no audio track.');
130
+ }
131
+
132
+ // Extract & convert to 16kHz WAV for ASR
133
+ console.log(`\n[1/3] Extracting audio (16kHz mono WAV)...`);
134
+ const extracted = await extractAudioForAsr(localFile);
135
+ tempFiles.push(extracted.wavPath);
136
+ durationMs = extracted.durationMs;
137
+ fileSize = fs.statSync(extracted.wavPath).size;
138
+ localFile = extracted.wavPath;
139
+
140
+ console.log(` OK (${formatSize(fileSize)}, ${formatDuration(durationMs)})`);
141
+ } else {
142
+ console.log(`Input: ${remoteUrl}`);
143
+ console.log(`(Remote URL — duration will be detected by ASR API)`);
144
+ }
145
+
146
+ // ── Determine mode ───────────────────────────────────────────────────
147
+ const hasUrl = !!audioUrl;
148
+ const actualMode = requestedMode === 'auto'
149
+ ? detectMode(durationMs, hasUrl || !!localFile, fileSize)
150
+ : requestedMode;
151
+
152
+ console.log(`Mode: ${actualMode}`);
153
+ console.log(`Language: ${LANG_LABELS[lang] || lang}`);
154
+ console.log(`Format: ${format}`);
155
+
156
+ // ── Upload to COS if needed ──────────────────────────────────────────
157
+ if (localFile && !audioUrl) {
158
+ const needsUpload =
159
+ actualMode === 'flash' ||
160
+ (actualMode === 'file' && fileSize > BASE64_MAX_BYTES) ||
161
+ (actualMode === 'sentence' && fileSize > BASE64_MAX_BYTES);
162
+
163
+ if (needsUpload) {
164
+ console.log(`\n[2/3] Uploading to Supabase Storage...`);
165
+ const uploadResult = await uploadAsrAudio(localFile, api, token);
166
+ audioUrl = uploadResult.downloadUrl;
167
+ console.log(` OK (${uploadResult.path})`);
168
+ } else {
169
+ console.log(`\n[2/3] Uploading... (skipped, using base64)`);
170
+ }
171
+ } else if (!localFile && audioUrl) {
172
+ console.log(`\n[2/3] Uploading... (skipped, using remote URL)`);
173
+ }
174
+
175
+ // ── Call ASR API ─────────────────────────────────────────────────────
176
+ console.log(`\n[3/3] ASR speech recognition (${actualMode})...`);
177
+
178
+ const startTime = Date.now();
179
+
180
+ const result = await recognize({
181
+ apiBase: api,
182
+ token,
183
+ mode: actualMode,
184
+ url: audioUrl,
185
+ filePath: !audioUrl ? localFile : undefined,
186
+ durationMs,
187
+ fileSize,
188
+ lang,
189
+ speakerDiarization: speakers,
190
+ speakerNumber,
191
+ wordInfo: format === 'srt',
192
+ onProgress: (status, elapsed) => {
193
+ const statusLabel =
194
+ status === TASK_STATUS.WAITING ? 'Queued' :
195
+ status === TASK_STATUS.PROCESSING ? 'Recognizing' : 'Unknown';
196
+ process.stdout.write(`\r ${statusLabel}... (${Math.round(elapsed / 1000)}s)`);
197
+ },
198
+ });
199
+
200
+ const elapsedSec = ((Date.now() - startTime) / 1000).toFixed(1);
201
+ console.log(`\n OK (${elapsedSec}s)`);
202
+
203
+ // ── Build captions ───────────────────────────────────────────────────
204
+ const effectiveAudioTime = result.audioTime || (durationMs / 1000) || 0;
205
+
206
+ let captions;
207
+ switch (result.mode) {
208
+ case 'flash':
209
+ captions = buildCaptionsFromFlash(result.flashResult || []);
210
+ break;
211
+ case 'sentence':
212
+ captions = buildCaptionsFromSentence(
213
+ result.result,
214
+ effectiveAudioTime,
215
+ result.wordList
216
+ );
217
+ break;
218
+ case 'file':
219
+ captions = buildCaptionsFromFile(result.result, effectiveAudioTime);
220
+ break;
221
+ default:
222
+ captions = [{ id: 1, startMs: 0, endMs: 0, text: result.result || '' }];
223
+ }
224
+
225
+ // ── Format output ────────────────────────────────────────────────────
226
+ let outputContent;
227
+ switch (format) {
228
+ case 'srt':
229
+ outputContent = formatSrt(captions);
230
+ break;
231
+ case 'txt':
232
+ outputContent = formatPlainText(captions, { includeSpeakers: speakers });
233
+ break;
234
+ case 'json':
235
+ outputContent = formatJson(captions);
236
+ break;
237
+ default:
238
+ throw new Error(`Unknown format: ${format}. Use: srt, txt, json`);
239
+ }
240
+
241
+ // ── Determine output path ────────────────────────────────────────────
242
+ const ext = FORMAT_EXTENSIONS[format] || '.txt';
243
+ const anchor = opts._initialCwd || process.cwd();
244
+ let outputPath;
245
+
246
+ if (userOutput) {
247
+ outputPath = path.isAbsolute(userOutput) ? userOutput : path.resolve(anchor, userOutput);
248
+ } else if (input) {
249
+ const inputAbs = path.isAbsolute(input) ? input : path.resolve(anchor, input);
250
+ const base = path.basename(inputAbs, path.extname(inputAbs));
251
+ const fname = base + ext;
252
+ outputPath = path.join(path.dirname(inputAbs), fname);
253
+ } else if (mic) {
254
+ const fname = 'mic-' + Date.now() + ext;
255
+ outputPath = path.join(anchor, fname);
256
+ } else {
257
+ try {
258
+ const urlObj = new URL(remoteUrl);
259
+ const base = path.basename(urlObj.pathname, path.extname(urlObj.pathname)) || 'asr';
260
+ const fname = base + ext;
261
+ outputPath = path.join(anchor, fname);
262
+ } catch {
263
+ const fname = 'asr-' + Date.now() + ext;
264
+ outputPath = path.join(anchor, fname);
265
+ }
266
+ }
267
+
268
+ // ── Write output ─────────────────────────────────────────────────────
269
+ fs.writeFileSync(outputPath, outputContent, 'utf8');
270
+
271
+ // ── Summary ──────────────────────────────────────────────────────────
272
+ const quota = result.quota || {};
273
+ const quotaUsed = 1;
274
+ const remaining = quota.remaining ?? '?';
275
+
276
+ console.log(`\n=== Done ===`);
277
+ console.log(`Output: ${outputPath}`);
278
+ console.log(`Captions: ${captions.length}`);
279
+ console.log(`Duration: ${formatDuration(durationMs || (result.audioTime || 0) * 1000)}`);
280
+ console.log(`Mode: ${result.mode}`);
281
+ console.log(`Quota: ${quotaUsed} used, ${remaining} remaining`);
282
+
283
+ // Print preview (first 3 captions)
284
+ if (captions.length > 0 && format !== 'json') {
285
+ console.log(`\n--- Preview ---`);
286
+ const preview = captions.slice(0, 3);
287
+ for (const cap of preview) {
288
+ const ts = formatDuration(cap.startMs);
289
+ const speaker = cap.speakerId ? `[${cap.speakerId}] ` : '';
290
+ const textSnippet = cap.text.length > 60
291
+ ? cap.text.slice(0, 57) + '...'
292
+ : cap.text;
293
+ console.log(` ${ts} ${speaker}${textSnippet}`);
294
+ }
295
+ if (captions.length > 3) {
296
+ console.log(` ... (${captions.length - 3} more)`);
297
+ }
298
+ }
299
+
300
+ return {
301
+ outputPath,
302
+ mode: result.mode,
303
+ duration: durationMs / 1000,
304
+ captionCount: captions.length,
305
+ quotaUsed,
306
+ };
307
+
308
+ } finally {
309
+ // ── Clean up temp files ──────────────────────────────────────────────
310
+ for (const tmp of tempFiles) {
311
+ try { fs.unlinkSync(tmp); } catch { /* ignore */ }
312
+ }
313
+ }
314
+ }
315
+
316
+ // ─── Resume polling ─────────────────────────────────────────────────────────
317
+
318
+ async function resumePoll({ apiBase, token, taskId, format, output }) {
319
+ console.log(`\n=== VoxFlow ASR — Resume Task ===`);
320
+ console.log(`Task ID: ${taskId}`);
321
+
322
+ const { pollTaskResult, TASK_STATUS: TS } = require('../../core/asr-client');
323
+
324
+ console.log(`Polling...`);
325
+
326
+ const result = await pollTaskResult({
327
+ apiBase,
328
+ token,
329
+ taskId,
330
+ onProgress: (status, elapsed) => {
331
+ const label = status === TS.WAITING ? 'Queued' : status === TS.PROCESSING ? 'Recognizing' : '?';
332
+ process.stdout.write(`\r ${label}... (${Math.round(elapsed / 1000)}s)`);
333
+ },
334
+ });
335
+
336
+ console.log(`\n OK`);
337
+
338
+ const captions = buildCaptionsFromFile(result.result, result.audioTime);
339
+
340
+ let outputContent;
341
+ switch (format) {
342
+ case 'srt': outputContent = formatSrt(captions); break;
343
+ case 'txt': outputContent = formatPlainText(captions); break;
344
+ case 'json': outputContent = formatJson(captions); break;
345
+ default: outputContent = formatPlainText(captions);
346
+ }
347
+
348
+ const ext = FORMAT_EXTENSIONS[format] || '.txt';
349
+ const outputPath = output
350
+ ? path.resolve(output)
351
+ : path.resolve(`task-${taskId}${ext}`);
352
+
353
+ fs.writeFileSync(outputPath, outputContent, 'utf8');
354
+
355
+ console.log(`\n=== Done ===`);
356
+ console.log(`Output: ${outputPath}`);
357
+ console.log(`Captions: ${captions.length}`);
358
+ console.log(`Duration: ${formatDuration((result.audioTime || 0) * 1000)}`);
359
+
360
+ return { outputPath, mode: 'file', duration: result.audioTime, captionCount: captions.length };
361
+ }
362
+
363
+ // ─── Microphone input ───────────────────────────────────────────────────────
364
+
365
+ async function handleMicInput() {
366
+ const { recordMic, checkRecAvailable } = require('../../core/mic-recorder');
367
+
368
+ const check = await checkRecAvailable();
369
+ if (!check.available) {
370
+ throw new Error(check.error);
371
+ }
372
+
373
+ console.log(`\nRecording from microphone...`);
374
+ console.log(` Press Enter or Q to stop recording.`);
375
+ console.log(` Max duration: 5 minutes.\n`);
376
+
377
+ const { wavPath, durationMs, stopped } = await recordMic({ maxSeconds: 300 });
378
+
379
+ console.log(`\n Recording ${stopped === 'user' ? 'stopped' : 'finished'}: ${formatDuration(durationMs)}`);
380
+
381
+ return wavPath;
382
+ }
383
+
384
+ module.exports = { asrCloud, resumePoll };
@@ -0,0 +1,76 @@
1
+ /**
2
+ * ASR command — shared helpers and constants.
3
+ */
4
+
5
+ 'use strict';
6
+
7
+ const LANG_LABELS = {
8
+ '16k_zh': 'Chinese (16kHz)',
9
+ '16k_en': 'English (16kHz)',
10
+ '16k_zh_en': 'Chinese-English (16kHz)',
11
+ '16k_ja': 'Japanese (16kHz)',
12
+ '16k_ko': 'Korean (16kHz)',
13
+ '16k_zh_dialect': 'Chinese dialect (16kHz)',
14
+ '8k_zh': 'Chinese (8kHz phone)',
15
+ '8k_en': 'English (8kHz phone)',
16
+ };
17
+
18
+ const FORMAT_EXTENSIONS = {
19
+ srt: '.srt',
20
+ txt: '.txt',
21
+ json: '.json',
22
+ };
23
+
24
+ function formatDuration(ms) {
25
+ if (!ms || ms <= 0) return '0s';
26
+ const totalSec = Math.round(ms / 1000);
27
+ if (totalSec < 60) return `${totalSec}s`;
28
+ const min = Math.floor(totalSec / 60);
29
+ const sec = totalSec % 60;
30
+ if (min < 60) return `${min}m${sec > 0 ? sec + 's' : ''}`;
31
+ const hr = Math.floor(min / 60);
32
+ const remMin = min % 60;
33
+ return `${hr}h${remMin > 0 ? remMin + 'm' : ''}`;
34
+ }
35
+
36
+ function formatSize(bytes) {
37
+ if (bytes < 1024) return `${bytes} B`;
38
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
39
+ return `${(bytes / 1024 / 1024).toFixed(1)} MB`;
40
+ }
41
+
42
+ /**
43
+ * Resolve engine selection: 'auto' checks whisper availability.
44
+ * @param {string} engine - 'auto', 'local', 'cloud', 'whisper', 'tencent', 'azure'
45
+ * @returns {'local'|'cloud'|'azure'}
46
+ */
47
+ function resolveEngine(engine) {
48
+ const { checkWhisperAvailable } = require('../../core/whisper-local');
49
+ if (engine === 'local' || engine === 'whisper') {
50
+ const check = checkWhisperAvailable();
51
+ if (!check.available) {
52
+ throw new Error(
53
+ 'Local whisper engine requires nodejs-whisper.\n' +
54
+ 'Install: npm install -g nodejs-whisper\n' +
55
+ 'Download a model: npx nodejs-whisper download\n' +
56
+ 'Or use: --engine cloud'
57
+ );
58
+ }
59
+ return 'local';
60
+ }
61
+ if (engine === 'azure') return 'azure';
62
+ if (engine === 'cloud' || engine === 'tencent') return 'cloud';
63
+ if (engine === 'auto') {
64
+ const { available } = checkWhisperAvailable();
65
+ return available ? 'local' : 'cloud';
66
+ }
67
+ return 'cloud';
68
+ }
69
+
70
+ module.exports = {
71
+ LANG_LABELS,
72
+ FORMAT_EXTENSIONS,
73
+ formatDuration,
74
+ formatSize,
75
+ resolveEngine,
76
+ };
@@ -0,0 +1,236 @@
1
+ /**
2
+ * VoxFlow CLI — ASR (Automatic Speech Recognition) command
3
+ *
4
+ * Thin orchestrator: dispatches to engine-specific submodules.
5
+ *
6
+ * Supported engines:
7
+ * - cloud (Tencent): sentence/flash/file modes
8
+ * - azure: batch transcription via R2 upload
9
+ * - local: offline Whisper
10
+ */
11
+
12
+ 'use strict';
13
+
14
+ const fs = require('fs');
15
+ const { API_BASE, ASR_DEFAULTS } = require('../../core/config');
16
+ const { ApiError } = require('../../core/http');
17
+ const { resolveEngine } = require('./helpers');
18
+ const { asrLocal } = require('./local-transcribe');
19
+ const { asrAzure, asrAzureResume, joinWords, splitSegmentByWords, azureSegmentsToCaptions } = require('./azure-transcribe');
20
+ const { asrCloud, resumePoll } = require('./cloud-transcribe');
21
+
22
+ // ─── Main command ───────────────────────────────────────────────────────────
23
+
24
+ /**
25
+ * ASR command entry point (with SIGINT guard).
26
+ */
27
+ async function asr(opts) {
28
+ let isExiting = false;
29
+ let tempFiles = [];
30
+
31
+ const initialCwd = process.cwd();
32
+
33
+ const sigintHandler = () => {
34
+ if (isExiting) return;
35
+ isExiting = true;
36
+ console.log('\n\nASR cancelled.');
37
+ for (const f of tempFiles) {
38
+ try { fs.unlinkSync(f); } catch {}
39
+ }
40
+ process.exit(130);
41
+ };
42
+ process.on('SIGINT', sigintHandler);
43
+
44
+ // Background refresh: Azure ASR jobs can poll for >1h (long lectures, batch
45
+ // dictation). Refresh proactively so the poll loop never sees a 401.
46
+ // No-op if `token` is the env-var path (refresh would fail anyway, env
47
+ // wins on re-read).
48
+ const { startBackgroundRefresh } = require('../../core/auth');
49
+ const stopRefresh = startBackgroundRefresh({ api: opts.api });
50
+
51
+ try {
52
+ return await _asr({ ...opts, _initialCwd: initialCwd }, tempFiles);
53
+ } finally {
54
+ stopRefresh();
55
+ process.removeListener('SIGINT', sigintHandler);
56
+ }
57
+ }
58
+
59
+ async function _asr(opts, tempFiles) {
60
+ const {
61
+ token,
62
+ api = API_BASE,
63
+ mode: requestedMode = ASR_DEFAULTS.mode,
64
+ lang = ASR_DEFAULTS.lang,
65
+ format = ASR_DEFAULTS.format,
66
+ output: userOutput,
67
+ taskId,
68
+ jobId,
69
+ engine = 'auto',
70
+ model = 'base',
71
+ } = opts;
72
+
73
+ // ── Resume Azure job (UUID jobId) ────────────────────────────────────
74
+ if (jobId) {
75
+ return await asrAzureResume({ apiBase: api, token, jobId, format, output: userOutput });
76
+ }
77
+
78
+ // ── Resume Tencent task (numeric taskId) ─────────────────────────────
79
+ if (taskId) {
80
+ return await resumePoll({
81
+ apiBase: api, token, taskId, format, output: userOutput, lang,
82
+ });
83
+ }
84
+
85
+ // ── Resolve engine ─────────────────────────────────────────────────
86
+ const resolvedEngine = resolveEngine(engine);
87
+
88
+ // If local engine, take the local whisper path
89
+ if (resolvedEngine === 'local') {
90
+ return await asrLocal({ input: opts.input, format, output: userOutput, model, lang });
91
+ }
92
+
93
+ // Azure engine takes a separate code path
94
+ if (resolvedEngine === 'azure') {
95
+ return await asrAzure({
96
+ apiBase: api, token, input: opts.input, lang, format, output: userOutput, opts, tempFiles
97
+ });
98
+ }
99
+
100
+ // Cloud (Tencent) engine
101
+ return await asrCloud(opts, tempFiles);
102
+ }
103
+
104
+ // ─── CLI Handler ────────────────────────────────────────────────────────────
105
+
106
+ async function handle(args) {
107
+ const { parseFlag, parseIntFlag, parseBoolFlag, runWithRetry } = require('../../core/args');
108
+ const { getToken, getTokenInfo } = require('../../core/auth');
109
+ const { API_BASE, ASR_DEFAULTS: ASR_DEFS, getConfigDir } = require('../../core/config');
110
+ const { warnIfMissingFfmpeg } = require('../../core/ffmpeg');
111
+
112
+ // Check FFmpeg availability (one-time hint)
113
+ await warnIfMissingFfmpeg(getConfigDir(), 'asr');
114
+
115
+ const api = parseFlag(args, '--api') || API_BASE;
116
+ const explicitToken = parseFlag(args, '--token');
117
+
118
+ // Parse engine and model flags first (affects auth requirement)
119
+ const engine = parseFlag(args, '--engine') || ASR_DEFS.engine;
120
+ const model = parseFlag(args, '--model') || ASR_DEFS.model;
121
+
122
+ // Validate engine
123
+ if (engine && !['auto', 'local', 'cloud', 'whisper', 'tencent', 'azure'].includes(engine)) {
124
+ console.error(`Error: --engine must be one of: auto, local, cloud, azure (got: "${engine}")`);
125
+ process.exit(1);
126
+ }
127
+
128
+ // Validate model
129
+ if (model && !['tiny', 'base', 'small', 'medium', 'large'].includes(model)) {
130
+ console.error(`Error: --model must be one of: tiny, base, small, medium, large (got: "${model}")`);
131
+ process.exit(1);
132
+ }
133
+
134
+ // Parse and validate ASR-specific flags before auth
135
+ const input = parseFlag(args, '--input');
136
+ const url = parseFlag(args, '--url');
137
+ const mic = parseBoolFlag(args, '--mic');
138
+ const mode = parseFlag(args, '--mode') || ASR_DEFS.mode;
139
+ const lang = parseFlag(args, '--lang') || parseFlag(args, '--language') || ASR_DEFS.lang;
140
+ const format = parseFlag(args, '--format') || ASR_DEFS.format;
141
+ const output = parseFlag(args, '--output', '-o');
142
+ const speakers = parseBoolFlag(args, '--speakers');
143
+ const speakerNumber = parseIntFlag(args, '--speaker-number');
144
+ const taskId = parseIntFlag(args, '--task-id');
145
+ const jobId = parseFlag(args, '--job-id');
146
+ const diarize = parseBoolFlag(args, '--diarize') || speakers;
147
+
148
+ // Validate mode
149
+ if (mode && !['auto', 'sentence', 'flash', 'file'].includes(mode)) {
150
+ console.error(`Error: --mode must be one of: auto, sentence, flash, file (got: "${mode}")`);
151
+ process.exit(1);
152
+ }
153
+
154
+ // Validate format
155
+ if (format && !['srt', 'txt', 'json'].includes(format)) {
156
+ console.error(`Error: --format must be one of: srt, txt, json (got: "${format}")`);
157
+ process.exit(1);
158
+ }
159
+
160
+ // Validate input file existence
161
+ if (input) {
162
+ const path = require('path');
163
+ const resolved = path.resolve(input);
164
+ if (!fs.existsSync(resolved)) {
165
+ console.error(`Error: Input file not found: ${resolved}`);
166
+ process.exit(1);
167
+ }
168
+ }
169
+
170
+ // Authenticate after all validation (local engine skips auth)
171
+ const isLocalEngine = engine === 'local' || engine === 'whisper';
172
+
173
+ let token;
174
+ if (isLocalEngine) {
175
+ token = null; // no auth needed
176
+ } else if (explicitToken) {
177
+ token = explicitToken;
178
+ } else {
179
+ token = await getToken({ api });
180
+ const info = getTokenInfo();
181
+ if (info) {
182
+ console.log(`\x1b[32mLogged in as ${info.email}\x1b[0m`);
183
+ }
184
+ }
185
+
186
+ const opts = {
187
+ token, api, input, url, mic, mode, lang, format, output,
188
+ speakers, speakerNumber, taskId, jobId, diarize,
189
+ engine, model,
190
+ };
191
+
192
+ // Local engine: no retry needed (no API auth)
193
+ if (isLocalEngine) {
194
+ await asr(opts);
195
+ } else {
196
+ await runWithRetry(asr, opts, api, explicitToken);
197
+ }
198
+ }
199
+
200
+ const meta = {
201
+ asr: {
202
+ usage: '[opts]',
203
+ description: 'Transcribe audio/video to text (alias: transcribe)',
204
+ aliasOf: 'transcribe',
205
+ options: [
206
+ `--input <file> Local audio or video file to transcribe`,
207
+ `--url <url> Remote audio URL — CLI fetches it locally then re-uploads (cloud only)`,
208
+ `--mic Record from microphone (cloud only, requires sox)`,
209
+ `--engine <type> auto (default) | local | cloud | azure`,
210
+ `--model <name> Whisper model: tiny, base (default), small, medium, large`,
211
+ `--mode <type> auto (default) | sentence | flash | file (cloud only)`,
212
+ `--lang <model> Language. Tencent: 16k_zh (default), 16k_en, ... | Azure: ja-JP, en-US, zh-CN, ...`,
213
+ `--format <fmt> Output format: srt (default), txt, json`,
214
+ `--output <path> Output file path (default: <input>.<format>)`,
215
+ `--speakers Enable speaker diarization (alias of --diarize)`,
216
+ `--diarize Enable speaker diarization (azure)`,
217
+ `--speaker-number <n> Expected number of speakers (with --speakers / --diarize)`,
218
+ `--task-id <id> Resume polling an existing async task (Tencent — numeric)`,
219
+ `--job-id <uuid> Resume polling an existing Azure job (UUID)`,
220
+ ],
221
+ examples: [
222
+ 'voxflow asr --input recording.mp3',
223
+ 'voxflow asr --input recording.mp3 --engine local --model small',
224
+ 'voxflow asr --input video.mp4 --format srt --lang 16k_zh',
225
+ 'voxflow asr --input meeting.mp4 --engine azure --lang ja-JP --diarize',
226
+ 'voxflow asr --engine azure --job-id 6f3c2798-87bf-4367-bb4c-08b872e12bef',
227
+ 'voxflow transcribe --input meeting.wav --speakers --speaker-number 3',
228
+ ],
229
+ },
230
+ // Alias picked up by the CLI router (issue #2389)
231
+ transcribe: { alias: 'asr', description: 'Alias for asr' },
232
+ };
233
+
234
+ module.exports = { asr, handle, meta, ApiError };
235
+ // 以下导出仅用于单元测试:
236
+ module.exports._internals = { joinWords, splitSegmentByWords, azureSegmentsToCaptions };