/* Step before building: * 1. Copy onnxruntime-node/bin to out/ * 2. Modify onnxruntime-node/dist/binding.js for bun * 3. Profit */ import os from "node:os"; import { $ } from "bun"; import chalk from "chalk"; import { KokoroTTS, TextSplitterStream } from "kokoro-js"; const model_id = "onnx-community/Kokoro-82M-v1.0-ONNX"; const tts = await KokoroTTS.from_pretrained(model_id, { dtype: "fp32", // Options: "fp32", "fp16", "q8", "q4", "q4f16" device: "cpu", // Options: "wasm", "webgpu" (web) or "cpu" (node). If using "webgpu", we recommend using dtype="fp32". }); const stream = new TextSplitterStream(); const input = await $`wl-paste`.text(); if (!input) { console.error("No input"); process.exit(1); } stream.push(input); await $`rm -r ${os.homedir()}/.aitts/`.nothrow(); await $`mkdir ${os.homedir()}/.aitts/`.nothrow(); let fileId = 0; let buffer = ""; for (const text of stream) { buffer += ` ${text}`; if (buffer.length < 100) continue; console.log(`${chalk.blue(fileId)}:${buffer}`); const audio = await tts.generate(buffer, { voice: "af_heart", speed: 1.2, }); const file = `${os.homedir()}/.aitts/${fileId}.wav`; audio.save(file); fileId++; buffer = ""; } if (buffer) { console.log(`${chalk.blue(fileId)}:${buffer}`); const audio = await tts.generate(buffer, { voice: "af_heart", speed: 1.2, }); const file = `${os.homedir()}/.aitts/${fileId}.wav`; audio.save(file); } console.log(chalk.yellow("Combine wav file with sox...")); await $`sox ${os.homedir()}/.aitts/* ${os.homedir()}/.aitts/all.wav`; console.log(chalk.green("Success: ~/.aitts/all.wav")); console.log(chalk.yellow("Listening with mpv...")); await Bun.spawn({ cmd: ["mpv", `${os.homedir()}/.aitts/all.wav`], stdout: "inherit", }).exited; console.log(chalk.green("Have a nice day!"));