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,532 @@
1
+ /**
2
+ * VoxFlow CLI — Summarize command (V2)
3
+ *
4
+ * Video/audio → ASR → LLM structured summary → PPTX + Video
5
+ *
6
+ * Video pipeline (--video):
7
+ * 1. ASR with timestamps → segmented transcript
8
+ * 2. LLM extracts key points with time ranges from original video
9
+ * 3. Per-point: cut original video clip + overlay text + TTS narration
10
+ * 4. FFmpeg concat: title card + annotated clips + closing card → MP4
11
+ */
12
+
13
+ const fs = require('fs');
14
+ const path = require('path');
15
+ const os = require('os');
16
+ const { asr } = require('./asr');
17
+ const { chatCompletion } = require('../core/llm-client');
18
+ const { request, throwApiError, throwNetworkError } = require('../core/http');
19
+ const { buildWav, createSilence } = require('../core/audio');
20
+ const { API_BASE, SUMMARIZE_DEFAULTS } = require('../core/config');
21
+
22
+ // ─── LLM Prompt: structured summary with time ranges ────────────────────────
23
+
24
+ const SUMMARIZE_PROMPT = `You are a video content analyst. Given a transcript with timestamps, extract key points and structure them for a summary presentation.
25
+
26
+ LANGUAGE RULE: Detect the language of the input content. All text fields (titles, bullets, narration) MUST be in the SAME language as the input.
27
+
28
+ STRICT RULES:
29
+ 1. Output ONLY valid JSON, no markdown fences, no extra text.
30
+ 2. Extract 4-8 key points from the transcript.
31
+ 3. Each point MUST reference a time range from the original video.
32
+ 4. narration: a professional summary of this point, 2-3 sentences, as if narrating a recap video.
33
+ 5. Remove filler words and repetitions. Every bullet should be specific.
34
+ 6. Do NOT invent facts not in the transcript.
35
+ 7. title: a short slide title for the point (max 15 chars).
36
+ 8. bullets: 1-3 concise bullet points (max 25 chars each).
37
+
38
+ OUTPUT FORMAT:
39
+ {
40
+ "meta": { "title": "...", "language": "..." },
41
+ "points": [
42
+ {
43
+ "id": 1,
44
+ "title": "<point title>",
45
+ "bullets": ["<bullet 1>", "<bullet 2>"],
46
+ "startSec": 0,
47
+ "endSec": 25,
48
+ "narration": "<narrator summary of this point>"
49
+ }
50
+ ]
51
+ }`;
52
+
53
+ // ─── PPTX generation ────────────────────────────────────────────────────────
54
+
55
+ async function generatePptx(summaryData, outputPath) {
56
+ let PptxGenJS;
57
+ try {
58
+ PptxGenJS = require('pptxgenjs');
59
+ } catch {
60
+ const jsonPath = outputPath.replace(/\.pptx$/, '.json');
61
+ fs.writeFileSync(jsonPath, JSON.stringify(summaryData, null, 2), 'utf8');
62
+ return { path: jsonPath, format: 'json', fallback: true };
63
+ }
64
+
65
+ const pptx = new PptxGenJS();
66
+ pptx.title = summaryData.meta?.title || 'Summary';
67
+ pptx.author = 'VoxFlow Studio';
68
+ pptx.layout = 'LAYOUT_WIDE';
69
+
70
+ const accent = '6366F1';
71
+ const bg = '0F172A';
72
+ const text = 'F1F5F9';
73
+ const muted = '94A3B8';
74
+
75
+ for (const point of summaryData.points) {
76
+ const s = pptx.addSlide();
77
+ s.background = { color: bg };
78
+ s.addText(point.title, {
79
+ x: 0.8, y: 0.5, w: '85%', fontSize: 32, bold: true,
80
+ color: text, fontFace: 'Arial',
81
+ });
82
+ s.addShape('rect', { x: 0.8, y: 1.3, w: 1.2, h: 0.04, fill: { color: accent } });
83
+
84
+ if (point.bullets?.length) {
85
+ const bulletText = point.bullets.map(b => ({
86
+ text: b,
87
+ options: { bullet: { code: '2022' }, fontSize: 18, color: text, breakLine: true },
88
+ }));
89
+ s.addText(bulletText, {
90
+ x: 0.8, y: 1.8, w: '85%', h: 3, fontFace: 'Arial', paraSpaceAfter: 10, valign: 'top',
91
+ });
92
+ }
93
+
94
+ // Time range indicator
95
+ const timeLabel = `${formatTime(point.startSec)} - ${formatTime(point.endSec)}`;
96
+ s.addText(timeLabel, {
97
+ x: 0.8, y: 4.8, w: 3, fontSize: 12, color: muted, fontFace: 'Arial',
98
+ });
99
+
100
+ if (point.narration) s.addNotes(point.narration);
101
+ }
102
+
103
+ const buffer = await pptx.write({ outputType: 'nodebuffer' });
104
+ fs.writeFileSync(outputPath, buffer);
105
+ return { path: outputPath, format: 'pptx', fallback: false };
106
+ }
107
+
108
+ function formatTime(sec) {
109
+ const m = Math.floor(sec / 60);
110
+ const s = Math.floor(sec % 60);
111
+ return `${m}:${s.toString().padStart(2, '0')}`;
112
+ }
113
+
114
+ // ─── Video composition via FFmpeg ───────────────────────────────────────────
115
+
116
+ /**
117
+ * Compose a summary video with PiP layout:
118
+ * - Background: blurred frame from original video (per point)
119
+ * - PiP (bottom-left): original video clip (clear, with person speaking)
120
+ * - Audio: AI TTS narration replacing original audio
121
+ *
122
+ * Layout:
123
+ * ┌──────────────────────────┐
124
+ * │ (blurred bg) │
125
+ * │ │
126
+ * │ ┌────────┐ │
127
+ * │ │ 原视频 │ │
128
+ * │ │ (人物) │ │
129
+ * │ └────────┘ │
130
+ * └──────────────────────────┘
131
+ */
132
+ async function composeVideo(originalVideo, points, ttsWavs, outputPath) {
133
+ const {
134
+ generateTitleCard, concatVideos, normalizeVideo, runCommand,
135
+ } = require('../core/ffmpeg');
136
+
137
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'voxflow-sumvideo-'));
138
+
139
+ // Probe original video resolution
140
+ let width = 1920, height = 1080;
141
+ try {
142
+ const { stdout } = await runCommand('ffprobe', [
143
+ '-v', 'quiet', '-select_streams', 'v:0',
144
+ '-show_entries', 'stream=width,height',
145
+ '-of', 'csv=p=0', path.resolve(originalVideo),
146
+ ]);
147
+ const [w, h] = stdout.trim().split(',').map(Number);
148
+ if (w && h) { width = w; height = h; }
149
+ } catch {}
150
+
151
+ const resolution = `${width}x${height}`;
152
+ const pipW = Math.round(width * 0.35); // PiP = 35% of frame width
153
+ const pipPad = Math.round(width * 0.025); // 2.5% padding
154
+ const segmentPaths = [];
155
+
156
+ try {
157
+ // 1. Title card (darkened first frame)
158
+ process.stdout.write(' [1] Title card... ');
159
+ const titlePath = path.join(tmpDir, 'title.mp4');
160
+ await generateTitleCard(titlePath, '', {
161
+ duration: 3, resolution, sourceVideo: originalVideo,
162
+ });
163
+ const titleNorm = path.join(tmpDir, 'title-norm.mp4');
164
+ await normalizeVideo(titlePath, titleNorm, { resolution });
165
+ segmentPaths.push(titleNorm);
166
+ console.log('OK');
167
+
168
+ // 2. Each point: PiP layout (blurred bg + clear PiP + TTS audio)
169
+ for (let i = 0; i < points.length; i++) {
170
+ const point = points[i];
171
+ process.stdout.write(` [${i + 2}] "${point.title}"... `);
172
+
173
+ const safeStart = Math.max(0, point.startSec);
174
+ const safeEnd = Math.min(point.endSec, point.startSec + 30);
175
+ const pipPath = path.join(tmpDir, `pip-${i}.mp4`);
176
+
177
+ // Build PiP: blurred full-screen background + clear small video in bottom-left
178
+ // Round pip dimensions to even numbers (required by libx264)
179
+ const pipH = Math.round(pipW * height / width / 2) * 2;
180
+ const evenPipW = Math.round(pipW / 2) * 2;
181
+ const pipY = height - pipH - pipPad;
182
+
183
+ const filterComplex = [
184
+ // Background: scale original to fill, heavy blur + darken
185
+ `[0:v]scale=${width}:${height},boxblur=25:5,eq=brightness=-0.3:saturation=0.5[bg]`,
186
+ // PiP: scale original to small size with rounded corners effect
187
+ `[0:v]scale=${evenPipW}:${pipH}[pip]`,
188
+ // Overlay PiP on blurred background (bottom-right)
189
+ `[bg][pip]overlay=${width - evenPipW - pipPad}:${pipY}[out]`,
190
+ ].join(';');
191
+
192
+ if (ttsWavs[i]) {
193
+ // With TTS: use TTS audio, ignore original audio
194
+ await runCommand('ffmpeg', [
195
+ '-ss', String(safeStart), '-to', String(safeEnd), '-i', path.resolve(originalVideo),
196
+ '-i', path.resolve(ttsWavs[i]),
197
+ '-filter_complex', filterComplex,
198
+ '-map', '[out]', '-map', '1:a:0',
199
+ '-c:v', 'libx264', '-preset', 'fast', '-crf', '23', '-pix_fmt', 'yuv420p',
200
+ '-c:a', 'aac', '-ar', '24000', '-ac', '1',
201
+ '-shortest',
202
+ '-y', pipPath,
203
+ ], { timeout: 300_000 });
204
+ } else {
205
+ // Without TTS: keep original audio
206
+ await runCommand('ffmpeg', [
207
+ '-ss', String(safeStart), '-to', String(safeEnd), '-i', path.resolve(originalVideo),
208
+ '-filter_complex', filterComplex,
209
+ '-map', '[out]', '-map', '0:a:0',
210
+ '-c:v', 'libx264', '-preset', 'fast', '-crf', '23', '-pix_fmt', 'yuv420p',
211
+ '-c:a', 'aac', '-ar', '24000', '-ac', '1',
212
+ '-shortest',
213
+ '-y', pipPath,
214
+ ], { timeout: 300_000 });
215
+ }
216
+
217
+ // Normalize for concat
218
+ const normPath = path.join(tmpDir, `norm-${i}.mp4`);
219
+ await normalizeVideo(pipPath, normPath, { resolution });
220
+ segmentPaths.push(normPath);
221
+ console.log('OK');
222
+ }
223
+
224
+ // 3. Closing card
225
+ process.stdout.write(' [last] Closing... ');
226
+ const closingPath = path.join(tmpDir, 'closing.mp4');
227
+ await generateTitleCard(closingPath, '', {
228
+ duration: 2, resolution, sourceVideo: originalVideo,
229
+ });
230
+ const closingNorm = path.join(tmpDir, 'closing-norm.mp4');
231
+ await normalizeVideo(closingPath, closingNorm, { resolution });
232
+ segmentPaths.push(closingNorm);
233
+ console.log('OK');
234
+
235
+ // 4. Concatenate
236
+ process.stdout.write(' Concatenating... ');
237
+ await concatVideos(segmentPaths, path.resolve(outputPath));
238
+ console.log('OK');
239
+
240
+ } finally {
241
+ try { fs.rmSync(tmpDir, { recursive: true, force: true }); } catch {}
242
+ }
243
+ }
244
+
245
+ // ─── TTS synthesis for a single text ────────────────────────────────────────
246
+
247
+ async function synthesizeTts(apiBase, token, text, voiceId, speed) {
248
+ let status, data;
249
+ try {
250
+ ({ status, data } = await request(`${apiBase}/api/tts/synthesize`, {
251
+ method: 'POST',
252
+ headers: {
253
+ 'Content-Type': 'application/json',
254
+ 'Authorization': `Bearer ${token}`,
255
+ },
256
+ }, { text, voiceId, speed, format: 'pcm', sampleRate: 24000 }));
257
+ } catch (err) {
258
+ throwNetworkError(err, apiBase);
259
+ }
260
+
261
+ if (status !== 200 || data.code !== 'success') {
262
+ throwApiError(status, data, 'TTS');
263
+ }
264
+
265
+ return Buffer.from(data.audio, 'base64');
266
+ }
267
+
268
+ // ─── Main command ───────────────────────────────────────────────────────────
269
+
270
+ async function summarize(opts) {
271
+ const sigintHandler = () => {
272
+ console.log('\n\nSummarize cancelled.');
273
+ process.exit(0);
274
+ };
275
+ process.on('SIGINT', sigintHandler);
276
+
277
+ try {
278
+ return await _summarize(opts);
279
+ } finally {
280
+ process.removeListener('SIGINT', sigintHandler);
281
+ }
282
+ }
283
+
284
+ async function _summarize(opts) {
285
+ const {
286
+ token,
287
+ api = API_BASE,
288
+ input,
289
+ text: inputText,
290
+ slideCount = SUMMARIZE_DEFAULTS.slides,
291
+ language = SUMMARIZE_DEFAULTS.language,
292
+ voice = SUMMARIZE_DEFAULTS.voice,
293
+ speed = SUMMARIZE_DEFAULTS.speed,
294
+ engine = SUMMARIZE_DEFAULTS.engine,
295
+ model,
296
+ tts = false,
297
+ video = false,
298
+ output: userOutput,
299
+ } = opts;
300
+
301
+ console.log('\n=== VoxFlow Summarize ===');
302
+
303
+ let transcript;
304
+ let totalQuota = 0;
305
+ const resolvedInput = input ? path.resolve(input) : null;
306
+
307
+ // ─── Step 1: Get transcript ──────────────────────────────────────────
308
+ if (inputText) {
309
+ console.log(`Input: text (${inputText.length} chars)`);
310
+ transcript = inputText;
311
+ } else if (input) {
312
+ console.log(`Input: ${path.basename(resolvedInput)}`);
313
+ process.stdout.write('[1] Transcribing audio... ');
314
+
315
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'voxflow-summarize-'));
316
+ const asrOutputPath = path.join(tmpDir, 'transcript.txt');
317
+
318
+ const asrResult = await asr({
319
+ token, api, input: resolvedInput,
320
+ format: 'txt', output: asrOutputPath,
321
+ engine, model,
322
+ mode: 'file',
323
+ });
324
+
325
+ transcript = fs.readFileSync(asrOutputPath, 'utf8');
326
+ totalQuota += asrResult.quotaUsed;
327
+ console.log(`${asrResult.captionCount} segments (${asrResult.mode})`);
328
+ try { fs.rmSync(tmpDir, { recursive: true, force: true }); } catch {}
329
+ } else {
330
+ throw new Error('Either --input <file> or --text <text> is required.');
331
+ }
332
+
333
+ if (!transcript.trim()) {
334
+ throw new Error('Transcript is empty. No audible speech detected.');
335
+ }
336
+
337
+ // ─── Step 2: LLM → structured points ─────────────────────────────────
338
+ process.stdout.write('[2] Extracting key points... ');
339
+
340
+ const llmResult = await chatCompletion({
341
+ apiBase: api, token,
342
+ messages: [
343
+ { role: 'system', content: SUMMARIZE_PROMPT },
344
+ {
345
+ role: 'user',
346
+ content: `Extract ${slideCount} key points from this transcript. Language: ${language}.\n\nTRANSCRIPT:\n${transcript.slice(0, 8000)}\n\nOutput JSON only:`,
347
+ },
348
+ ],
349
+ temperature: 0.3,
350
+ maxTokens: 4000,
351
+ });
352
+ totalQuota += 1;
353
+
354
+ let summaryData;
355
+ try {
356
+ summaryData = JSON.parse(llmResult.content.trim());
357
+ } catch {
358
+ const m = llmResult.content.match(/```(?:json)?\s*([\s\S]*?)```/);
359
+ if (m?.[1]) summaryData = JSON.parse(m[1].trim());
360
+ else throw new Error('Failed to parse summary JSON from LLM');
361
+ }
362
+
363
+ const points = summaryData.points || [];
364
+ console.log(`${points.length} points`);
365
+
366
+ // ─── Step 3: Generate PPTX ────────────────────────────────────────────
367
+ process.stdout.write('[3] Generating PPTX... ');
368
+ const baseName = input ? path.basename(resolvedInput, path.extname(resolvedInput)) : 'summary';
369
+ const outputDir = input ? path.dirname(resolvedInput) : process.cwd();
370
+ const pptxPath = userOutput
371
+ ? path.resolve(userOutput)
372
+ : path.resolve(outputDir, `${baseName}-summary.pptx`);
373
+
374
+ const pptxResult = await generatePptx(summaryData, pptxPath);
375
+ console.log(`OK (${pptxResult.format})`);
376
+
377
+ // ─── Step 4: TTS narrations ───────────────────────────────────────────
378
+ const ttsWavPaths = [];
379
+ if (video || tts) {
380
+ console.log('[4] Synthesizing narrations...');
381
+ const allPcm = [];
382
+
383
+ for (let i = 0; i < points.length; i++) {
384
+ const p = points[i];
385
+ if (!p.narration?.trim()) {
386
+ ttsWavPaths.push(null);
387
+ allPcm.push(createSilence(1, 24000));
388
+ continue;
389
+ }
390
+
391
+ process.stdout.write(` TTS [${i + 1}/${points.length}]... `);
392
+ const pcm = await synthesizeTts(api, token, p.narration, voice, speed);
393
+ totalQuota += 1;
394
+
395
+ // Save per-point WAV for video pipeline
396
+ if (video) {
397
+ const wavPath = path.join(os.tmpdir(), `voxflow-sum-tts-${i}.wav`);
398
+ const wavBuf = buildWav([pcm], 0);
399
+ fs.writeFileSync(wavPath, wavBuf.wav || wavBuf);
400
+ ttsWavPaths.push(wavPath);
401
+ }
402
+
403
+ allPcm.push(pcm);
404
+ allPcm.push(createSilence(0.5, 24000));
405
+ const durMs = (pcm.length / 48).toFixed(0);
406
+ console.log(`OK (${durMs}ms)`);
407
+ }
408
+
409
+ // Save combined narration WAV
410
+ if (tts) {
411
+ const narrationPath = pptxPath.replace(/\.(pptx|json)$/, '-narration.wav');
412
+ // allPcm already contains interleaved PCM + silence buffers, so use silenceSec=0
413
+ const wavBuf = buildWav(allPcm, 0);
414
+ fs.writeFileSync(narrationPath, wavBuf.wav || wavBuf);
415
+ console.log(` Narration: ${narrationPath}`);
416
+ }
417
+ }
418
+
419
+ // ─── Step 5: Video composition ────────────────────────────────────────
420
+ let videoPath = null;
421
+ if (video && resolvedInput) {
422
+ console.log('[5] Composing video...');
423
+ videoPath = pptxPath.replace(/\.(pptx|json)$/, '.mp4');
424
+
425
+ try {
426
+ await composeVideo(resolvedInput, points, ttsWavPaths, videoPath, {
427
+ title: summaryData.meta?.title || 'Summary',
428
+ });
429
+ } catch (err) {
430
+ console.log(` Video failed: ${err.message}`);
431
+ videoPath = null;
432
+ }
433
+
434
+ // Cleanup TTS temp files
435
+ ttsWavPaths.forEach(f => { if (f) try { fs.unlinkSync(f); } catch {} });
436
+ }
437
+
438
+ // ─── Summary ──────────────────────────────────────────────────────────
439
+ console.log('\n=== Done ===');
440
+ console.log(`Slides: ${pptxResult.path} (${points.length} points)`);
441
+ if (videoPath) console.log(`Video: ${videoPath}`);
442
+ console.log(`Quota: ${totalQuota} used`);
443
+
444
+ return { pptxPath: pptxResult.path, videoPath, slideCount: points.length, quotaUsed: totalQuota, summaryData };
445
+ }
446
+
447
+ // ─── CLI Handler ────────────────────────────────────────────────────────────
448
+
449
+ async function handle(args) {
450
+ const { parseFlag, parseIntFlag, parseFloatFlag, parseBoolFlag, runWithRetry } = require('../core/args');
451
+ const { getToken } = require('../core/auth');
452
+ const { API_BASE, SUMMARIZE_DEFAULTS: SUM_DEFS } = require('../core/config');
453
+
454
+ const fs = require('fs');
455
+ const path = require('path');
456
+ const api = parseFlag(args, '--api') || API_BASE;
457
+ const explicitToken = parseFlag(args, '--token');
458
+
459
+ const input = parseFlag(args, '--input');
460
+ const text = parseFlag(args, '--text');
461
+ const output = parseFlag(args, '--output', '-o');
462
+ const voice = parseFlag(args, '--voice') || SUM_DEFS.voice;
463
+ const speed = parseFloatFlag(args, '--speed') ?? SUM_DEFS.speed;
464
+ const slideCount = parseIntFlag(args, '--slides') ?? SUM_DEFS.slides;
465
+ const language = parseFlag(args, '--lang') || SUM_DEFS.language;
466
+ const engine = parseFlag(args, '--engine') || SUM_DEFS.engine;
467
+ const model = parseFlag(args, '--model');
468
+ const tts = parseBoolFlag(args, '--tts');
469
+ const video = parseBoolFlag(args, '--video');
470
+ const scheme = parseFlag(args, '--scheme') || 'aurora';
471
+
472
+ if (!input && !text) {
473
+ console.error('Error: --input <file> or --text <text> is required.\nExample: voxflow summarize --input lecture.mp4');
474
+ process.exit(1);
475
+ }
476
+
477
+ if (input) {
478
+ const resolved = path.resolve(input);
479
+ if (!fs.existsSync(resolved)) {
480
+ console.error(`Error: File not found: ${resolved}`);
481
+ process.exit(1);
482
+ }
483
+ }
484
+
485
+ if (speed !== undefined && (isNaN(speed) || speed < 0.5 || speed > 2.0)) {
486
+ console.error(`Error: --speed must be between 0.5 and 2.0`);
487
+ process.exit(1);
488
+ }
489
+
490
+ const token = explicitToken || await getToken();
491
+ if (!token) {
492
+ console.error('Not logged in. Run: voxflow login');
493
+ process.exit(1);
494
+ }
495
+
496
+ const opts = {
497
+ token, api, input, text, output, voice, speed, slideCount, language,
498
+ engine, model, tts, video, scheme,
499
+ };
500
+
501
+ await runWithRetry(summarize, opts, api, explicitToken);
502
+ }
503
+
504
+ const meta = {
505
+ summarize: {
506
+ usage: '<--input|--text> [opts]',
507
+ description: 'Summarize video/audio/text into presentation slides (PPTX)',
508
+ options: [
509
+ `--input <file> Input video/audio file → ASR + summarize`,
510
+ `--text <text> Direct text input (skip ASR)`,
511
+ `--slides <n> Number of slides, 4-12 (default: ${SUMMARIZE_DEFAULTS.slides})`,
512
+ `--lang <code> Output language: en, zh, ja, etc. (default: ${SUMMARIZE_DEFAULTS.language})`,
513
+ `--engine <engine> ASR engine: auto, local, cloud (default: ${SUMMARIZE_DEFAULTS.engine})`,
514
+ `--model <model> Whisper model for local ASR: tiny, base, small, medium, large`,
515
+ `--tts Generate TTS narration audio for each slide`,
516
+ `--video Also render an MP4 video (requires remotion-cards/ + Remotion)`,
517
+ `--scheme <name> Video visual scheme: noir, neon, editorial, aurora (default), brutalist`,
518
+ `--voice <id> TTS voice ID (default: ${SUMMARIZE_DEFAULTS.voice})`,
519
+ `--speed <n> TTS speed 0.5-2.0 (default: ${SUMMARIZE_DEFAULTS.speed})`,
520
+ `--output <path> Output PPTX path (default: <input>-summary.pptx)`,
521
+ ],
522
+ examples: [
523
+ 'voxflow summarize --input lecture.mp4',
524
+ 'voxflow summarize --input meeting.mp4 --lang zh --slides 10',
525
+ 'voxflow summarize --input podcast.mp3 --engine local --tts',
526
+ 'voxflow summarize --input lecture.mp4 --video --scheme aurora',
527
+ 'voxflow summarize --text "长篇文章内容..." --slides 6 --lang zh',
528
+ ],
529
+ },
530
+ };
531
+
532
+ module.exports = { summarize, handle, meta };