Update Kokoro.js: WebGPU support, v1.0 integration (#60)

* Set up JS project

* Finalise JS library

* Update README

* Fix package.json repository url

* Rename package -> `kokoro-js`

* Fix samples in README

* Cleanup README

* Bump `phonemizer` version

* Create web demo

* Run prettier

* Link to model used in demo

* Enable multithreading in HF space demo (~40% faster)

* Add link to demo in README

* Bump to v1.0.1

* Update voices

* Update versions

* Update phonemize JSDoc

* Use updated voice pack

* Update versions

* Update demo (v1.0 & WebGPU support)

* Update README

* Enforce maximum number of tokens

* Update README

* [version] Update to 1.1.1
This commit is contained in:
Joshua Lochner
2025-02-07 20:04:41 +02:00
committed by GitHub
parent 31a2b6337b
commit e0bf641def
65 changed files with 1242 additions and 164 deletions

View File

@@ -5,10 +5,10 @@
<a href="https://www.npmjs.com/package/kokoro-js"><img alt="NPM Downloads" src="https://img.shields.io/npm/dw/kokoro-js"></a>
<a href="https://www.jsdelivr.com/package/npm/kokoro-js"><img alt="jsDelivr Hits" src="https://img.shields.io/jsdelivr/npm/hw/kokoro-js"></a>
<a href="https://github.com/hexgrad/kokoro/blob/main/LICENSE"><img alt="License" src="https://img.shields.io/github/license/hexgrad/kokoro?color=blue"></a>
<a href="https://huggingface.co/spaces/webml-community/kokoro-web"><img alt="Demo" src="https://img.shields.io/badge/Hugging_Face-demo-green"></a>
<a href="https://huggingface.co/spaces/webml-community/kokoro-webgpu"><img alt="Demo" src="https://img.shields.io/badge/Hugging_Face-demo-green"></a>
</p>
Kokoro is a frontier TTS model for its size of 82 million parameters (text in/audio out). This JavaScript library allows the model to be run 100% locally in the browser thanks to [🤗 Transformers.js](https://huggingface.co/docs/transformers.js). Try it out using our [online demo](https://huggingface.co/spaces/webml-community/kokoro-web)!
Kokoro is a frontier TTS model for its size of 82 million parameters (text in/audio out). This JavaScript library allows the model to be run 100% locally in the browser thanks to [🤗 Transformers.js](https://huggingface.co/docs/transformers.js). Try it out using our [online demo](https://huggingface.co/spaces/webml-community/kokoro-webgpu)!
## Usage
@@ -23,33 +23,59 @@ You can then generate speech as follows:
```js
import { KokoroTTS } from "kokoro-js";
const model_id = "onnx-community/Kokoro-82M-ONNX";
const model_id = "onnx-community/Kokoro-82M-v1.0-ONNX";
const tts = await KokoroTTS.from_pretrained(model_id, {
dtype: "q8", // Options: "fp32", "fp16", "q8", "q4", "q4f16"
device: "wasm", // Options: "wasm", "webgpu" (web) or "cpu" (node). If using "webgpu", we recommend using dtype="fp32".
});
const text = "Life is like a box of chocolates. You never know what you're gonna get.";
const audio = await tts.generate(text, {
// Use `tts.list_voices()` to list all available voices
voice: "af_bella",
voice: "af_heart",
});
audio.save("audio.wav");
```
## Voices/Samples
> Life is like a box of chocolates. You never know what you're gonna get.
> [!TIP]
> You can find samples for each of the voices in the [model card](https://huggingface.co/onnx-community/Kokoro-82M-v1.0-ONNX#samples) on Hugging Face.
| Voice | Nationality | Gender | Sample |
| ------------------------ | ----------- | ------ | -------------------------------------------------------------------------------------------------------- |
| Default (`af`) | American | Female | <video controls src="https://github.com/user-attachments/assets/c183df83-58a9-4aea-8fdf-225092acec57" /> |
| Bella (`af_bella`) | American | Female | <video controls src="https://github.com/user-attachments/assets/0730fff0-22b3-458f-9675-36d313d872d6" /> |
| Nicole (`af_nicole`) | American | Female | <video controls src="https://github.com/user-attachments/assets/4ce0b3f6-eaec-4e47-901c-9d29e2b60c86" /> |
| Sarah (`af_sarah`) | American | Female | <video controls src="https://github.com/user-attachments/assets/d37dba3f-de59-44c4-bc3d-da91ea1b5a4a" /> |
| Sky (`af_sky`) | American | Female | <video controls src="https://github.com/user-attachments/assets/38230be5-881c-4407-81e6-a0b1e4101565" /> |
| Adam (`am_adam`) | American | Male | <video controls src="https://github.com/user-attachments/assets/66a4c439-e80b-4c91-8a27-ae094486a2d8" /> |
| Michael (`am_michael`) | American | Male | <video controls src="https://github.com/user-attachments/assets/79a8879d-b564-4222-b2d5-a97f783ae897" /> |
| Emma (`bf_emma`) | British | Female | <video controls src="https://github.com/user-attachments/assets/ad5eb254-1d84-4282-9d23-371d5765d820" /> |
| Isabella (`bf_isabella`) | British | Female | <video controls src="https://github.com/user-attachments/assets/ea7e6825-dad0-403c-9ece-680af04f5a25" /> |
| George (`bm_george`) | British | Male | <video controls src="https://github.com/user-attachments/assets/e09040aa-578f-40a6-b7fd-76a5b005346c" /> |
| Lewis (`bm_lewis`) | British | Male | <video controls src="https://github.com/user-attachments/assets/5d7b26bf-8900-4a9a-8ee5-a16c39bb834c" /> |
### American English
| Name | Traits | Target Quality | Training Duration | Overall Grade |
| ------------ | ------ | -------------- | ----------------- | ------------- |
| **af_heart** | 🚺❤️ | | | **A** |
| af_alloy | 🚺 | B | MM minutes | C |
| af_aoede | 🚺 | B | H hours | C+ |
| af_bella | 🚺🔥 | **A** | **HH hours** | **A-** |
| af_jessica | 🚺 | C | MM minutes | D |
| af_kore | 🚺 | B | H hours | C+ |
| af_nicole | 🚺🎧 | B | **HH hours** | B- |
| af_nova | 🚺 | B | MM minutes | C |
| af_river | 🚺 | C | MM minutes | D |
| af_sarah | 🚺 | B | H hours | C+ |
| af_sky | 🚺 | B | _M minutes_ 🤏 | C- |
| am_adam | 🚹 | D | H hours | F+ |
| am_echo | 🚹 | C | MM minutes | D |
| am_eric | 🚹 | C | MM minutes | D |
| am_fenrir | 🚹 | B | H hours | C+ |
| am_liam | 🚹 | C | MM minutes | D |
| am_michael | 🚹 | B | H hours | C+ |
| am_onyx | 🚹 | C | MM minutes | D |
| am_puck | 🚹 | B | H hours | C+ |
| am_santa | 🚹 | C | _M minutes_ 🤏 | D- |
### British English
| Name | Traits | Target Quality | Training Duration | Overall Grade |
| ----------- | ------ | -------------- | ----------------- | ------------- |
| bf_alice | 🚺 | C | MM minutes | D |
| bf_emma | 🚺 | B | **HH hours** | B- |
| bf_isabella | 🚺 | B | MM minutes | C |
| bf_lily | 🚺 | C | MM minutes | D |
| bm_daniel | 🚹 | C | MM minutes | D |
| bm_fable | 🚹 | B | MM minutes | C |
| bm_george | 🚹 | B | MM minutes | C |
| bm_lewis | 🚹 | C | H hours | D+ |

View File

@@ -31,10 +31,10 @@
},
"..": {
"name": "kokoro-js",
"version": "1.0.0",
"version": "1.1.0",
"license": "Apache-2.0",
"dependencies": {
"@huggingface/transformers": "^3.3.1",
"@huggingface/transformers": "^3.3.3",
"phonemizer": "^1.2.1"
},
"devDependencies": {
@@ -334,14 +334,151 @@
"node": ">=6.9.0"
}
},
"node_modules/@esbuild/linux-x64": {
"version": "0.24.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.0.tgz",
"integrity": "sha512-vbutsFqQ+foy3wSSbmjBXXIJ6PL3scghJoM8zCL142cGaZKAdCZHyf+Bpu/MmX9zT9Q0zFBVKb36Ma5Fzfa8xA==",
"node_modules/@esbuild/aix-ppc64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz",
"integrity": "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"aix"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.24.2.tgz",
"integrity": "sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-arm64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.24.2.tgz",
"integrity": "sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-x64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.24.2.tgz",
"integrity": "sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/darwin-arm64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.2.tgz",
"integrity": "sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/darwin-x64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.24.2.tgz",
"integrity": "sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/freebsd-arm64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.2.tgz",
"integrity": "sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/freebsd-x64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.24.2.tgz",
"integrity": "sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-arm": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.24.2.tgz",
"integrity": "sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
@@ -350,6 +487,278 @@
"node": ">=18"
}
},
"node_modules/@esbuild/linux-arm64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.24.2.tgz",
"integrity": "sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-ia32": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.24.2.tgz",
"integrity": "sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.24.2.tgz",
"integrity": "sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==",
"cpu": [
"loong64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-mips64el": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.24.2.tgz",
"integrity": "sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==",
"cpu": [
"mips64el"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-ppc64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.24.2.tgz",
"integrity": "sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-riscv64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.24.2.tgz",
"integrity": "sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==",
"cpu": [
"riscv64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-s390x": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.24.2.tgz",
"integrity": "sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==",
"cpu": [
"s390x"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-x64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.2.tgz",
"integrity": "sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/netbsd-arm64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.24.2.tgz",
"integrity": "sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/netbsd-x64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.24.2.tgz",
"integrity": "sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openbsd-arm64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.2.tgz",
"integrity": "sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openbsd-x64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.24.2.tgz",
"integrity": "sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/sunos-x64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.2.tgz",
"integrity": "sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"sunos"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-arm64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.24.2.tgz",
"integrity": "sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-ia32": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.24.2.tgz",
"integrity": "sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-x64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.24.2.tgz",
"integrity": "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@eslint-community/eslint-utils": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz",
@@ -648,32 +1057,272 @@
"node": ">=14"
}
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.28.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.28.0.tgz",
"integrity": "sha512-Nl4KIzteVEKE9BdAvYoTkW19pa7LR/RBrT6F1dJCV/3pbjwDcaOq+edkP0LXuJ9kflW/xOK414X78r+K84+msw==",
"node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.34.5",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.5.tgz",
"integrity": "sha512-JXmmQcKQtpf3Z6lvA8akkrHDZ5AEfgc2hLMix1/X5BhQbezBQ0AP5GYLdU8jsQRme8qr2sscCe3wizp7UT0L9g==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
]
},
"node_modules/@rollup/rollup-android-arm64": {
"version": "4.34.5",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.5.tgz",
"integrity": "sha512-9/A8/ZBOprUjkrJoP9BBEq2vdSud6BPd3LChw09bJQiEZH5oN4kWIkHu90cA0Cj0cSF5cIaD76+0lA+d5KHmpQ==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
]
},
"node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.34.5",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.5.tgz",
"integrity": "sha512-b9oCfgHKfc1AJEQ5sEpE8Kf6s7aeygj5bZAsl1hTpZc1V9cfZASFSXzzNj7o/BQNPbjmVkVxpCCLRhBfLXhJ5g==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
]
},
"node_modules/@rollup/rollup-darwin-x64": {
"version": "4.34.5",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.5.tgz",
"integrity": "sha512-Gz42gKBQPoFdMYdsVqkcpttYOO/0aP7f+1CgMaeZEz0gss7dop1TsO3hT77Iroz/TV7PdPUG/RYlj9EA39L4dw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
]
},
"node_modules/@rollup/rollup-freebsd-arm64": {
"version": "4.34.5",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.5.tgz",
"integrity": "sha512-JPkafjkOFaupd8VQYsXfGFKC2pfMr7hwSYGkVGNwhbW0k0lHHyIdhCSNBendJ4O7YlT4yRyKXoms1TL7saO7SQ==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
]
},
"node_modules/@rollup/rollup-freebsd-x64": {
"version": "4.34.5",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.5.tgz",
"integrity": "sha512-j6Q8VFqyI8hZM33h1JC6DZK2w8ejkXqEMozTrtIEGfRVMpVZL3GrLOOYEUkAgUSpJ9sb2w+FEpjGj7IHRcQfdw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
]
},
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.34.5",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.5.tgz",
"integrity": "sha512-6jyiXKF9Xq6x9yQjct5xrRT0VghJk5VzAfed3o0hgncwacZkzOdR0TXLRNjexsEXWN8tG7jWWwsVk7WeFi//gw==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
"version": "4.34.5",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.5.tgz",
"integrity": "sha512-cOTYe5tLcGAvGztRLIqx87LE7j/qjaAqFrrHsPFlnuhhhFO5LSr2AzvdQYuxomJMzMBrXkMRNl9bQEpDZ5bjLQ==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.34.5",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.5.tgz",
"integrity": "sha512-KHlrd+YqmS7rriW+LBb1kQNYmd5w1sAIG3z7HEpnQOrg/skeYYv9DAcclGL9gpFdpnzmiAEkzsTT74kZWUtChQ==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-arm64-musl": {
"version": "4.34.5",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.5.tgz",
"integrity": "sha512-uOb6hzDqym4Sw+qw3+svS3SmwQGVUhyTdPKyHDdlYg1Z0aHjdNmjwRY7zw/90/UfBe/yD7Mv2mYKhQpOfy4RYA==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-loongarch64-gnu": {
"version": "4.34.5",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.5.tgz",
"integrity": "sha512-pARu8ZKANZH4wINLdHLKG69EPwJswM6A+Ox1a9LpiclRQoyjacFFTtXN3akKQ2ufJXDasO/pWvxKN9ZfCgEoFA==",
"cpu": [
"loong64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
"version": "4.34.5",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.5.tgz",
"integrity": "sha512-crUWn12NRmCdao2YwS1GvlPCVypMBMJlexTaantaP2+dAMd2eZBErFcKG8hZYEHjSbbk2UoH1aTlyeA4iKLqSA==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
"version": "4.34.5",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.5.tgz",
"integrity": "sha512-XtD/oMhCdixi3x8rCNyDRMUsLo1Z+1UQcK+oR7AsjglGov9ETiT3TNFhUPzaGC1jH+uaMtPhxrVRUub+pnAKTg==",
"cpu": [
"riscv64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-s390x-gnu": {
"version": "4.34.5",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.5.tgz",
"integrity": "sha512-V3+BvgyHb21aF7lw0sc78Tv0+xLp4lm2OM7CKFVrBuppsMvtl/9O5y2OX4tdDT0EhIsDP/ObJPqDuEg1ZoTwSQ==",
"cpu": [
"s390x"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.34.5",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.5.tgz",
"integrity": "sha512-SkCIXLGk42yldTcH8UXh++m0snVxp9DLf4meb1mWm0lC8jzxjFBwSLGtUSeLgQDsC05iBaIhyjNX46DlByrApQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-x64-musl": {
"version": "4.28.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.28.0.tgz",
"integrity": "sha512-eKpJr4vBDOi4goT75MvW+0dXcNUqisK4jvibY9vDdlgLx+yekxSm55StsHbxUsRxSTt3JEQvlr3cGDkzcSP8bw==",
"version": "4.34.5",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.5.tgz",
"integrity": "sha512-iUcH3FBtBN2/Ce0rI84suRhD0+bB5BVEffqOwsGaX5py5TuYLOQa7S7oVBP0NKtB5rub3i9IvZtMXiD96l5v0A==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-win32-arm64-msvc": {
"version": "4.34.5",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.5.tgz",
"integrity": "sha512-PUbWd+h/h6rUowalDYIdc9S9LJXbQDMcJe0BjABl3oT3efYRgZ8aUe8ZZDSie7y+fz6Z+rueNfdorIbkWv5Eqg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
]
},
"node_modules/@rollup/rollup-win32-ia32-msvc": {
"version": "4.34.5",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.5.tgz",
"integrity": "sha512-3vncGhOJiAUR85fnAXJyvSp2GaDWYByIQmW68ZAr+e8kIxgvJ1VaZbfHD5BO5X6hwRQdY6Um/XfA3l5c2lV+OQ==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
]
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.34.5",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.5.tgz",
"integrity": "sha512-Mi8yVUlQOoeBpY72n75VLATptPGvj2lHa47rQdK9kZ4MoG5Ve86aVIU+PO3tBklTCBtILtdRfXS0EvIbXgmCAg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
]
},
"node_modules/@types/babel__core": {
"version": "7.20.5",
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
@@ -1621,11 +2270,12 @@
}
},
"node_modules/esbuild": {
"version": "0.24.0",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.0.tgz",
"integrity": "sha512-FuLPevChGDshgSicjisSooU0cemp/sGXR841D5LHMB7mTVOmsEHcAxaH3irL53+8YDIeVNQEySh4DaYU/iuPqQ==",
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.2.tgz",
"integrity": "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"bin": {
"esbuild": "bin/esbuild"
},
@@ -1633,30 +2283,31 @@
"node": ">=18"
},
"optionalDependencies": {
"@esbuild/aix-ppc64": "0.24.0",
"@esbuild/android-arm": "0.24.0",
"@esbuild/android-arm64": "0.24.0",
"@esbuild/android-x64": "0.24.0",
"@esbuild/darwin-arm64": "0.24.0",
"@esbuild/darwin-x64": "0.24.0",
"@esbuild/freebsd-arm64": "0.24.0",
"@esbuild/freebsd-x64": "0.24.0",
"@esbuild/linux-arm": "0.24.0",
"@esbuild/linux-arm64": "0.24.0",
"@esbuild/linux-ia32": "0.24.0",
"@esbuild/linux-loong64": "0.24.0",
"@esbuild/linux-mips64el": "0.24.0",
"@esbuild/linux-ppc64": "0.24.0",
"@esbuild/linux-riscv64": "0.24.0",
"@esbuild/linux-s390x": "0.24.0",
"@esbuild/linux-x64": "0.24.0",
"@esbuild/netbsd-x64": "0.24.0",
"@esbuild/openbsd-arm64": "0.24.0",
"@esbuild/openbsd-x64": "0.24.0",
"@esbuild/sunos-x64": "0.24.0",
"@esbuild/win32-arm64": "0.24.0",
"@esbuild/win32-ia32": "0.24.0",
"@esbuild/win32-x64": "0.24.0"
"@esbuild/aix-ppc64": "0.24.2",
"@esbuild/android-arm": "0.24.2",
"@esbuild/android-arm64": "0.24.2",
"@esbuild/android-x64": "0.24.2",
"@esbuild/darwin-arm64": "0.24.2",
"@esbuild/darwin-x64": "0.24.2",
"@esbuild/freebsd-arm64": "0.24.2",
"@esbuild/freebsd-x64": "0.24.2",
"@esbuild/linux-arm": "0.24.2",
"@esbuild/linux-arm64": "0.24.2",
"@esbuild/linux-ia32": "0.24.2",
"@esbuild/linux-loong64": "0.24.2",
"@esbuild/linux-mips64el": "0.24.2",
"@esbuild/linux-ppc64": "0.24.2",
"@esbuild/linux-riscv64": "0.24.2",
"@esbuild/linux-s390x": "0.24.2",
"@esbuild/linux-x64": "0.24.2",
"@esbuild/netbsd-arm64": "0.24.2",
"@esbuild/netbsd-x64": "0.24.2",
"@esbuild/openbsd-arm64": "0.24.2",
"@esbuild/openbsd-x64": "0.24.2",
"@esbuild/sunos-x64": "0.24.2",
"@esbuild/win32-arm64": "0.24.2",
"@esbuild/win32-ia32": "0.24.2",
"@esbuild/win32-x64": "0.24.2"
}
},
"node_modules/escalade": {
@@ -2055,6 +2706,21 @@
}
}
},
"node_modules/fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/function-bind": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
@@ -3334,9 +4000,9 @@
}
},
"node_modules/postcss": {
"version": "8.4.49",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz",
"integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==",
"version": "8.5.1",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.1.tgz",
"integrity": "sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==",
"dev": true,
"funding": [
{
@@ -3352,8 +4018,9 @@
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"dependencies": {
"nanoid": "^3.3.7",
"nanoid": "^3.3.8",
"picocolors": "^1.1.1",
"source-map-js": "^1.2.1"
},
@@ -3689,10 +4356,11 @@
}
},
"node_modules/rollup": {
"version": "4.28.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.28.0.tgz",
"integrity": "sha512-G9GOrmgWHBma4YfCcX8PjH0qhXSdH8B4HDE2o4/jaxj93S4DPCIDoLcXz99eWMji4hB29UFCEd7B2gwGJDR9cQ==",
"version": "4.34.5",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.34.5.tgz",
"integrity": "sha512-GyVCmpo9z/HYqFD8QWoBUnz1Q9xC22t8tPAZm/AvAcUg2U2/+DkboEvSioMwv042zE4I9N3FEhx7fiCT2YHzKQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/estree": "1.0.6"
},
@@ -3704,24 +4372,25 @@
"npm": ">=8.0.0"
},
"optionalDependencies": {
"@rollup/rollup-android-arm-eabi": "4.28.0",
"@rollup/rollup-android-arm64": "4.28.0",
"@rollup/rollup-darwin-arm64": "4.28.0",
"@rollup/rollup-darwin-x64": "4.28.0",
"@rollup/rollup-freebsd-arm64": "4.28.0",
"@rollup/rollup-freebsd-x64": "4.28.0",
"@rollup/rollup-linux-arm-gnueabihf": "4.28.0",
"@rollup/rollup-linux-arm-musleabihf": "4.28.0",
"@rollup/rollup-linux-arm64-gnu": "4.28.0",
"@rollup/rollup-linux-arm64-musl": "4.28.0",
"@rollup/rollup-linux-powerpc64le-gnu": "4.28.0",
"@rollup/rollup-linux-riscv64-gnu": "4.28.0",
"@rollup/rollup-linux-s390x-gnu": "4.28.0",
"@rollup/rollup-linux-x64-gnu": "4.28.0",
"@rollup/rollup-linux-x64-musl": "4.28.0",
"@rollup/rollup-win32-arm64-msvc": "4.28.0",
"@rollup/rollup-win32-ia32-msvc": "4.28.0",
"@rollup/rollup-win32-x64-msvc": "4.28.0",
"@rollup/rollup-android-arm-eabi": "4.34.5",
"@rollup/rollup-android-arm64": "4.34.5",
"@rollup/rollup-darwin-arm64": "4.34.5",
"@rollup/rollup-darwin-x64": "4.34.5",
"@rollup/rollup-freebsd-arm64": "4.34.5",
"@rollup/rollup-freebsd-x64": "4.34.5",
"@rollup/rollup-linux-arm-gnueabihf": "4.34.5",
"@rollup/rollup-linux-arm-musleabihf": "4.34.5",
"@rollup/rollup-linux-arm64-gnu": "4.34.5",
"@rollup/rollup-linux-arm64-musl": "4.34.5",
"@rollup/rollup-linux-loongarch64-gnu": "4.34.5",
"@rollup/rollup-linux-powerpc64le-gnu": "4.34.5",
"@rollup/rollup-linux-riscv64-gnu": "4.34.5",
"@rollup/rollup-linux-s390x-gnu": "4.34.5",
"@rollup/rollup-linux-x64-gnu": "4.34.5",
"@rollup/rollup-linux-x64-musl": "4.34.5",
"@rollup/rollup-win32-arm64-msvc": "4.34.5",
"@rollup/rollup-win32-ia32-msvc": "4.34.5",
"@rollup/rollup-win32-x64-msvc": "4.34.5",
"fsevents": "~2.3.2"
}
},
@@ -4384,14 +5053,15 @@
"dev": true
},
"node_modules/vite": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/vite/-/vite-6.0.1.tgz",
"integrity": "sha512-Ldn6gorLGr4mCdFnmeAOLweJxZ34HjKnDm4HGo6P66IEqTxQb36VEdFJQENKxWjupNfoIjvRUnswjn1hpYEpjQ==",
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/vite/-/vite-6.1.0.tgz",
"integrity": "sha512-RjjMipCKVoR4hVfPY6GQTgveinjNuyLw+qruksLDvA5ktI1150VmcMBKmQaEWJhg/j6Uaf6dNCNA0AfdzUb/hQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"esbuild": "^0.24.0",
"postcss": "^8.4.49",
"rollup": "^4.23.0"
"esbuild": "^0.24.2",
"postcss": "^8.5.1",
"rollup": "^4.30.1"
},
"bin": {
"vite": "bin/vite.js"

View File

@@ -6,11 +6,12 @@ export default function App() {
const worker = useRef(null);
const [inputText, setInputText] = useState("Life is like a box of chocolates. You never know what you're gonna get.");
const [selectedSpeaker, setSelectedSpeaker] = useState("af");
const [selectedSpeaker, setSelectedSpeaker] = useState("af_heart");
const [voices, setVoices] = useState([]);
const [status, setStatus] = useState(null);
const [error, setError] = useState(null);
const [loadingMessage, setLoadingMessage] = useState("Loading model (only downloaded once)...");
const [loadingMessage, setLoadingMessage] = useState("Loading...");
const [results, setResults] = useState([]);
@@ -24,18 +25,16 @@ export default function App() {
// Create a callback function for messages from the worker thread.
const onMessageReceived = (e) => {
switch (e.data.status) {
// TODO: WebGPU feature checking
// case "feature-success":
// break;
// case "feature-error":
// setError(e.data.data);
// break;
case "device":
setLoadingMessage(`Loading model (device="${e.data.device}")`);
break;
case "ready":
setStatus("ready");
setVoices(e.data.voices);
break;
case "error":
setError(e.data.data);
break;
case "complete":
const { audio, text } = e.data;
// Generation complete: re-enable the "Generate" button
@@ -47,6 +46,7 @@ export default function App() {
const onErrorReceived = (e) => {
console.error("Worker error:", e);
setError(e.message);
};
// Attach the callback function as an event listener.
@@ -99,17 +99,11 @@ export default function App() {
<textarea placeholder="Enter text..." value={inputText} onChange={(e) => setInputText(e.target.value)} className="w-full min-h-[100px] max-h-[300px] bg-gray-700/50 backdrop-blur-sm border-2 border-gray-600 rounded-xl resize-y text-gray-100 placeholder-gray-400 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" rows={Math.min(8, inputText.split("\n").length)} />
<div className="flex flex-col items-center space-y-4">
<select value={selectedSpeaker} onChange={(e) => setSelectedSpeaker(e.target.value)} className="w-full bg-gray-700/50 backdrop-blur-sm border-2 border-gray-600 rounded-xl text-gray-100 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent">
<option value="af">Default (American Female)</option>
<option value="af_bella">Bella (American Female)</option>
<option value="af_nicole">Nicole (American Female)</option>
<option value="af_sarah">Sarah (American Female)</option>
<option value="af_sky">Sky (American Female)</option>
<option value="am_adam">Adam (American Male)</option>
<option value="am_michael">Michael (American Male)</option>
<option value="bf_emma">Emma (British Female)</option>
<option value="bf_isabella">Isabella (British Female)</option>
<option value="bm_george">George (British Male)</option>
<option value="bm_lewis">Lewis (British Male)</option>
{Object.entries(voices).map(([id, voice]) => (
<option key={id} value={id}>
{voice.name} ({voice.language === "en-us" ? "American" : "British"} {voice.gender})
</option>
))}
</select>
<button type="submit" className="inline-flex justify-center items-center px-6 py-2 text-lg font-semibold bg-gradient-to-t from-blue-600 to-purple-600 hover:from-blue-700 hover:to-purple-700 transition-colors duration-300 rounded-xl text-white disabled:opacity-50" disabled={status === "running" || inputText.trim() === ""}>
{status === "running" ? "Generating..." : "Generate"}

View File

@@ -0,0 +1,8 @@
export async function detectWebGPU() {
try {
const adapter = await navigator.gpu.requestAdapter();
return !!adapter;
} catch (e) {
return false;
}
}

View File

@@ -1,11 +1,20 @@
import { KokoroTTS } from "kokoro-js";
import { detectWebGPU } from "./utils.js";
const model_id = "onnx-community/Kokoro-82M-ONNX";
// Device detection
const device = (await detectWebGPU()) ? "webgpu" : "wasm";
self.postMessage({ status: "device", device });
// Load the model
const model_id = "onnx-community/Kokoro-82M-v1.0-ONNX";
const tts = await KokoroTTS.from_pretrained(model_id, {
dtype: "q8", // Options: "fp32", "fp16", "q8", "q4", "q4f16"
dtype: device === "wasm" ? "q8" : "fp32",
device,
}).catch((e) => {
self.postMessage({ status: "error", error: e.message });
throw e;
});
self.postMessage({ status: "ready" });
self.postMessage({ status: "ready", voices: tts.voices, device });
// Listen for messages from the main thread
self.addEventListener("message", async (e) => {

View File

@@ -1,15 +1,15 @@
{
"name": "kokoro-js",
"version": "1.0.1",
"version": "1.1.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "kokoro-js",
"version": "1.0.1",
"version": "1.1.1",
"license": "Apache-2.0",
"dependencies": {
"@huggingface/transformers": "^3.3.1",
"@huggingface/transformers": "^3.3.3",
"phonemizer": "^1.2.1"
},
"devDependencies": {
@@ -423,23 +423,23 @@
}
},
"node_modules/@huggingface/jinja": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/@huggingface/jinja/-/jinja-0.3.2.tgz",
"integrity": "sha512-F2FvuIc+w1blGsaqJI/OErRbWH6bVJDCBI8Rm5D86yZ2wlwrGERsfIaru7XUv9eYC3DMP3ixDRRtF0h6d8AZcQ==",
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/@huggingface/jinja/-/jinja-0.3.3.tgz",
"integrity": "sha512-vQQr2JyWvVFba3Lj9es4q9vCl1sAc74fdgnEMoX8qHrXtswap9ge9uO3ONDzQB0cQ0PUyaKY2N6HaVbTBvSXvw==",
"license": "MIT",
"engines": {
"node": ">=18"
}
},
"node_modules/@huggingface/transformers": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/@huggingface/transformers/-/transformers-3.3.1.tgz",
"integrity": "sha512-ypduhicsjFQAIcYPBicojDGz9jpvU+abCuoRFYj/V9glTmMVLlGxCwssAGSGmoC+T+FV9JFI5U8i2H+zpOxVbg==",
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/@huggingface/transformers/-/transformers-3.3.3.tgz",
"integrity": "sha512-OcMubhBjW6u1xnp0zSt5SvCxdGHuhP2k+w2Vlm3i0vNcTJhJTZWxxYQmPBfcb7PX+Q6c43lGSzWD6tsJFwka4Q==",
"license": "Apache-2.0",
"dependencies": {
"@huggingface/jinja": "^0.3.2",
"@huggingface/jinja": "^0.3.3",
"onnxruntime-node": "1.20.1",
"onnxruntime-web": "1.21.0-dev.20250114-228dd16893",
"onnxruntime-web": "1.21.0-dev.20250206-d981b153d3",
"sharp": "^0.33.5"
}
},
@@ -1754,10 +1754,10 @@
}
},
"node_modules/flatbuffers": {
"version": "1.12.0",
"resolved": "https://registry.npmjs.org/flatbuffers/-/flatbuffers-1.12.0.tgz",
"integrity": "sha512-c7CZADjRcl6j0PlvFy0ZqXQ67qSEZfrVPynmnL+2zPc+NtMvrF8Y0QceMo7QqnSPc7+uWjUIAbvCQ5WIKlMVdQ==",
"license": "SEE LICENSE IN LICENSE.txt"
"version": "25.1.24",
"resolved": "https://registry.npmjs.org/flatbuffers/-/flatbuffers-25.1.24.tgz",
"integrity": "sha512-Ni+KCqYquU30UEgGkrrwpbYtUcUmNuLFcQ5Xdy9DK7WUaji+AAov+Bf12FEYmu0eI15y31oD38utnBexe0cAYA==",
"license": "Apache-2.0"
},
"node_modules/foreground-child": {
"version": "3.3.0",
@@ -2028,23 +2028,23 @@
}
},
"node_modules/onnxruntime-web": {
"version": "1.21.0-dev.20250114-228dd16893",
"resolved": "https://registry.npmjs.org/onnxruntime-web/-/onnxruntime-web-1.21.0-dev.20250114-228dd16893.tgz",
"integrity": "sha512-fUnedxS63NYwNkQJlvdD55jVcOtyM+Qzw1SGt9Pj3jZVaIwR4mltx/5C0yvwdue44BTSV7M5Q0qnhL6/30ewqA==",
"version": "1.21.0-dev.20250206-d981b153d3",
"resolved": "https://registry.npmjs.org/onnxruntime-web/-/onnxruntime-web-1.21.0-dev.20250206-d981b153d3.tgz",
"integrity": "sha512-esDVQdRic6J44VBMFLumYvcGfioMh80ceLmzF1yheJyuLKq/Th8VT2aj42XWQst+2bcWnAhw4IKmRQaqzU8ugg==",
"license": "MIT",
"dependencies": {
"flatbuffers": "^1.12.0",
"flatbuffers": "^25.1.24",
"guid-typescript": "^1.0.9",
"long": "^5.2.3",
"onnxruntime-common": "1.21.0-dev.20241212-1f88284f96",
"onnxruntime-common": "1.21.0-dev.20250206-d981b153d3",
"platform": "^1.3.6",
"protobufjs": "^7.2.4"
}
},
"node_modules/onnxruntime-web/node_modules/onnxruntime-common": {
"version": "1.21.0-dev.20241212-1f88284f96",
"resolved": "https://registry.npmjs.org/onnxruntime-common/-/onnxruntime-common-1.21.0-dev.20241212-1f88284f96.tgz",
"integrity": "sha512-zD6mQJfgeezbNKV2fiN/ZqB+LKdixJ7sKc5vu6PdqMU+bZk581g5XqrhoYNwe/RDJdFGQSMKK9+gUg4Mep+jKw==",
"version": "1.21.0-dev.20250206-d981b153d3",
"resolved": "https://registry.npmjs.org/onnxruntime-common/-/onnxruntime-common-1.21.0-dev.20250206-d981b153d3.tgz",
"integrity": "sha512-TwaE51xV9q2y8pM61q73rbywJnusw9ivTEHAJ39GVWNZqxCoDBpe/tQkh/w9S+o/g+zS7YeeL0I/2mEWd+dgyA==",
"license": "MIT"
},
"node_modules/package-json-from-dist": {
@@ -2688,9 +2688,9 @@
"license": "MIT"
},
"node_modules/vite": {
"version": "5.4.11",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.11.tgz",
"integrity": "sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==",
"version": "5.4.14",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.14.tgz",
"integrity": "sha512-EK5cY7Q1D8JNhSaPKVK4pwBFvaTmZxEnoKXLG/U9gmdDcihQGNzFlgIvaxezFR4glP1LsuiedwMBqCXH3wZccA==",
"dev": true,
"license": "MIT",
"dependencies": {

View File

@@ -1,6 +1,6 @@
{
"name": "kokoro-js",
"version": "1.0.1",
"version": "1.1.1",
"type": "module",
"exports": {
"types": "./types/kokoro.d.ts",
@@ -34,7 +34,7 @@
"license": "Apache-2.0",
"description": "High-quality text-to-speech for the web",
"dependencies": {
"@huggingface/transformers": "^3.3.1",
"@huggingface/transformers": "^3.3.3",
"phonemizer": "^1.2.1"
},
"devDependencies": {

View File

@@ -41,33 +41,39 @@ export class KokoroTTS {
console.table(VOICES);
}
/**
* Generate audio from text.
*
* Note: The model will be loaded on the first call, and subsequent calls will use the same model.
* @param {string} text The input text
* @param {Object} options Additional options
* @param {keyof typeof VOICES} [options.voice="af"] The voice style to use
* @param {number} [options.speed=1] The speaking speed
* @returns {Promise<RawAudio>} The generated audio
*/
async generate(text, { voice = "af", speed = 1 } = {}) {
_validate_voice(voice) {
if (!VOICES.hasOwnProperty(voice)) {
console.error(`Voice "${voice}" not found. Available voices:`);
console.table(VOICES);
throw new Error(`Voice "${voice}" not found. Should be one of: ${Object.keys(VOICES).join(", ")}.`);
}
}
const language = voice.at(0); // "a" or "b"
/**
* Generate audio from text.
*
* @param {string} text The input text
* @param {Object} options Additional options
* @param {keyof typeof VOICES} [options.voice="af_heart"] The voice style to use
* @param {number} [options.speed=1] The speaking speed
* @returns {Promise<RawAudio>} The generated audio
*/
async generate(text, { voice = "af_heart", speed = 1 } = {}) {
this._validate_voice(voice);
const language = /** @type {"a"|"b"} */ (voice.at(0)); // "a" or "b"
const phonemes = await phonemize(text, language);
const { input_ids } = this.tokenizer(phonemes, {
truncation: true,
});
// Select voice style based on number of input tokens
const num_tokens = Math.max(
input_ids.dims.at(-1) - 2, // Without padding;
0,
const num_tokens = Math.min(
Math.max(
input_ids.dims.at(-1) - 2,
0,
),
509,
);
// Load voice style

View File

@@ -164,6 +164,13 @@ function escapeRegExp(string) {
const PUNCTUATION = ';:,.!?¡¿—…"«»“”(){}[]';
const PUNCTUATION_PATTERN = new RegExp(`(\\s*[${escapeRegExp(PUNCTUATION)}]+\\s*)+`, "g");
/**
* Phonemize text using the eSpeak-NG phonemizer
* @param {string} text The text to phonemize
* @param {"a"|"b"} language The language to use
* @param {boolean} norm Whether to normalize the text
* @returns {Promise<string>} The phonemized text
*/
export async function phonemize(text, language = "a", norm = true) {
// 1. Normalize text
if (norm) {

View File

@@ -2,66 +2,423 @@ import path from "path";
import fs from "fs/promises";
export const VOICES = Object.freeze({
af: {
// Default voice is a 50-50 mix of Bella & Sarah
name: "Default",
af_heart: {
name: "Heart",
language: "en-us",
gender: "Female",
traits: "❤️",
targetQuality: "A",
overallGrade: "A",
},
af_alloy: {
name: "Alloy",
language: "en-us",
gender: "Female",
targetQuality: "B",
overallGrade: "C",
},
af_aoede: {
name: "Aoede",
language: "en-us",
gender: "Female",
targetQuality: "B",
overallGrade: "C+",
},
af_bella: {
name: "Bella",
language: "en-us",
gender: "Female",
traits: "🔥",
targetQuality: "A",
overallGrade: "A-",
},
af_jessica: {
name: "Jessica",
language: "en-us",
gender: "Female",
targetQuality: "C",
overallGrade: "D",
},
af_kore: {
name: "Kore",
language: "en-us",
gender: "Female",
targetQuality: "B",
overallGrade: "C+",
},
af_nicole: {
name: "Nicole",
language: "en-us",
gender: "Female",
traits: "🎧",
targetQuality: "B",
overallGrade: "B-",
},
af_nova: {
name: "Nova",
language: "en-us",
gender: "Female",
targetQuality: "B",
overallGrade: "C",
},
af_river: {
name: "River",
language: "en-us",
gender: "Female",
targetQuality: "C",
overallGrade: "D",
},
af_sarah: {
name: "Sarah",
language: "en-us",
gender: "Female",
targetQuality: "B",
overallGrade: "C+",
},
af_sky: {
name: "Sky",
language: "en-us",
gender: "Female",
targetQuality: "B",
overallGrade: "C-",
},
am_adam: {
name: "Adam",
language: "en-us",
gender: "Male",
targetQuality: "D",
overallGrade: "F+",
},
am_echo: {
name: "Echo",
language: "en-us",
gender: "Male",
targetQuality: "C",
overallGrade: "D",
},
am_eric: {
name: "Eric",
language: "en-us",
gender: "Male",
targetQuality: "C",
overallGrade: "D",
},
am_fenrir: {
name: "Fenrir",
language: "en-us",
gender: "Male",
targetQuality: "B",
overallGrade: "C+",
},
am_liam: {
name: "Liam",
language: "en-us",
gender: "Male",
targetQuality: "C",
overallGrade: "D",
},
am_michael: {
name: "Michael",
language: "en-us",
gender: "Male",
targetQuality: "B",
overallGrade: "C+",
},
am_onyx: {
name: "Onyx",
language: "en-us",
gender: "Male",
targetQuality: "C",
overallGrade: "D",
},
am_puck: {
name: "Puck",
language: "en-us",
gender: "Male",
targetQuality: "B",
overallGrade: "C+",
},
am_santa: {
name: "Santa",
language: "en-us",
gender: "Male",
targetQuality: "C",
overallGrade: "D-",
},
bf_emma: {
name: "Emma",
language: "en-gb",
gender: "Female",
traits: "🚺",
targetQuality: "B",
overallGrade: "B-",
},
bf_isabella: {
name: "Isabella",
language: "en-gb",
gender: "Female",
targetQuality: "B",
overallGrade: "C",
},
bm_george: {
name: "George",
language: "en-gb",
gender: "Male",
targetQuality: "B",
overallGrade: "C",
},
bm_lewis: {
name: "Lewis",
language: "en-gb",
gender: "Male",
targetQuality: "C",
overallGrade: "D+",
},
bf_alice: {
name: "Alice",
language: "en-gb",
gender: "Female",
traits: "🚺",
targetQuality: "C",
overallGrade: "D",
},
bf_lily: {
name: "Lily",
language: "en-gb",
gender: "Female",
traits: "🚺",
targetQuality: "C",
overallGrade: "D",
},
bm_daniel: {
name: "Daniel",
language: "en-gb",
gender: "Male",
traits: "🚹",
targetQuality: "C",
overallGrade: "D",
},
bm_fable: {
name: "Fable",
language: "en-gb",
gender: "Male",
traits: "🚹",
targetQuality: "B",
overallGrade: "C",
},
// TODO: Add support for other languages:
// jf_alpha: {
// name: "alpha",
// language: "ja",
// gender: "Female",
// traits: "🚺",
// targetQuality: "B",
// overallGrade: "C+",
// },
// jf_gongitsune: {
// name: "gongitsune",
// language: "ja",
// gender: "Female",
// traits: "🚺",
// targetQuality: "B",
// overallGrade: "C",
// },
// jf_nezumi: {
// name: "nezumi",
// language: "ja",
// gender: "Female",
// traits: "🚺",
// targetQuality: "B",
// overallGrade: "C-",
// },
// jf_tebukuro: {
// name: "tebukuro",
// language: "ja",
// gender: "Female",
// traits: "🚺",
// targetQuality: "B",
// overallGrade: "C",
// },
// jm_kumo: {
// name: "kumo",
// language: "ja",
// gender: "Male",
// traits: "🚹",
// targetQuality: "B",
// overallGrade: "C-",
// },
// zf_xiaobei: {
// name: "xiaobei",
// language: "zh",
// gender: "Female",
// traits: "🚺",
// targetQuality: "C",
// overallGrade: "D",
// },
// zf_xiaoni: {
// name: "xiaoni",
// language: "zh",
// gender: "Female",
// traits: "🚺",
// targetQuality: "C",
// overallGrade: "D",
// },
// zf_xiaoxiao: {
// name: "xiaoxiao",
// language: "zh",
// gender: "Female",
// traits: "🚺",
// targetQuality: "C",
// overallGrade: "D",
// },
// zf_xiaoyi: {
// name: "xiaoyi",
// language: "zh",
// gender: "Female",
// traits: "🚺",
// targetQuality: "C",
// overallGrade: "D",
// },
// zm_yunjian: {
// name: "yunjian",
// language: "zh",
// gender: "Male",
// traits: "🚹",
// targetQuality: "C",
// overallGrade: "D",
// },
// zm_yunxi: {
// name: "yunxi",
// language: "zh",
// gender: "Male",
// traits: "🚹",
// targetQuality: "C",
// overallGrade: "D",
// },
// zm_yunxia: {
// name: "yunxia",
// language: "zh",
// gender: "Male",
// traits: "🚹",
// targetQuality: "C",
// overallGrade: "D",
// },
// zm_yunyang: {
// name: "yunyang",
// language: "zh",
// gender: "Male",
// traits: "🚹",
// targetQuality: "C",
// overallGrade: "D",
// },
// ef_dora: {
// name: "dora",
// language: "es",
// gender: "Female",
// traits: "🚺",
// targetQuality: "C",
// overallGrade: "D",
// },
// em_alex: {
// name: "alex",
// language: "es",
// gender: "Male",
// traits: "🚹",
// targetQuality: "C",
// overallGrade: "D",
// },
// em_santa: {
// name: "santa",
// language: "es",
// gender: "Male",
// traits: "🚹",
// targetQuality: "C",
// overallGrade: "D",
// },
// ff_siwis: {
// name: "siwis",
// language: "es",
// gender: "Female",
// traits: "🚺",
// targetQuality: "B",
// overallGrade: "B-",
// },
// hf_alpha: {
// name: "alpha",
// language: "hi",
// gender: "Female",
// traits: "🚺",
// targetQuality: "B",
// overallGrade: "C",
// },
// hf_beta: {
// name: "beta",
// language: "hi",
// gender: "Female",
// traits: "🚺",
// targetQuality: "B",
// overallGrade: "C",
// },
// hm_omega: {
// name: "omega",
// language: "hi",
// gender: "Male",
// traits: "🚹",
// targetQuality: "B",
// overallGrade: "C",
// },
// hm_psi: {
// name: "psi",
// language: "hi",
// gender: "Male",
// traits: "🚹",
// targetQuality: "B",
// overallGrade: "C",
// },
// if_sara: {
// name: "sara",
// language: "it",
// gender: "Female",
// traits: "🚺",
// targetQuality: "B",
// overallGrade: "C",
// },
// im_nicola: {
// name: "nicola",
// language: "it",
// gender: "Male",
// traits: "🚹",
// targetQuality: "B",
// overallGrade: "C",
// },
// pf_dora: {
// name: "dora",
// language: "pt-br",
// gender: "Female",
// traits: "🚺",
// targetQuality: "C",
// overallGrade: "D",
// },
// pm_alex: {
// name: "alex",
// language: "pt-br",
// gender: "Male",
// traits: "🚹",
// targetQuality: "C",
// overallGrade: "D",
// },
// pm_santa: {
// name: "santa",
// language: "pt-br",
// gender: "Male",
// traits: "🚹",
// targetQuality: "C",
// overallGrade: "D",
// },
});
const VOICE_DATA_URL = "https://huggingface.co/onnx-community/Kokoro-82M-ONNX/resolve/main/voices";
const VOICE_DATA_URL = "https://huggingface.co/onnx-community/Kokoro-82M-v1.0-ONNX/resolve/main/voices";
/**
*
@@ -70,7 +427,8 @@ const VOICE_DATA_URL = "https://huggingface.co/onnx-community/Kokoro-82M-ONNX/re
*/
async function getVoiceFile(id) {
if (fs?.readFile) {
const file = path.resolve(import.meta.dirname ?? __dirname, `../voices/${id}.bin`);
const dirname = typeof __dirname !== "undefined" ? __dirname : import.meta.dirname;
const file = path.resolve(dirname, `../voices/${id}.bin`);
const { buffer } = await fs.readFile(file);
return buffer;
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
kokoro.js/voices/hm_psi.bin Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.