{"_id":"@adeptvs_mechanicvs/corvvs","name":"@adeptvs_mechanicvs/corvvs","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@adeptvs_mechanicvs/corvvs","version":"0.1.0","description":"Fast, local, private text-to-speech — Kokoro-82M on your own GPU, one install per machine, shared by every project on it.","type":"module","main":"./src/index.js","types":"./dist/index.d.ts","exports":{".":"./src/index.js"},"engines":{"node":">=20"},"scripts":{"test":"node --test","build:types":"tsc","prepublishOnly":"npm run build:types"},"keywords":["tts","text-to-speech","kokoro","speech-synthesis","local-first","offline","self-hosted"],"license":"MIT","publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/magus-mechanicus/corvvs.git","directory":"client"},"homepage":"https://github.com/magus-mechanicus/corvvs#readme","optionalDependencies":{"kokoro-js":"^1.2.1"},"devDependencies":{"typescript":"^5.6.0"},"gitHead":"44af35f913c4d608bd9d629511d527a240c47530","_id":"@adeptvs_mechanicvs/corvvs@0.1.0","bugs":{"url":"https://github.com/magus-mechanicus/corvvs/issues"},"_nodeVersion":"25.8.1","_npmVersion":"11.11.0","dist":{"integrity":"sha512-wd1jtrHQVt8FKMI1EeN8MheAbKB1zjFQnWO7ZhSrb+f9UuYdNq7MWL50hEd7Qz92FUHUk7TPEiEJx+0R/Xjq7Q==","shasum":"893457f6bd4493ee7f86bd832938248cbc7bf8da","tarball":"https://registry.npmjs.org/@adeptvs_mechanicvs/corvvs/-/corvvs-0.1.0.tgz","fileCount":11,"unpackedSize":29465,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCKnEHPmTLzP8fX3IJ1DW9pEXwDmNhAwBIy8Q8PV5UUWQIgBUS8m0x8lbYQTcVnLAI0+p5b1x8FSN7n5lCX8TPIpxg="}]},"_npmUser":{"name":"adeptvs_mechanicvs","email":"prophetoftheomnissiah@gmail.com"},"directories":{},"maintainers":[{"name":"adeptvs_mechanicvs","email":"prophetoftheomnissiah@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/corvvs_0.1.0_1786830865435_0.8500294235840145"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-15T21:54:25.252Z","0.1.0":"2026-08-15T21:54:25.581Z","modified":"2026-08-15T21:54:25.822Z"},"maintainers":[{"name":"adeptvs_mechanicvs","email":"prophetoftheomnissiah@gmail.com"}],"description":"Fast, local, private text-to-speech — Kokoro-82M on your own GPU, one install per machine, shared by every project on it.","homepage":"https://github.com/magus-mechanicus/corvvs#readme","keywords":["tts","text-to-speech","kokoro","speech-synthesis","local-first","offline","self-hosted"],"repository":{"type":"git","url":"git+https://github.com/magus-mechanicus/corvvs.git","directory":"client"},"bugs":{"url":"https://github.com/magus-mechanicus/corvvs/issues"},"license":"MIT","readme":"# corvvs\n\nFast, local, private text-to-speech. [Kokoro-82M](https://huggingface.co/hexgrad/Kokoro-82M)\non your own GPU — no API keys, no per-character billing, nothing leaves the machine.\n\nPublished as `@adeptvs_mechanicvs/corvvs` — npm blocks a plain `corvvs` as too similar to\nthe widely-used `cors` package. The function you actually call is still named `corvvs`;\nonly the install/import specifier carries the scope.\n\n```bash\nnpm install @adeptvs_mechanicvs/corvvs\n```\n\n```js\nimport { corvvs } from '@adeptvs_mechanicvs/corvvs';\n\nconst tts = corvvs();\nconst wav = await tts.speak('Hello there', { voice: 'af_heart' });\n```\n\n`wav` is a Buffer: 24 kHz, 16-bit PCM, mono.\n\n## This package is the client\n\nThe synthesis happens in the **CORVVS engine**, a small service you install once per\nmachine and every project on it shares. Install it from\n[the repo](https://github.com/magus-mechanicus/corvvs):\n\n```bash\ngit clone https://github.com/magus-mechanicus/corvvs\ncd corvvs && npm install && npm run setup && npm start\n```\n\nWithout the engine this package still works — it falls back to running the same model on\nthe CPU, which is correct but roughly **170x slower** (~29 s/sentence vs ~0.17 s). It logs\na warning when that happens rather than being quietly slow.\n\n## API\n\n### `corvvs(options?)`\n\n| Option | Default | |\n|---|---|---|\n| `url` | `http://127.0.0.1:8765` | Engine base URL. Also read from `CORVVS_URL` |\n| `key` | — | Bearer token, if the engine requires one. Also `CORVVS_TOKEN` |\n| `voice` | `af_heart` | Default voice |\n| `speed` | `1.0` | Default speed, 0.5–2.0 |\n| `fallback` | `true` | CPU fallback when no engine is reachable |\n| `timeout` | `120000` | Per-request timeout, ms |\n\nThe engine's location is always a parameter — local, LAN, and hosted engines speak the\nsame protocol:\n\n```js\ncorvvs();                                         // local\ncorvvs({ url: 'http://192.168.1.50:8765' });      // another machine\ncorvvs({ url: 'https://…', key: '…' });           // hosted\n```\n\n### `tts.speak(text, { voice?, speed? })` → `Promise<Buffer>`\n\n### `tts.speakStream(text, { voice?, speed? })` → `AsyncGenerator<{ text, audio }>`\n\nYields clips as soon as they're ready instead of waiting for the whole text:\n\n```js\nfor await (const { text, audio } of tts.speakStream(longArticle)) {\n  console.log('now playing:', text);\n  await play(audio); // however your app plays a WAV Buffer\n}\n```\n\n**A yielded chunk is not one sentence.** Kokoro's own pipeline decides chunk boundaries\nby an internal length budget, not punctuation — measured in this repo, anywhere from one\nto several sentences came back per chunk. If you need one chunk per sentence\nspecifically, use `tts.split()` and call `speak()` per sentence instead.\n\nOnly the engine actually streams. If there's no engine and the CPU fallback kicks in,\n`speakStream` still works — it just synthesizes the whole text up front and yields it as\none chunk, since `kokoro-js` has no equivalent streaming mode wired up here. Check\n`tts.available()` first if your app needs to know which behavior it's getting.\n\n### `tts.split(text)` → `string[]`\n\nA sentence splitter, good enough for chunking text before `speak()`/`speakStream()` —\nnot a linguistic tokenizer. Handles common abbreviations (`Dr.`, `etc.`) and decimals\n(`3.14`) without splitting on them; doesn't special-case runs of initials (`J. K.\nRowling` will over-split).\n\n```js\nfor (const sentence of tts.split(article)) {\n  await tts.speak(sentence);\n}\n```\n\n### `tts.voices()` → `Promise<Voice[]>`\n\nEach voice carries the model author's own quality `grade`. The roster is long but only a\nhandful are genuinely good — sort by grade before showing users a dropdown.\n\n```js\n[{ id: 'af_heart', name: 'Heart', gender: 'female', language: 'en-US', grade: 'A' }, …]\n```\n\n### `tts.health()` → `Promise<{ status, device, model, version }>`\n\n`device` is `cuda`, `mps`, or `cpu`. **A `cpu` result on a machine with a GPU means the\nengine install fell back** and everything will be far slower than it should be.\n\n### `tts.available()` → `Promise<boolean>`\n\nNever throws. For deciding a code path up front — disabling a \"read aloud\" button, say —\nrather than discovering the answer mid-synthesis.\n\n## Errors\n\nEvery failure is a `CorvvsError` with a stable `code`:\n\n```js\nimport { CorvvsError } from '@adeptvs_mechanicvs/corvvs';\n\ntry {\n  await tts.speak(text);\n} catch (err) {\n  if (err.code === 'ERR_TOO_LARGE') { /* split into sentences */ }\n}\n```\n\n`ERR_UNREACHABLE` · `ERR_TIMEOUT` · `ERR_VERSION_MISMATCH` · `ERR_NO_FALLBACK` ·\n`ERR_BAD_REQUEST` · `ERR_UNAUTHORIZED` · `ERR_TOO_LARGE` · `ERR_SYNTHESIS`\n\nOnly `ERR_UNREACHABLE` triggers the fallback. `ERR_TIMEOUT` deliberately does **not** —\na slow-but-working engine isn't the same as no engine, and falling back would make a slow\nresponse look like an even slower one. Every other failure — including a\nrunning-but-broken engine — surfaces as-is rather than being papered over.\n\n## Notes\n\n- Text over 5000 characters is rejected (`ERR_TOO_LARGE`). Use `tts.split()` to chunk a\n  long document, or `speakStream()` to stream it sentence-by-sentence instead.\n- `kokoro-js` is an `optionalDependency` (it powers the CPU fallback). Skip it with\n  `npm install @adeptvs_mechanicvs/corvvs --omit=optional` for an HTTP-only client.\n- Ships TypeScript declarations (`dist/index.d.ts`), generated from the JSDoc above via\n  `npm run build:types`.\n\nMIT.\n","readmeFilename":"README.md","_rev":"1-0e7143f75ef404b07ade4a839f0bcc84"}