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,55 @@
1
+ /**
2
+ * VoxFlow CLI — Image generation client
3
+ *
4
+ * Calls /api/image/generate to produce AI images for picstory scenes.
5
+ */
6
+
7
+ const { request, throwApiError, throwNetworkError } = require('./http');
8
+
9
+ /**
10
+ * Generate an image via the VoxFlow image API.
11
+ *
12
+ * @param {object} opts
13
+ * @param {string} opts.apiBase - API base URL
14
+ * @param {string} opts.token - JWT auth token
15
+ * @param {string} opts.prompt - Image generation prompt
16
+ * @param {string} [opts.ratio='portrait'] - 'portrait' | 'landscape' | 'square'
17
+ * @param {string} [opts.quality='fast'] - 'fast' | 'hd'
18
+ * @param {number} [opts.index] - Current scene index (for progress output)
19
+ * @param {number} [opts.total] - Total scene count (for progress output)
20
+ * @returns {Promise<{ imageDataUrl: string, quota: object }>}
21
+ */
22
+ async function generateImage({ apiBase, token, prompt, ratio = 'portrait', quality = 'fast', index, total }) {
23
+ if (index !== undefined && total !== undefined) {
24
+ process.stdout.write(` Image [${index + 1}/${total}]...`);
25
+ }
26
+
27
+ let status, data;
28
+ try {
29
+ ({ status, data } = await request(`${apiBase}/api/image/generate`, {
30
+ method: 'POST',
31
+ headers: {
32
+ 'Content-Type': 'application/json',
33
+ Authorization: `Bearer ${token}`,
34
+ },
35
+ timeoutMs: 180_000,
36
+ }, { prompt, ratio, quality }));
37
+ } catch (err) {
38
+ if (index !== undefined) console.log(' FAIL');
39
+ throwNetworkError(err, apiBase);
40
+ }
41
+
42
+ if (status !== 200 || data.code !== 'success') {
43
+ if (index !== undefined) console.log(' FAIL');
44
+ throwApiError(status, data, `Image generation scene ${(index ?? 0) + 1}`);
45
+ }
46
+
47
+ if (index !== undefined) {
48
+ const sizeKb = Math.round(data.image.length * 0.75 / 1024); // base64 → approx bytes
49
+ console.log(` OK (~${sizeKb} KB)`);
50
+ }
51
+
52
+ return { imageDataUrl: data.image, quota: data.quota };
53
+ }
54
+
55
+ module.exports = { generateImage };
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Intent → TTS parameter mapping for podcast synthesis.
3
+ *
4
+ * Single source of truth: backend/config/intent-tts-params.js
5
+ * This file re-exports from backend to avoid duplication.
6
+ * ncc bundles from the monorepo at build time, so the relative path works.
7
+ */
8
+
9
+ const { INTENT_TTS_PARAMS, getIntentParams } = require('../../../backend/config/intent-tts-params');
10
+
11
+ module.exports = { INTENT_TTS_PARAMS, getIntentParams };
@@ -0,0 +1,76 @@
1
+ /**
2
+ * VoxFlow CLI — LLM API client
3
+ *
4
+ * Thin wrapper for /api/llm/chat and /api/lang-detect/detect endpoints.
5
+ */
6
+ const { request, throwApiError, throwNetworkError } = require('./http');
7
+
8
+ /**
9
+ * Call /api/llm/chat for text completion.
10
+ * Cost: 1 quota per call.
11
+ *
12
+ * @param {object} opts
13
+ * @param {string} opts.apiBase - API server base URL
14
+ * @param {string} opts.token - JWT auth token
15
+ * @param {Array} opts.messages - [{ role, content }]
16
+ * @param {number} [opts.temperature=0.3]
17
+ * @param {number} [opts.maxTokens=2000]
18
+ * @param {string} [opts.model] - Override LLM model (e.g. 'openai/gpt-4o-mini')
19
+ * @returns {{ content: string, usage: object, quota: object }}
20
+ */
21
+ async function chatCompletion({ apiBase, token, messages, temperature = 0.3, maxTokens = 2000, model, modelPreset, timeoutMs }) {
22
+ const body = { messages, temperature, max_tokens: maxTokens };
23
+ if (modelPreset) body.modelPreset = modelPreset;
24
+ else if (model) body.model = model;
25
+
26
+ let status, data;
27
+ try {
28
+ // Default 180s — slide generation at maxTokens=4000 on Sonnet/GPT-4o
29
+ // routinely needs 60-120s and the old 60s default was timing out
30
+ // before the LLM finished streaming (issue #2916).
31
+ ({ status, data } = await request(`${apiBase}/api/llm/chat`, {
32
+ method: 'POST',
33
+ headers: {
34
+ 'Content-Type': 'application/json',
35
+ 'Authorization': `Bearer ${token}`,
36
+ },
37
+ timeoutMs: Number(timeoutMs) > 0 ? Number(timeoutMs) : 180_000,
38
+ }, body));
39
+ } catch (err) {
40
+ throwNetworkError(err, apiBase);
41
+ }
42
+
43
+ if (status !== 200 || data.code !== 'success') {
44
+ throwApiError(status, data, 'LLM chat');
45
+ }
46
+
47
+ return { content: data.content, usage: data.usage, quota: data.quota };
48
+ }
49
+
50
+ /**
51
+ * Call /api/lang-detect/detect for language detection.
52
+ * Cost: FREE (no auth required).
53
+ *
54
+ * @param {object} opts
55
+ * @param {string} opts.apiBase - API server base URL
56
+ * @param {string} opts.text - Text sample to detect
57
+ * @returns {string} language code (e.g. 'zh', 'en') or 'auto' on failure
58
+ */
59
+ async function detectLanguage({ apiBase, text }) {
60
+ let status, data;
61
+ try {
62
+ ({ status, data } = await request(`${apiBase}/api/lang-detect/detect`, {
63
+ method: 'POST',
64
+ headers: { 'Content-Type': 'application/json' },
65
+ }, { text: text.slice(0, 200) }));
66
+ } catch {
67
+ return 'auto'; // Fallback on network error
68
+ }
69
+
70
+ if (status === 200 && data.code === 'success') {
71
+ return data.language;
72
+ }
73
+ return 'auto';
74
+ }
75
+
76
+ module.exports = { chatCompletion, detectLanguage };
@@ -0,0 +1,208 @@
1
+ /**
2
+ * VoxFlow CLI — structured stderr logger.
3
+ *
4
+ * Zero external deps (project convention). Adds what a CLI user-facing tool
5
+ * actually needs:
6
+ *
7
+ * - `-v / -vv / -vvv` (+ `--verbose[=level]`) parsed from argv to set level.
8
+ * Also honours `DEBUG=voxflow:*` and plain `DEBUG=voxflow` for parity with
9
+ * the wider Node ecosystem (wrangler, vercel, etc).
10
+ * - Everything writes to **stderr** so `voxflow xxx --json` stays pipeable on
11
+ * stdout. `voxflow dub ... --json | jq` must keep working.
12
+ * - Pretty when stderr is a TTY (ANSI colors + aligned level tag); JSON when
13
+ * piped / in CI. No `process.env.CI` magic — we key strictly on
14
+ * `isTTY`, which is what terminals set.
15
+ * - Sub-loggers via `logger.with({ command: 'dub', jobId: '...' })` —
16
+ * context is merged into every record so greppable metadata flows without
17
+ * threading arguments through every helper.
18
+ *
19
+ * Usage:
20
+ *
21
+ * const { logger, parseVerbosityFromArgv } = require('./core/logger');
22
+ *
23
+ * const { level, rest } = parseVerbosityFromArgv(process.argv.slice(2));
24
+ * logger.setLevel(level);
25
+ *
26
+ * const log = logger.with({ cmd: 'dub' });
27
+ * log.info({ captions: 47, voice: voiceId }, 'pipeline start');
28
+ * log.debug({ url }, 'POST /api/tts/synthesize');
29
+ * log.error({ err }, 'pipeline failed');
30
+ *
31
+ * The first arg is the context object (pino style). The string is the
32
+ * message. Either may be omitted.
33
+ */
34
+
35
+ const LEVELS = Object.freeze({
36
+ silent: 0,
37
+ error: 1,
38
+ warn: 2,
39
+ info: 3,
40
+ debug: 4,
41
+ trace: 5
42
+ });
43
+
44
+ const LEVEL_LABEL = Object.freeze({
45
+ error: 'ERR',
46
+ warn: 'WRN',
47
+ info: 'INF',
48
+ debug: 'DBG',
49
+ trace: 'TRC'
50
+ });
51
+
52
+ // ANSI colour codes. Plain strings — keeps zero-dep promise.
53
+ const COLOR = Object.freeze({
54
+ reset: '\x1b[0m',
55
+ dim: '\x1b[2m',
56
+ red: '\x1b[31m',
57
+ yellow: '\x1b[33m',
58
+ cyan: '\x1b[36m',
59
+ magenta: '\x1b[35m',
60
+ grey: '\x1b[90m'
61
+ });
62
+
63
+ const LEVEL_COLOR = Object.freeze({
64
+ error: COLOR.red,
65
+ warn: COLOR.yellow,
66
+ info: COLOR.cyan,
67
+ debug: COLOR.magenta,
68
+ trace: COLOR.grey
69
+ });
70
+
71
+ /**
72
+ * Parse `-v / -vv / -vvv / --verbose[=N]` flags out of argv.
73
+ * Returns `{ level, rest }` where `rest` has the flags stripped so the
74
+ * subcommand parser doesn't trip on them.
75
+ *
76
+ * Precedence: explicit `--verbose=N` > repeated short flags > default.
77
+ * `DEBUG` env var forces at least debug if matches `voxflow*`.
78
+ */
79
+ function parseVerbosityFromArgv(argv) {
80
+ let vCount = 0;
81
+ let explicit = null;
82
+ const rest = [];
83
+
84
+ for (const arg of argv) {
85
+ if (arg === '-v' || arg === '--verbose') { vCount += 1; continue; }
86
+ if (arg === '-vv') { vCount += 2; continue; }
87
+ if (arg === '-vvv') { vCount += 3; continue; }
88
+ if (arg.startsWith('--verbose=')) {
89
+ const v = arg.slice('--verbose='.length).toLowerCase();
90
+ if (v in LEVELS) explicit = v;
91
+ continue;
92
+ }
93
+ rest.push(arg);
94
+ }
95
+
96
+ // `DEBUG=voxflow` or `DEBUG=voxflow:*` → at least debug.
97
+ const debugEnv = process.env.DEBUG || '';
98
+ const debugMatchesUs = debugEnv.split(',').some(
99
+ part => part.trim() === 'voxflow' || part.trim().startsWith('voxflow:') || part.trim() === '*'
100
+ );
101
+
102
+ if (explicit) return { level: explicit, rest };
103
+ if (vCount >= 3) return { level: 'trace', rest };
104
+ if (vCount === 2) return { level: 'debug', rest };
105
+ if (vCount === 1) return { level: 'info', rest };
106
+ if (debugMatchesUs) return { level: 'debug', rest };
107
+ return { level: 'warn', rest };
108
+ }
109
+
110
+ // Internal state
111
+ let currentLevel = LEVELS.warn;
112
+ let useColor = Boolean(process.stderr.isTTY) && process.env.NO_COLOR !== '1';
113
+ let prettyMode = Boolean(process.stderr.isTTY);
114
+
115
+ function setLevel(levelName) {
116
+ if (!(levelName in LEVELS)) return;
117
+ currentLevel = LEVELS[levelName];
118
+ }
119
+
120
+ function getLevel() {
121
+ for (const [name, value] of Object.entries(LEVELS)) {
122
+ if (value === currentLevel) return name;
123
+ }
124
+ return 'warn';
125
+ }
126
+
127
+ /**
128
+ * Format one log record. Pretty for TTY stderr, single-line JSON otherwise
129
+ * (CI, piping `2>` to a file, etc).
130
+ */
131
+ function formatRecord(levelName, ctx, msg) {
132
+ const record = {
133
+ time: new Date().toISOString(),
134
+ level: levelName,
135
+ msg: msg || '',
136
+ ...(ctx || {})
137
+ };
138
+
139
+ // Lift Error objects into message + stack — JSON.stringify loses them otherwise.
140
+ if (record.err instanceof Error) {
141
+ record.errorMessage = record.err.message;
142
+ record.errorStack = record.err.stack;
143
+ delete record.err;
144
+ }
145
+
146
+ if (!prettyMode) {
147
+ return JSON.stringify(record);
148
+ }
149
+
150
+ const tag = LEVEL_LABEL[levelName] || levelName.toUpperCase();
151
+ const colour = useColor ? (LEVEL_COLOR[levelName] || '') : '';
152
+ const reset = useColor ? COLOR.reset : '';
153
+ const dim = useColor ? COLOR.dim : '';
154
+ const grey = useColor ? COLOR.grey : '';
155
+
156
+ const time = record.time.slice(11, 19); // HH:MM:SS
157
+ // Strip well-known fields to keep the context short.
158
+ const { time: _t, level: _l, msg: _m, ...kv } = record;
159
+ const extras = Object.entries(kv)
160
+ .map(([k, v]) => `${grey}${k}=${reset}${formatValue(v)}`)
161
+ .join(' ');
162
+
163
+ return `${dim}${time}${reset} ${colour}${tag}${reset} ${record.msg}${extras ? ' ' + extras : ''}`;
164
+ }
165
+
166
+ function formatValue(v) {
167
+ if (v === null || v === undefined) return String(v);
168
+ if (typeof v === 'string') return v.length > 200 ? JSON.stringify(v.slice(0, 200) + '…') : v;
169
+ if (typeof v === 'number' || typeof v === 'boolean') return String(v);
170
+ try { return JSON.stringify(v); } catch { return String(v); }
171
+ }
172
+
173
+ function emit(levelName, ctxOrMsg, maybeMsg) {
174
+ if (LEVELS[levelName] > currentLevel) return;
175
+ let ctx, msg;
176
+ if (typeof ctxOrMsg === 'string') { msg = ctxOrMsg; ctx = null; }
177
+ else { ctx = ctxOrMsg; msg = maybeMsg; }
178
+ const line = formatRecord(levelName, ctx, msg);
179
+ process.stderr.write(line + '\n');
180
+ }
181
+
182
+ /**
183
+ * Create a logger bound to a context object. Child ctx wins over parent.
184
+ */
185
+ function createLogger(boundCtx) {
186
+ const ctx = boundCtx || {};
187
+ const merge = (c) => c ? { ...ctx, ...c } : ctx;
188
+ return {
189
+ error: (c, m) => emit('error', typeof c === 'string' ? c : merge(c), typeof c === 'string' ? c : m),
190
+ warn: (c, m) => emit('warn', typeof c === 'string' ? c : merge(c), typeof c === 'string' ? c : m),
191
+ info: (c, m) => emit('info', typeof c === 'string' ? c : merge(c), typeof c === 'string' ? c : m),
192
+ debug: (c, m) => emit('debug', typeof c === 'string' ? c : merge(c), typeof c === 'string' ? c : m),
193
+ trace: (c, m) => emit('trace', typeof c === 'string' ? c : merge(c), typeof c === 'string' ? c : m),
194
+ with: (extra) => createLogger({ ...ctx, ...extra }),
195
+ setLevel,
196
+ getLevel
197
+ };
198
+ }
199
+
200
+ const root = createLogger({});
201
+
202
+ module.exports = {
203
+ logger: root,
204
+ parseVerbosityFromArgv,
205
+ // Exposed for tests only — not part of the public API.
206
+ LEVELS,
207
+ _formatRecord: formatRecord
208
+ };
@@ -0,0 +1,182 @@
1
+ /**
2
+ * VoxFlow CLI — Microphone recording via sox/rec
3
+ *
4
+ * Records audio from the default microphone into a 16kHz mono WAV file
5
+ * suitable for Tencent Cloud ASR APIs.
6
+ *
7
+ * Requires: sox (with rec) installed on the system.
8
+ * macOS: brew install sox
9
+ * Ubuntu: sudo apt install sox
10
+ * Windows: https://sourceforge.net/projects/sox/
11
+ */
12
+
13
+ const { spawn } = require('child_process');
14
+ const path = require('path');
15
+ const os = require('os');
16
+ const fs = require('fs');
17
+
18
+ // ─── Check availability ─────────────────────────────────────────────────────
19
+
20
+ /**
21
+ * Check whether the `rec` command (part of sox) is available.
22
+ * @returns {Promise<{available: boolean, error?: string}>}
23
+ */
24
+ async function checkRecAvailable() {
25
+ return new Promise((resolve) => {
26
+ const proc = spawn('rec', ['--version'], { stdio: 'pipe' });
27
+ let out = '';
28
+
29
+ proc.stdout.on('data', (d) => { out += d; });
30
+ proc.stderr.on('data', (d) => { out += d; });
31
+
32
+ proc.on('error', () => {
33
+ resolve({
34
+ available: false,
35
+ error:
36
+ 'rec (sox) not found. Please install sox:\n' +
37
+ ' macOS: brew install sox\n' +
38
+ ' Ubuntu: sudo apt install sox\n' +
39
+ ' Windows: https://sourceforge.net/projects/sox/',
40
+ });
41
+ });
42
+
43
+ proc.on('close', (code) => {
44
+ resolve({ available: code === 0 || out.length > 0 });
45
+ });
46
+ });
47
+ }
48
+
49
+ // ─── Recording ──────────────────────────────────────────────────────────────
50
+
51
+ /**
52
+ * Record audio from the microphone until the user presses Enter or a stop
53
+ * callback is invoked.
54
+ *
55
+ * @param {object} [opts]
56
+ * @param {string} [opts.outputDir] - Directory for the WAV file (default: os.tmpdir())
57
+ * @param {number} [opts.maxSeconds] - Maximum recording duration (default: 300 = 5 min)
58
+ * @param {number} [opts.silenceThreshold] - Stop after this many seconds of silence (0 = disabled)
59
+ * @returns {Promise<{wavPath: string, durationMs: number, stopped: 'user'|'timeout'|'silence'}>}
60
+ */
61
+ function recordMic(opts = {}) {
62
+ const {
63
+ outputDir = os.tmpdir(),
64
+ maxSeconds = 300,
65
+ silenceThreshold = 0,
66
+ } = opts;
67
+
68
+ const wavPath = path.join(outputDir, `mic-${Date.now()}.wav`);
69
+
70
+ return new Promise((resolve, reject) => {
71
+ // Build rec arguments:
72
+ // rec -r 16000 -c 1 -b 16 -e signed-integer output.wav trim 0 <max>
73
+ const args = [
74
+ '-r', '16000', // 16kHz sample rate (ASR requirement)
75
+ '-c', '1', // mono
76
+ '-b', '16', // 16-bit
77
+ '-e', 'signed-integer', // PCM encoding
78
+ wavPath,
79
+ 'trim', '0', String(maxSeconds),
80
+ ];
81
+
82
+ // Add silence detection if requested
83
+ if (silenceThreshold > 0) {
84
+ args.push('silence', '1', '0.1', '1%', '1', String(silenceThreshold), '1%');
85
+ }
86
+
87
+ const proc = spawn('rec', args, { stdio: ['pipe', 'pipe', 'pipe'] });
88
+ let stderr = '';
89
+
90
+ proc.stderr.on('data', (d) => { stderr += d.toString(); });
91
+
92
+ proc.on('error', (err) => {
93
+ if (err.code === 'ENOENT') {
94
+ reject(new Error(
95
+ 'rec (sox) not found. Please install sox:\n' +
96
+ ' macOS: brew install sox\n' +
97
+ ' Ubuntu: sudo apt install sox\n' +
98
+ ' Windows: https://sourceforge.net/projects/sox/'
99
+ ));
100
+ } else {
101
+ reject(new Error(`Microphone recording failed: ${err.message}`));
102
+ }
103
+ });
104
+
105
+ let stoppedBy = 'timeout';
106
+
107
+ proc.on('close', (_code) => {
108
+ if (!fs.existsSync(wavPath)) {
109
+ return reject(new Error(
110
+ `Recording failed — no output file created.\n${stderr.slice(0, 500)}`
111
+ ));
112
+ }
113
+
114
+ const stat = fs.statSync(wavPath);
115
+ if (stat.size < 100) {
116
+ fs.unlinkSync(wavPath);
117
+ return reject(new Error(
118
+ 'Recording produced an empty file. Check that your microphone is connected and accessible.'
119
+ ));
120
+ }
121
+
122
+ // PCM s16le, 16kHz, mono: 32000 bytes per second
123
+ const durationMs = Math.round((stat.size - 44) / 32);
124
+
125
+ resolve({ wavPath, durationMs, stopped: stoppedBy });
126
+ });
127
+
128
+ // Allow the caller to stop recording by sending SIGTERM
129
+ // Also handle SIGINT gracefully (user presses Ctrl+C)
130
+ const stopRecording = () => {
131
+ stoppedBy = 'user';
132
+ proc.kill('SIGTERM');
133
+ };
134
+
135
+ // Listen for Enter key on stdin to stop recording
136
+ if (process.stdin.isTTY) {
137
+ process.stdin.setRawMode(true);
138
+ process.stdin.resume();
139
+
140
+ const onKey = (key) => {
141
+ // Enter key (CR or LF) or 'q' to stop
142
+ if (key[0] === 0x0d || key[0] === 0x0a || key[0] === 0x71) {
143
+ stoppedBy = 'user';
144
+ process.stdin.setRawMode(false);
145
+ process.stdin.removeListener('data', onKey);
146
+ process.stdin.pause();
147
+ proc.kill('SIGTERM');
148
+ }
149
+ // Ctrl+C
150
+ if (key[0] === 0x03) {
151
+ stoppedBy = 'user';
152
+ process.stdin.setRawMode(false);
153
+ process.stdin.removeListener('data', onKey);
154
+ process.stdin.pause();
155
+ proc.kill('SIGTERM');
156
+ }
157
+ };
158
+
159
+ process.stdin.on('data', onKey);
160
+
161
+ // Clean up stdin listener when process ends (regardless of how)
162
+ proc.on('close', () => {
163
+ try {
164
+ process.stdin.removeListener('data', onKey);
165
+ if (process.stdin.isTTY) {
166
+ process.stdin.setRawMode(false);
167
+ }
168
+ process.stdin.pause();
169
+ } catch {
170
+ // stdin may already be closed
171
+ }
172
+ });
173
+ }
174
+
175
+ // Expose stop function on the returned promise (for programmatic use)
176
+ // Callers can do: const p = recordMic(); p.stop();
177
+ // But since we return a promise, we attach it as a non-standard property
178
+ proc._stopRecording = stopRecording;
179
+ });
180
+ }
181
+
182
+ module.exports = { recordMic, checkRecAvailable };
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Pause Markers — CLI mirror of backend/utils/pause-markers.js.
3
+ *
4
+ * Markers (forward-compat with MiniMax T2A v2 PROSODY_TOKENS spec):
5
+ * <|break|> — long pause (LONG_PAUSE_MS = 600 ms)
6
+ * <|s_break|> — short pause (SHORT_PAUSE_MS = 300 ms)
7
+ *
8
+ * Tencent flow_01_turbo (current podcast provider) does NOT recognize
9
+ * these tokens, so we strip-and-splice client-side. The same `turn.text`
10
+ * payload Just Works if a voice ever routes through MiniMax — no schema
11
+ * change needed.
12
+ *
13
+ * Keep in sync with backend/utils/pause-markers.js + studio/src/shared/audio/pause-markers.js.
14
+ */
15
+
16
+ 'use strict';
17
+
18
+ const LONG_PAUSE = '<|break|>';
19
+ const SHORT_PAUSE = '<|s_break|>';
20
+ const LONG_PAUSE_MS = 600;
21
+ const SHORT_PAUSE_MS = 300;
22
+
23
+ function insertPauseMarkers(text) {
24
+ if (!text || typeof text !== 'string') return '';
25
+ // Only paragraph breaks auto-insert. Per-sentence and per-clause auto-
26
+ // insertion removed — TTS already pauses on punctuation natively, so
27
+ // adding `<|break|>` after every `。!?` and `<|s_break|>` after every
28
+ // long clause just stacked pause on pause.
29
+ let result = text.replace(/\n\n+/g, `\n\n${LONG_PAUSE}\n\n`);
30
+ const shortThenLong = new RegExp(escapeForRegex(SHORT_PAUSE) + '\\s*' + escapeForRegex(LONG_PAUSE), 'g');
31
+ result = result.replace(shortThenLong, LONG_PAUSE);
32
+ const doubleLong = new RegExp('(' + escapeForRegex(LONG_PAUSE) + '\\s*){2,}', 'g');
33
+ result = result.replace(doubleLong, LONG_PAUSE);
34
+ const doubleShort = new RegExp('(' + escapeForRegex(SHORT_PAUSE) + '\\s*){2,}', 'g');
35
+ result = result.replace(doubleShort, SHORT_PAUSE);
36
+ const trailingMarker = new RegExp(
37
+ '(' + escapeForRegex(LONG_PAUSE) + '|' + escapeForRegex(SHORT_PAUSE) + ')\\s*$'
38
+ );
39
+ result = result.replace(trailingMarker, '');
40
+ return result.trim();
41
+ }
42
+
43
+ function stripPauseMarkers(text) {
44
+ if (!text || typeof text !== 'string') return '';
45
+ return text
46
+ .replace(new RegExp(escapeForRegex(LONG_PAUSE), 'g'), '')
47
+ .replace(new RegExp(escapeForRegex(SHORT_PAUSE), 'g'), '')
48
+ .trim();
49
+ }
50
+
51
+ /**
52
+ * Split marked-up text into segments + the silence (ms) that follows each.
53
+ * Last segment's pauseAfterMs is 0 — caller decides trailing silence.
54
+ *
55
+ * Returns: [{ text, pauseAfterMs }, ...]
56
+ */
57
+ function splitOnPauseMarkers(text) {
58
+ if (!text || typeof text !== 'string') return [];
59
+ const tokenPattern = new RegExp(`(${escapeForRegex(LONG_PAUSE)}|${escapeForRegex(SHORT_PAUSE)})`, 'g');
60
+ const parts = text.split(tokenPattern).filter(p => p !== '');
61
+ const segments = [];
62
+ let current = '';
63
+ for (const part of parts) {
64
+ if (part === LONG_PAUSE || part === SHORT_PAUSE) {
65
+ const trimmed = current.trim();
66
+ if (trimmed) {
67
+ segments.push({
68
+ text: trimmed,
69
+ pauseAfterMs: part === LONG_PAUSE ? LONG_PAUSE_MS : SHORT_PAUSE_MS,
70
+ });
71
+ }
72
+ current = '';
73
+ } else {
74
+ current += part;
75
+ }
76
+ }
77
+ const tail = current.trim();
78
+ if (tail) segments.push({ text: tail, pauseAfterMs: 0 });
79
+ return segments;
80
+ }
81
+
82
+ function escapeForRegex(str) {
83
+ return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
84
+ }
85
+
86
+ module.exports = {
87
+ LONG_PAUSE,
88
+ SHORT_PAUSE,
89
+ LONG_PAUSE_MS,
90
+ SHORT_PAUSE_MS,
91
+ insertPauseMarkers,
92
+ stripPauseMarkers,
93
+ splitOnPauseMarkers,
94
+ };