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.
- package/README.md +34 -0
- package/bin/voxflow.js +27 -0
- package/dist/index.js +1 -1
- package/dist/remotion-bundle/02a2fb2eb80bc7bf.woff2 +0 -0
- package/dist/remotion-bundle/052ca5351e5e06ba.woff2 +0 -0
- package/dist/remotion-bundle/05853dd28f4019cb.woff2 +0 -0
- package/dist/remotion-bundle/072ead3737f7c0d0.woff2 +0 -0
- package/dist/remotion-bundle/07d4248613c86a2e.woff2 +0 -0
- package/dist/remotion-bundle/0884a5c2d1d2d99b.woff2 +0 -0
- package/dist/remotion-bundle/0b0e185b2752095e.woff2 +0 -0
- package/dist/remotion-bundle/0e66c11bde067d91.woff2 +0 -0
- package/dist/remotion-bundle/0f7794cfba2c5d21.woff2 +0 -0
- package/dist/remotion-bundle/0fdbae5a4365783a.woff2 +0 -0
- package/dist/remotion-bundle/112.bundle.js +11 -0
- package/dist/remotion-bundle/112.bundle.js.map +1 -0
- package/dist/remotion-bundle/113.bundle.js +11 -0
- package/dist/remotion-bundle/113.bundle.js.map +1 -0
- package/dist/remotion-bundle/119cae0c4c16f7ed.woff2 +0 -0
- package/dist/remotion-bundle/14725f649fd1e78c.woff2 +0 -0
- package/dist/remotion-bundle/14abe9e3f95f7888.woff2 +0 -0
- package/dist/remotion-bundle/163.bundle.js +14678 -0
- package/dist/remotion-bundle/163.bundle.js.map +1 -0
- package/dist/remotion-bundle/1808c54072bf6d14.woff2 +0 -0
- package/dist/remotion-bundle/18948bec3e3012fe.woff2 +0 -0
- package/dist/remotion-bundle/1a661c60d0fc84fc.woff2 +0 -0
- package/dist/remotion-bundle/1af94941e1bc7e1e.woff2 +0 -0
- package/dist/remotion-bundle/1bee0219595f606c.woff2 +0 -0
- package/dist/remotion-bundle/1bfd5da7ce9d4ec4.woff2 +0 -0
- package/dist/remotion-bundle/1c158d56f1884f3f.woff2 +0 -0
- package/dist/remotion-bundle/1cf5e88e667610eb.woff2 +0 -0
- package/dist/remotion-bundle/1d431bd10f53c481.woff2 +0 -0
- package/dist/remotion-bundle/1d701a81a7670db2.woff2 +0 -0
- package/dist/remotion-bundle/1da0fecad4240f16.woff2 +0 -0
- package/dist/remotion-bundle/1ed14d3d0c5c63fe.woff2 +0 -0
- package/dist/remotion-bundle/1edfecf40e586f53.woff2 +0 -0
- package/dist/remotion-bundle/1f479711bc34b054.woff +0 -0
- package/dist/remotion-bundle/1f86e54a0ff5fcd1.woff2 +0 -0
- package/dist/remotion-bundle/2043ea87d9aabd11.woff2 +0 -0
- package/dist/remotion-bundle/20563c39ee8a0e40.woff2 +0 -0
- package/dist/remotion-bundle/20c231590fd12c44.woff2 +0 -0
- package/dist/remotion-bundle/20ce61713f754c07.woff2 +0 -0
- package/dist/remotion-bundle/21eb9306fce24bb1.woff2 +0 -0
- package/dist/remotion-bundle/244bf71c0cc851af.woff2 +0 -0
- package/dist/remotion-bundle/274d4cfc02bffbcb.woff2 +0 -0
- package/dist/remotion-bundle/275.bundle.js +21 -0
- package/dist/remotion-bundle/275.bundle.js.map +1 -0
- package/dist/remotion-bundle/2958f540b39513dc.woff2 +0 -0
- package/dist/remotion-bundle/2a168b98fd97722e.woff2 +0 -0
- package/dist/remotion-bundle/2d1f6373937ab55f.woff2 +0 -0
- package/dist/remotion-bundle/2d213ae47ff6daa9.woff2 +0 -0
- package/dist/remotion-bundle/2e4b1f04fcd05047.woff2 +0 -0
- package/dist/remotion-bundle/304170d98f4c4563.woff2 +0 -0
- package/dist/remotion-bundle/30d02e136e7a5642.woff2 +0 -0
- package/dist/remotion-bundle/3135562b52a714cd.woff2 +0 -0
- package/dist/remotion-bundle/313713af2c8144e9.woff2 +0 -0
- package/dist/remotion-bundle/325fa4108d2285b9.woff2 +0 -0
- package/dist/remotion-bundle/338e927ed3345e0c.woff2 +0 -0
- package/dist/remotion-bundle/35fc6b190365bc17.woff2 +0 -0
- package/dist/remotion-bundle/37a51f1122d4efc5.woff2 +0 -0
- package/dist/remotion-bundle/39a4d63e02736f5e.woff2 +0 -0
- package/dist/remotion-bundle/3a00e0d62dfc4171.woff2 +0 -0
- package/dist/remotion-bundle/3a6955e6561affe1.woff2 +0 -0
- package/dist/remotion-bundle/3c573945aef49b89.woff2 +0 -0
- package/dist/remotion-bundle/3cdbfbfa23b516a5.woff2 +0 -0
- package/dist/remotion-bundle/3e42f85a9e64ca8a.woff2 +0 -0
- package/dist/remotion-bundle/3e83eaf1ec859415.woff2 +0 -0
- package/dist/remotion-bundle/3f3c8c90de1250ee.woff2 +0 -0
- package/dist/remotion-bundle/434.bundle.js +205 -0
- package/dist/remotion-bundle/434.bundle.js.map +1 -0
- package/dist/remotion-bundle/44ffc6ca4d781692.woff2 +0 -0
- package/dist/remotion-bundle/4670d9c4580b09eb.woff2 +0 -0
- package/dist/remotion-bundle/479756881b302824.woff2 +0 -0
- package/dist/remotion-bundle/481b82134bfa9c82.woff2 +0 -0
- package/dist/remotion-bundle/48d27029626f4328.woff2 +0 -0
- package/dist/remotion-bundle/49b7b2a30329c511.woff2 +0 -0
- package/dist/remotion-bundle/4c8b25a1a9337045.woff2 +0 -0
- package/dist/remotion-bundle/4cba14788ca9259b.woff2 +0 -0
- package/dist/remotion-bundle/4cd6c589c004a6a7.woff2 +0 -0
- package/dist/remotion-bundle/4cd8d79c1021608d.woff2 +0 -0
- package/dist/remotion-bundle/4d8fa99b3f00f9f0.woff2 +0 -0
- package/dist/remotion-bundle/4e7805a643f86d53.woff2 +0 -0
- package/dist/remotion-bundle/4ff91be454542e3f.woff2 +0 -0
- package/dist/remotion-bundle/504cbcba1f63591b.woff2 +0 -0
- package/dist/remotion-bundle/5202d792e5791d6c.woff2 +0 -0
- package/dist/remotion-bundle/534db5ad4770cc1d.woff2 +0 -0
- package/dist/remotion-bundle/53b9568eb85f866b.woff2 +0 -0
- package/dist/remotion-bundle/543ad386ca171de9.woff2 +0 -0
- package/dist/remotion-bundle/54798e55bbf7976e.woff2 +0 -0
- package/dist/remotion-bundle/580.bundle.js +11 -0
- package/dist/remotion-bundle/580.bundle.js.map +1 -0
- package/dist/remotion-bundle/58d174d1193af6d1.woff2 +0 -0
- package/dist/remotion-bundle/591d29ff3ff53c80.woff2 +0 -0
- package/dist/remotion-bundle/5c28c4f4824383c6.woff2 +0 -0
- package/dist/remotion-bundle/5da9740d2ce894c8.woff2 +0 -0
- package/dist/remotion-bundle/6197735364642360.woff2 +0 -0
- package/dist/remotion-bundle/6265a4335724080f.woff2 +0 -0
- package/dist/remotion-bundle/633f5e4f6394daa7.woff2 +0 -0
- package/dist/remotion-bundle/637d95ace6a69c49.woff2 +0 -0
- package/dist/remotion-bundle/648e04a04dacff8f.woff2 +0 -0
- package/dist/remotion-bundle/64a6e83045a008b2.woff2 +0 -0
- package/dist/remotion-bundle/651.bundle.js +11 -0
- package/dist/remotion-bundle/651.bundle.js.map +1 -0
- package/dist/remotion-bundle/65e2a988c070facc.woff2 +0 -0
- package/dist/remotion-bundle/66a2f6ce5cc69105.woff2 +0 -0
- package/dist/remotion-bundle/690.bundle.js +3479 -0
- package/dist/remotion-bundle/690.bundle.js.map +1 -0
- package/dist/remotion-bundle/690ff55252ca715d.woff2 +0 -0
- package/dist/remotion-bundle/6a01a1cff49314fc.woff2 +0 -0
- package/dist/remotion-bundle/6cbc32670982986c.woff2 +0 -0
- package/dist/remotion-bundle/6d3cc42ae547f454.woff2 +0 -0
- package/dist/remotion-bundle/6d8f4cfa1ddc0830.woff2 +0 -0
- package/dist/remotion-bundle/6e4d7c6ae65e2dc3.woff2 +0 -0
- package/dist/remotion-bundle/6e86418bbcefb2e8.woff2 +0 -0
- package/dist/remotion-bundle/6ee02884b29cf7fb.woff2 +0 -0
- package/dist/remotion-bundle/6f436a74c9e3252c.woff2 +0 -0
- package/dist/remotion-bundle/78c8022f1657618b.woff2 +0 -0
- package/dist/remotion-bundle/7c5444169792bca4.woff2 +0 -0
- package/dist/remotion-bundle/7c86bddd9d997212.woff2 +0 -0
- package/dist/remotion-bundle/7e1284684767f584.woff2 +0 -0
- package/dist/remotion-bundle/7e81c17522d182b2.woff2 +0 -0
- package/dist/remotion-bundle/7eb87be198f7858c.woff2 +0 -0
- package/dist/remotion-bundle/8060c928f948aab5.woff2 +0 -0
- package/dist/remotion-bundle/80bc9dfbea2b35ae.woff2 +0 -0
- package/dist/remotion-bundle/811b83f69963bb48.woff2 +0 -0
- package/dist/remotion-bundle/813.bundle.js +117511 -0
- package/dist/remotion-bundle/813.bundle.js.map +1 -0
- package/dist/remotion-bundle/84df492e349f82e9.woff2 +0 -0
- package/dist/remotion-bundle/8501bfd73eb36f2b.woff2 +0 -0
- package/dist/remotion-bundle/854236a8376093fe.woff2 +0 -0
- package/dist/remotion-bundle/8571d74529082753.woff2 +0 -0
- package/dist/remotion-bundle/860bf44f8e6f4b5d.woff2 +0 -0
- package/dist/remotion-bundle/879.bundle.js +64 -0
- package/dist/remotion-bundle/879.bundle.js.map +1 -0
- package/dist/remotion-bundle/887dd482f848d56f.woff2 +0 -0
- package/dist/remotion-bundle/89b2132e85fbbb5a.woff2 +0 -0
- package/dist/remotion-bundle/8ba60d6c306010c2.woff2 +0 -0
- package/dist/remotion-bundle/8c7c4dadea897806.woff2 +0 -0
- package/dist/remotion-bundle/8c943f9999706f61.woff2 +0 -0
- package/dist/remotion-bundle/8f2a718c90575cc9.woff2 +0 -0
- package/dist/remotion-bundle/906b6edb3e1772c9.woff2 +0 -0
- package/dist/remotion-bundle/930ff9daccdf14eb.woff2 +0 -0
- package/dist/remotion-bundle/934db2f1c403c4d0.woff2 +0 -0
- package/dist/remotion-bundle/938.bundle.js +451 -0
- package/dist/remotion-bundle/938.bundle.js.map +1 -0
- package/dist/remotion-bundle/967.bundle.js +4462 -0
- package/dist/remotion-bundle/967.bundle.js.map +1 -0
- package/dist/remotion-bundle/9684a1093d3c02ce.woff2 +0 -0
- package/dist/remotion-bundle/973dcd0faa6116cc.woff2 +0 -0
- package/dist/remotion-bundle/9745400694e76cd8.woff2 +0 -0
- package/dist/remotion-bundle/999ef957bed3bdca.woff2 +0 -0
- package/dist/remotion-bundle/99a3d67c8b0f43e3.woff2 +0 -0
- package/dist/remotion-bundle/a0586c3e03127283.woff2 +0 -0
- package/dist/remotion-bundle/a0eb654fdae46269.woff2 +0 -0
- package/dist/remotion-bundle/a20e35d3b08f7994.woff2 +0 -0
- package/dist/remotion-bundle/a2dcaced7c8c25ab.woff2 +0 -0
- package/dist/remotion-bundle/a79255a972a2681a.woff2 +0 -0
- package/dist/remotion-bundle/a804b352cb9fec1a.woff2 +0 -0
- package/dist/remotion-bundle/aae7117164e1eabc.woff2 +0 -0
- package/dist/remotion-bundle/affd121385d0442d.woff2 +0 -0
- package/dist/remotion-bundle/b19a6083987ee0d7.woff2 +0 -0
- package/dist/remotion-bundle/b1b2bd04d8637981.woff2 +0 -0
- package/dist/remotion-bundle/b2c07f341486be87.woff2 +0 -0
- package/dist/remotion-bundle/b33d8f82e575c4ce.woff2 +0 -0
- package/dist/remotion-bundle/b366c0bed35ef491.woff2 +0 -0
- package/dist/remotion-bundle/b41e857ec1b85642.woff2 +0 -0
- package/dist/remotion-bundle/b420bb34ccf23e7f.woff2 +0 -0
- package/dist/remotion-bundle/b4f7bf4efb0c0ccf.woff2 +0 -0
- package/dist/remotion-bundle/b60fe5eca03cff93.woff2 +0 -0
- package/dist/remotion-bundle/b6bd31a336e64bce.woff2 +0 -0
- package/dist/remotion-bundle/b6d2befba3dfefeb.woff2 +0 -0
- package/dist/remotion-bundle/b75f39ab06c43bf4.woff2 +0 -0
- package/dist/remotion-bundle/b77880e8c413d4fd.woff2 +0 -0
- package/dist/remotion-bundle/b7e38ec441e4a77a.woff2 +0 -0
- package/dist/remotion-bundle/b83baa383ff0bf2b.woff2 +0 -0
- package/dist/remotion-bundle/b9ad7b6c0a11450a.woff2 +0 -0
- package/dist/remotion-bundle/baf84486e8ae3aaf.woff2 +0 -0
- package/dist/remotion-bundle/bc047b1f6869cffa.woff2 +0 -0
- package/dist/remotion-bundle/bf4f3ac6e93f33aa.woff2 +0 -0
- package/dist/remotion-bundle/bf6835ffec5897a2.woff2 +0 -0
- package/dist/remotion-bundle/bf8885f581eb1724.woff2 +0 -0
- package/dist/remotion-bundle/bundle.js +83376 -0
- package/dist/remotion-bundle/bundle.js.map +1 -0
- package/dist/remotion-bundle/c03f046bccd789d0.woff2 +0 -0
- package/dist/remotion-bundle/c0bb1f8962b73bc3.woff2 +0 -0
- package/dist/remotion-bundle/c1003f9a7db6e1cf.woff2 +0 -0
- package/dist/remotion-bundle/c15d83fb1e199515.woff2 +0 -0
- package/dist/remotion-bundle/c28e7e5d310f73ef.woff2 +0 -0
- package/dist/remotion-bundle/c2b840274db78aea.woff2 +0 -0
- package/dist/remotion-bundle/c3000e3299d4e45f.woff2 +0 -0
- package/dist/remotion-bundle/c83ce886e5288510.woff2 +0 -0
- package/dist/remotion-bundle/c87a5a64d4ac0918.woff2 +0 -0
- package/dist/remotion-bundle/c8a7e0d049e965fa.woff2 +0 -0
- package/dist/remotion-bundle/c949a35d3a3b1faf.woff2 +0 -0
- package/dist/remotion-bundle/c9618c9b9ac2bc78.woff2 +0 -0
- package/dist/remotion-bundle/ca3add3b84152d5b.woff2 +0 -0
- package/dist/remotion-bundle/cad9dd036408d707.woff2 +0 -0
- package/dist/remotion-bundle/cbb24916619df439.woff2 +0 -0
- package/dist/remotion-bundle/cc054f0b5514e177.woff2 +0 -0
- package/dist/remotion-bundle/ccc248ed9312bc71.woff2 +0 -0
- package/dist/remotion-bundle/cd9d623aa07af925.woff2 +0 -0
- package/dist/remotion-bundle/ce2ba7a321bd1247.woff2 +0 -0
- package/dist/remotion-bundle/cf72455f79a29b14.woff2 +0 -0
- package/dist/remotion-bundle/d267cbfefab452ac.woff2 +0 -0
- package/dist/remotion-bundle/d435cff46a64955f.woff +0 -0
- package/dist/remotion-bundle/d494d07f67e363f6.woff2 +0 -0
- package/dist/remotion-bundle/d7aa0cc1fa47bf38.woff2 +0 -0
- package/dist/remotion-bundle/d7c5ca93d885160a.woff2 +0 -0
- package/dist/remotion-bundle/d855d3e252db74e2.woff2 +0 -0
- package/dist/remotion-bundle/d8f13d47f02f82c2.woff2 +0 -0
- package/dist/remotion-bundle/d9567cce2ee11019.woff2 +0 -0
- package/dist/remotion-bundle/db8d4456fc75dd86.woff +0 -0
- package/dist/remotion-bundle/dc274628378c47ee.woff2 +0 -0
- package/dist/remotion-bundle/dc3e06947bb69903.woff2 +0 -0
- package/dist/remotion-bundle/dd67040ac3b6d523.woff2 +0 -0
- package/dist/remotion-bundle/e0b04bd488f953f4.woff2 +0 -0
- package/dist/remotion-bundle/e2a572ff95089370.woff2 +0 -0
- package/dist/remotion-bundle/e2e18a86b1c2b0cc.woff2 +0 -0
- package/dist/remotion-bundle/e3a78ee2fc9c6931.woff2 +0 -0
- package/dist/remotion-bundle/e654c9d547605a9f.woff2 +0 -0
- package/dist/remotion-bundle/e67a3a64c129927c.woff2 +0 -0
- package/dist/remotion-bundle/e6be28b4203cd6ce.woff2 +0 -0
- package/dist/remotion-bundle/e841907ad9b0a191.woff +0 -0
- package/dist/remotion-bundle/e889d1541c69fffa.woff2 +0 -0
- package/dist/remotion-bundle/e88ef8c76373a9e2.woff2 +0 -0
- package/dist/remotion-bundle/e9c72f4bc37defef.woff2 +0 -0
- package/dist/remotion-bundle/e9e35f863403a255.woff2 +0 -0
- package/dist/remotion-bundle/eb23b37b009375da.woff2 +0 -0
- package/dist/remotion-bundle/ee1342b741625721.woff2 +0 -0
- package/dist/remotion-bundle/f07da88543a57ec9.woff2 +0 -0
- package/dist/remotion-bundle/f522982115306f8a.woff2 +0 -0
- package/dist/remotion-bundle/f8449bd864e6d8bc.woff2 +0 -0
- package/dist/remotion-bundle/f906dd5bd95ff9ab.woff2 +0 -0
- package/dist/remotion-bundle/f9e9e9413e3c38bb.woff2 +0 -0
- package/dist/remotion-bundle/fa5a5b16280994a8.woff2 +0 -0
- package/dist/remotion-bundle/favicon.ico +0 -0
- package/dist/remotion-bundle/fb19c0517725599b.woff2 +0 -0
- package/dist/remotion-bundle/fcaf24232f684b9b.woff2 +0 -0
- package/dist/remotion-bundle/fe09e084a3eea8cf.woff2 +0 -0
- package/dist/remotion-bundle/ff38d5317df7345a.woff2 +0 -0
- package/dist/remotion-bundle/ffe7ea1ea08f455a.woff2 +0 -0
- package/dist/remotion-bundle/index.html +49 -0
- package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaomei/communication/0.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaomei/communication/1.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaomei/communication/2.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaomei/communication/3.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaoxin/career/0.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaoxin/career/1.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaoxin/career/2.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaoxin/career/3.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaoyue/parenting/0.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaoyue/parenting/1.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaoyue/parenting/2.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaoyue/parenting/3.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/male-kefu-xiaoxu/time-trap/0.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/male-kefu-xiaoxu/time-trap/1.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/male-kefu-xiaoxu/time-trap/2.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/male-kefu-xiaoxu/time-trap/3.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/cognition/0.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/cognition/1.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/cognition/2.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/cognition/3.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/growth/0.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/growth/1.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/growth/2.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/growth/3.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/parenting/0.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/parenting/1.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/parenting/2.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/parenting/3.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/soothing/0.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/soothing/1.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/soothing/2.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/soothing/3.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-female-R2s4N9qJ/cognition/0.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-female-R2s4N9qJ/cognition/1.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-female-R2s4N9qJ/cognition/2.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-female-R2s4N9qJ/cognition/3.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-male-Bk7vD3xP/decision/0.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-male-Bk7vD3xP/decision/1.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-male-Bk7vD3xP/decision/2.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-male-Bk7vD3xP/decision/3.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-male-W1tH9jVc/manager/0.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-male-W1tH9jVc/manager/1.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-male-W1tH9jVc/manager/2.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-male-W1tH9jVc/manager/3.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-male-W1tH9jVc/manager/4.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-male-s5NqE0rZ/founder/0.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-male-s5NqE0rZ/founder/1.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-male-s5NqE0rZ/founder/2.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-male-s5NqE0rZ/founder/3.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/career-advice/0.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/career-advice/1.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/career-advice/2.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/career-advice/3.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/career-advice/4.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/founder-lesson/0.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/founder-lesson/1.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/founder-lesson/2.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/founder-lesson/3.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/founder-lesson/4.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/incident-review/0.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/incident-review/1.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/incident-review/2.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/incident-review/3.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/incident-review/4.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/learning-loop/0.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/learning-loop/1.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/learning-loop/2.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/learning-loop/3.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/learning-loop/4.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/meeting-closure/0.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/meeting-closure/1.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/meeting-closure/2.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/meeting-closure/3.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/product-update/0.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/product-update/1.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/product-update/2.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/product-update/3.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/research-reading/0.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/research-reading/1.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/research-reading/2.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/research-reading/3.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/sales-enablement/0.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/sales-enablement/1.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/sales-enablement/2.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/sales-enablement/3.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/sales-enablement/4.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/ai-life/card-0.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/ai-life/card-1.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/ai-life/card-2.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/ai-life/card-3.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/ai-life/card-4.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/ai-life/card-5.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/coffee-science/card-0.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/coffee-science/card-1.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/coffee-science/card-2.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/coffee-science/card-3.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/coffee-science/card-4.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/coffee-science/card-5.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/coffee-science/card-6.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/reading-secrets/card-0.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/reading-secrets/card-1.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/reading-secrets/card-2.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/reading-secrets/card-3.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/reading-secrets/card-4.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/reading-secrets/card-5.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/reading-secrets/card-6.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/remote-work/card-0.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/remote-work/card-1.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/remote-work/card-2.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/remote-work/card-3.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/remote-work/card-4.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/remote-work/card-5.mp3 +0 -0
- package/dist/remotion-bundle/source-map-helper.wasm +0 -0
- package/lib/cli.js +270 -0
- package/lib/commands/_registry.js +48 -0
- package/lib/commands/add.js +242 -0
- package/lib/commands/asr/azure-transcribe.js +336 -0
- package/lib/commands/asr/cloud-transcribe.js +384 -0
- package/lib/commands/asr/helpers.js +76 -0
- package/lib/commands/asr/index.js +236 -0
- package/lib/commands/asr/local-transcribe.js +125 -0
- package/lib/commands/asr-jobs.js +257 -0
- package/lib/commands/asr.js +11 -0
- package/lib/commands/auth-cmds.js +358 -0
- package/lib/commands/dub.js +542 -0
- package/lib/commands/explain.js +512 -0
- package/lib/commands/feedback.js +152 -0
- package/lib/commands/image.js +207 -0
- package/lib/commands/mcp-key.js +166 -0
- package/lib/commands/narrate.js +639 -0
- package/lib/commands/picstory-templates.js +276 -0
- package/lib/commands/picstory.js +547 -0
- package/lib/commands/podcast/dialogue.js +109 -0
- package/lib/commands/podcast/generate.js +127 -0
- package/lib/commands/podcast/index.js +561 -0
- package/lib/commands/podcast/synthesize.js +188 -0
- package/lib/commands/podcast.js +11 -0
- package/lib/commands/present.js +519 -0
- package/lib/commands/publish.js +415 -0
- package/lib/commands/skills.js +473 -0
- package/lib/commands/slice-render.js +282 -0
- package/lib/commands/slice-stage.js +264 -0
- package/lib/commands/slice.js +346 -0
- package/lib/commands/slides/constants.js +108 -0
- package/lib/commands/slides/html-renderer.js +338 -0
- package/lib/commands/slides/index.js +345 -0
- package/lib/commands/slides.js +11 -0
- package/lib/commands/story.js +302 -0
- package/lib/commands/summarize.js +532 -0
- package/lib/commands/synthesize.js +261 -0
- package/lib/commands/translate.js +593 -0
- package/lib/commands/upgrade.js +249 -0
- package/lib/commands/video-translate.js +577 -0
- package/lib/commands/voices.js +292 -0
- package/lib/core/agent-env.js +104 -0
- package/lib/core/args.js +107 -0
- package/lib/core/asr-client.js +448 -0
- package/lib/core/asr-jobs-client.js +126 -0
- package/lib/core/asr-jobs-store.js +105 -0
- package/lib/core/asr-r2-upload.js +181 -0
- package/lib/core/asr-upload.js +132 -0
- package/lib/core/audio-extract.js +150 -0
- package/lib/core/audio.js +219 -0
- package/lib/core/auth.js +880 -0
- package/lib/core/config.js +197 -0
- package/lib/core/feedback.js +64 -0
- package/lib/core/ffmpeg.js +476 -0
- package/lib/core/http.js +188 -0
- package/lib/core/image-client.js +55 -0
- package/lib/core/intent-params.js +11 -0
- package/lib/core/llm-client.js +76 -0
- package/lib/core/logger.js +208 -0
- package/lib/core/mic-recorder.js +182 -0
- package/lib/core/pause-markers.js +94 -0
- package/lib/core/podcast-pacing.js +118 -0
- package/lib/core/spinner.js +33 -0
- package/lib/core/srt.js +394 -0
- package/lib/core/telemetry.js +100 -0
- package/lib/core/timeline.js +92 -0
- package/lib/core/tts-synthesizer.js +70 -0
- package/lib/core/update-check.js +185 -0
- package/lib/core/url-download.js +148 -0
- package/lib/core/whisper-local.js +279 -0
- package/lib/internal/deck-validator.js +488 -0
- package/lib/internal/slice-themes.json +370 -0
- package/lib/stage-core/cloud-render.js +170 -0
- package/lib/stage-core/deck-format.js +133 -0
- package/lib/stage-core/edit-prompt.js +104 -0
- package/lib/stage-core/event-bus.js +31 -0
- package/lib/stage-core/port.js +46 -0
- package/lib/stage-core/server.js +352 -0
- package/lib/stage-core/snapshot-store.js +198 -0
- package/lib/stage-core/watcher.js +106 -0
- package/lib/stage-ui/slice/template.js +1672 -0
- package/package.json +9 -4
- package/skills/.claude-plugin/marketplace.json +22 -0
- package/skills/.claude-plugin/plugin.json +25 -0
- package/skills/LICENSE +21 -0
- package/skills/README.md +120 -0
- package/skills/hub/SKILL.md +317 -0
- package/skills/podcast/SKILL.md +146 -0
- package/skills/slice/SKILL.md +205 -0
- package/skills/slice/agents/openai.yaml +4 -0
- package/skills/slice/references/deck-schema.md +183 -0
- package/skills/slice/references/example-decks.md +108 -0
- package/skills/slice/references/themes.md +172 -0
- package/skills/transcribe/SKILL.md +473 -0
- package/skills/video/SKILL.md +261 -0
- package/skills/voxflow-slice/SKILL.md +271 -0
- package/skills/voxflow-slice/examples/article.md +13 -0
- package/skills/voxflow-slice/examples/expected-deck.json +39 -0
- 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
|
+
};
|