refactor: stop buffering text and start streaming asap

This commit is contained in:
mitchell 2026-04-22 22:06:50 -04:00
parent 9c2c31be96
commit a6472f2075

View file

@ -3,14 +3,14 @@
* 2. Modify onnxruntime-node/dist/binding.js for bun * 2. Modify onnxruntime-node/dist/binding.js for bun
* 3. Profit */ * 3. Profit */
import os from "node:os"; import os from "node:os";
import { $ } from "bun"; import { $, which } from "bun";
import chalk from "chalk"; import chalk from "chalk";
import { KokoroTTS, TextSplitterStream } from "kokoro-js"; import { KokoroTTS, TextSplitterStream } from "kokoro-js";
const model_id = "onnx-community/Kokoro-82M-v1.0-ONNX"; const model_id = "onnx-community/Kokoro-82M-v1.0-ONNX";
const tts = await KokoroTTS.from_pretrained(model_id, { const tts = await KokoroTTS.from_pretrained(model_id, {
dtype: "fp32", // Options: "fp32", "fp16", "q8", "q4", "q4f16" dtype: "fp32", // fp32 and q8 work best; fp16 results in silent segments
device: "cpu", // Options: "wasm", "webgpu" (web) or "cpu" (node). If using "webgpu", we recommend using dtype="fp32". device: "cpu",
}); });
const stream = new TextSplitterStream(); const stream = new TextSplitterStream();
@ -21,46 +21,46 @@ if (!input) {
} }
stream.push(input); stream.push(input);
console.log(chalk.blue("Welcome to aitts!\n"));
console.log(input);
await $`rm -r ${os.homedir()}/.aitts/`.nothrow(); await $`rm -r ${os.homedir()}/.aitts/`.nothrow();
await $`mkdir ${os.homedir()}/.aitts/`.nothrow(); await $`mkdir ${os.homedir()}/.aitts/`.nothrow();
let fileId = 0; let fileId = 0;
let buffer = ""; const files: string[] = [];
for (const text of stream) {
buffer += ` ${text}`;
if (buffer.length < 100) continue;
console.log(`${chalk.blue(fileId)}:${buffer}`); const processText = async (text: string) => {
const audio = await tts.generate(buffer, { const audio = await tts.generate(text, {
voice: "af_heart", voice: "af_bella",
speed: 1.2, speed: 1.2,
}); });
const file = `${os.homedir()}/.aitts/${fileId}.wav`; const file = `${os.homedir()}/.aitts/${fileId}.wav`;
audio.save(file); audio.save(file);
files.push(file);
fileId++; fileId++;
buffer = ""; };
}
if (buffer) { const play = async () => {
console.log(`${chalk.blue(fileId)}:${buffer}`); for (const file of files) {
const audio = await tts.generate(buffer, { console.log(chalk.green(`Playing ${file}`));
voice: "af_heart", await Bun.spawn({
speed: 1.2, cmd: ["mpv", file],
});
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", stdout: "inherit",
}).exited; }).exited;
console.log(chalk.green("Have a nice day!")); process.stdout.moveCursor(-9999, -5);
process.stdout.clearScreenDown();
}
};
let playing: Promise<void> | undefined;
for (const text of stream) {
await processText(text);
if (!playing && which("mpv")) {
playing = play();
}
}
await playing;