@rimelabs/sdk 0.1.0-alpha.1 → 0.1.0-alpha.3
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/CHANGELOG.md +23 -11
- package/README.md +129 -56
- package/dist/audio.js +2 -1
- package/dist/client.d.ts +1 -0
- package/dist/client.js +1 -1
- package/dist/policy.d.ts +1 -0
- package/dist/policy.js +16 -7
- package/dist/transport.js +1 -1
- package/package.json +6 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,16 +1,28 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 0.1.0-alpha.1
|
|
3
|
+
## [0.1.0-alpha.3](https://github.com/rimelabs/rime-sdk/compare/typescript-v0.1.0-alpha.2...typescript-v0.1.0-alpha.3) (2026-09-28)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* match ITU mu-law quantization for negative PCM ([#10](https://github.com/rimelabs/rime-sdk/issues/10)) ([e03dcb3](https://github.com/rimelabs/rime-sdk/commit/e03dcb3424cab5a9b7d6bc9b1c37b3b72540e3a6))
|
|
4
9
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
10
|
+
## [0.1.0-alpha.2](https://github.com/rimelabs/rime-sdk/compare/typescript-v0.1.0-alpha.1...typescript-v0.1.0-alpha.2) (2026-09-28)
|
|
11
|
+
|
|
12
|
+
- Add `model: "mistv3"` for Mist v3 speech, voice discovery, and language discovery.
|
|
13
|
+
The model selects its standard endpoint and default voice. Custom endpoints
|
|
14
|
+
retain the model's default voice. Coda remains the default model.
|
|
15
|
+
- Reorganize the usage guide around examples and option tables. Clarify audio
|
|
16
|
+
output, timeout defaults, error handling, and cancellation.
|
|
17
|
+
|
|
18
|
+
## 0.1.0-alpha.1
|
|
9
19
|
|
|
10
|
-
|
|
11
|
-
mapping, distinguish token-exchange rate limits and service failures from
|
|
12
|
-
rejected credentials, and cancel failed HTTP response bodies.
|
|
20
|
+
Initial public alpha for Node.js 22 and later, with ESM and TypeScript types:
|
|
13
21
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
22
|
+
- Stream Coda speech from a string or an async text source with API-key authentication.
|
|
23
|
+
- Discover voices and languages, and select a custom deployment endpoint.
|
|
24
|
+
- Receive raw 24 kHz PCM or 8 kHz mu-law audio with sentence buffering.
|
|
25
|
+
- Set operation deadlines, cancel streams, and handle typed errors with request IDs.
|
|
26
|
+
- Preserve original text during sentence detection, including zero-width spaces
|
|
27
|
+
and byte order marks.
|
|
28
|
+
- Report server errors even when no audio metadata arrives or input writes fail.
|
package/README.md
CHANGED
|
@@ -1,23 +1,28 @@
|
|
|
1
1
|
# Rime SDK for Node.js
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
Install
|
|
3
|
+
Stream speech from a string or async text source with Rime.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
Requires Node.js 22 or later. This alpha package uses ESM and includes TypeScript
|
|
8
|
+
types. Browser use is not supported.
|
|
6
9
|
|
|
7
10
|
```sh
|
|
8
11
|
npm install @rimelabs/sdk@next
|
|
12
|
+
export RIME_API_KEY="your-api-key"
|
|
9
13
|
```
|
|
10
14
|
|
|
15
|
+
## Quick start
|
|
16
|
+
|
|
17
|
+
Save this as `speech.mjs` and run `node speech.mjs`:
|
|
18
|
+
|
|
11
19
|
```javascript
|
|
12
20
|
import { writeFile } from "node:fs/promises";
|
|
13
|
-
import { Rime
|
|
21
|
+
import { Rime } from "@rimelabs/sdk";
|
|
14
22
|
|
|
15
|
-
const client = new Rime(
|
|
23
|
+
const client = new Rime();
|
|
16
24
|
try {
|
|
17
|
-
const audio = client.tts.stream("Hello. This is Rime."
|
|
18
|
-
voice: "clementine",
|
|
19
|
-
audioFormat: AudioFormat.PCM_24000,
|
|
20
|
-
});
|
|
25
|
+
const audio = client.tts.stream("Hello. This is Rime.");
|
|
21
26
|
await writeFile("speech.pcm", audio);
|
|
22
27
|
console.log(audio.requestId);
|
|
23
28
|
} finally {
|
|
@@ -25,69 +30,137 @@ try {
|
|
|
25
30
|
}
|
|
26
31
|
```
|
|
27
32
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
33
|
+
Output is raw mono 24 kHz signed 16-bit little-endian PCM. Configure your player
|
|
34
|
+
for this format; there is no WAV header.
|
|
35
|
+
|
|
36
|
+
## Stream incoming text
|
|
37
|
+
|
|
38
|
+
Add this async text source before the client declaration in the quick start:
|
|
31
39
|
|
|
32
40
|
```javascript
|
|
33
|
-
|
|
41
|
+
async function* text() {
|
|
42
|
+
yield "Hello. ";
|
|
43
|
+
yield "This text arrives in separate chunks.";
|
|
44
|
+
}
|
|
34
45
|
```
|
|
35
46
|
|
|
36
|
-
Use
|
|
37
|
-
|
|
38
|
-
|
|
47
|
+
Use `client.tts.stream(text())` with the same file write and cleanup.
|
|
48
|
+
The SDK handles sentence boundaries. Do not await `tts.stream()`; the first
|
|
49
|
+
iterator read starts work. `writeFile` consumes the stream for you.
|
|
39
50
|
|
|
40
|
-
|
|
41
|
-
`tts.stream()` also accepts `AsyncIterable<string>`. Do not await the factory.
|
|
42
|
-
The first iterator read starts work. A `for await` loop exit cancels the stream.
|
|
43
|
-
Use `await audio.cancel()` in a `finally` block if you read the iterator manually.
|
|
51
|
+
## Configuration
|
|
44
52
|
|
|
45
|
-
`
|
|
46
|
-
`await client.languages.list()` returns language codes.
|
|
47
|
-
Both accept an options object with `timeout` in seconds.
|
|
53
|
+
Select Mist v3 with `new Rime({ model: "mistv3" })`. Mist v1 and v2 are not supported.
|
|
48
54
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
55
|
+
| Model | Standard endpoint | Default voice |
|
|
56
|
+
| --- | --- | --- |
|
|
57
|
+
| `coda` | `coda.api.rime.ai:443` | `clementine` |
|
|
58
|
+
| `mistv3` | `mist.api.rime.ai:443` | `astra` |
|
|
53
59
|
|
|
54
|
-
|
|
55
|
-
`channels`. `PCM_24000` is raw signed 16-bit little-endian mono PCM at 24 kHz.
|
|
56
|
-
`MULAW_8000` is raw mono G.711 mu-law at 8 kHz. Neither includes a file header.
|
|
57
|
-
The iterator yields `Uint8Array` chunks with complete sample frames.
|
|
58
|
-
Chunk sizes are not fixed.
|
|
60
|
+
### Client options
|
|
59
61
|
|
|
60
|
-
`
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
| `new Rime({ ... })` option | Default | Meaning |
|
|
63
|
+
| --- | --- | --- |
|
|
64
|
+
| `apiKey` | `RIME_API_KEY` | API key; an explicit value overrides the environment |
|
|
65
|
+
| `model` | `"coda"` | Model for speech and discovery |
|
|
66
|
+
| `endpoint` | Model's standard endpoint | Custom hostname and optional port for speech and discovery |
|
|
67
|
+
| `timeout` | No overall deadline | Positive seconds; `null` disables the overall deadline |
|
|
64
68
|
|
|
65
|
-
|
|
66
|
-
`RimeInputError`, `RimeResourceLimitError`, `RimeUnavailableError`,
|
|
67
|
-
`RimeTimeoutError`, `RimeAudioFormatError`, `RimeCancelledError`, or
|
|
68
|
-
`RimeStreamError`. Errors expose a message and optional `requestId`.
|
|
69
|
-
Cancellation cannot stop application code that waits on an unrelated promise.
|
|
70
|
-
The SDK stops its RPC and limits how long it waits for source cleanup.
|
|
69
|
+
Authentication uses bearer tokens over TLS. The SDK does not load `.env` files.
|
|
71
70
|
|
|
72
|
-
|
|
71
|
+
Custom deployments use `new Rime({ model: "coda", endpoint: "host:8443" })`.
|
|
72
|
+
Omit the scheme and path. TLS is required; the default port is `443`.
|
|
73
|
+
Model defaults still apply.
|
|
73
74
|
|
|
74
|
-
|
|
75
|
+
### Synthesis options
|
|
75
76
|
|
|
76
|
-
|
|
77
|
-
Run the commands from its `typescript/` directory:
|
|
77
|
+
Pass these options to `client.tts.stream(text, { ... })`:
|
|
78
78
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
79
|
+
| Option | Default | Meaning |
|
|
80
|
+
| --- | --- | --- |
|
|
81
|
+
| `voice` | Model's default voice | Voice name from `client.voices.list()` |
|
|
82
|
+
| `language` | `"en"` | Language code |
|
|
83
|
+
| `audioFormat` | `AudioFormat.PCM_24000` | Output profile, imported from `@rimelabs/sdk` |
|
|
84
|
+
| `timeout` | Client setting | Seconds; pass `null` to disable the overall deadline |
|
|
85
|
+
|
|
86
|
+
### Audio formats
|
|
87
|
+
|
|
88
|
+
Both profiles return raw audio without a file header.
|
|
89
|
+
|
|
90
|
+
| `AudioFormat` profile | Encoding | Sample rate | Channels |
|
|
91
|
+
| --- | --- | --- | --- |
|
|
92
|
+
| `PCM_24000` | Signed 16-bit little-endian PCM | 24 kHz | Mono |
|
|
93
|
+
| `MULAW_8000` | G.711 mu-law | 8 kHz | Mono |
|
|
94
|
+
|
|
95
|
+
Chunks are `Uint8Array` values with complete sample frames; sizes vary. Inspect the
|
|
96
|
+
read-only `audio.format.encoding`, `audio.format.sampleRate`, and `audio.format.channels`.
|
|
97
|
+
|
|
98
|
+
### Timeouts
|
|
99
|
+
|
|
100
|
+
An overall deadline includes pauses between reads. Disabling it leaves internal
|
|
101
|
+
connection and progress limits active. Discovery allows at most 10 seconds;
|
|
102
|
+
a shorter supplied timeout takes precedence. Omit an operation's `timeout` or
|
|
103
|
+
pass `undefined` to inherit the client setting.
|
|
104
|
+
|
|
105
|
+
## Discover voices and languages
|
|
106
|
+
|
|
107
|
+
List voices and languages inside the quick start's `try` block:
|
|
108
|
+
|
|
109
|
+
```javascript
|
|
110
|
+
const voices = await client.voices.list({ language: "en" });
|
|
111
|
+
const languages = await client.languages.list();
|
|
112
|
+
console.log(voices, languages);
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Both return string arrays and accept `timeout`. Omit `language` to disable filtering.
|
|
116
|
+
|
|
117
|
+
## Errors and cancellation
|
|
118
|
+
|
|
119
|
+
Report SDK errors and request IDs while closing the client on failure:
|
|
120
|
+
|
|
121
|
+
```javascript
|
|
122
|
+
import { writeFile } from "node:fs/promises";
|
|
123
|
+
import { Rime, RimeError } from "@rimelabs/sdk";
|
|
124
|
+
|
|
125
|
+
let client;
|
|
126
|
+
try {
|
|
127
|
+
client = new Rime();
|
|
128
|
+
await writeFile("speech.pcm", client.tts.stream("Hello. This is Rime."));
|
|
129
|
+
} catch (error) {
|
|
130
|
+
if (error instanceof RimeError) {
|
|
131
|
+
console.error(`Speech failed: ${error.message}; requestId=${error.requestId}`);
|
|
132
|
+
}
|
|
133
|
+
throw error;
|
|
134
|
+
} finally {
|
|
135
|
+
await client?.close();
|
|
136
|
+
}
|
|
85
137
|
```
|
|
86
138
|
|
|
87
|
-
|
|
88
|
-
|
|
139
|
+
Each SDK error inherits from `RimeError`:
|
|
140
|
+
|
|
141
|
+
| Error | Meaning |
|
|
142
|
+
| --- | --- |
|
|
143
|
+
| `RimeAuthenticationError` | Missing or rejected credentials |
|
|
144
|
+
| `RimePermissionError` | Access denied |
|
|
145
|
+
| `RimeInputError` | Invalid input or client use |
|
|
146
|
+
| `RimeResourceLimitError` | Service resource limit reached |
|
|
147
|
+
| `RimeUnavailableError` | Service unavailable |
|
|
148
|
+
| `RimeTimeoutError` | Overall or internal deadline reached |
|
|
149
|
+
| `RimeAudioFormatError` | Unsupported or unexpected audio format |
|
|
150
|
+
| `RimeCancelledError` | Operation cancelled |
|
|
151
|
+
| `RimeStreamError` | Other stream or transport failure |
|
|
152
|
+
|
|
153
|
+
Partial audio can arrive before an error. Output is complete only after successful
|
|
154
|
+
iteration. Synthesis is not retried automatically.
|
|
155
|
+
|
|
156
|
+
Keep cleanup when stopping early. A `for await` loop exit cancels the stream.
|
|
157
|
+
For manual reads, call `await audio.cancel()` in `finally`. `await client.close()`
|
|
158
|
+
stops all client work. Both calls are safe to repeat; both objects support
|
|
159
|
+
`Symbol.asyncDispose`. Cancellation stops the RPC and limits cleanup time, but
|
|
160
|
+
cannot force your text source to finish an unrelated promise.
|
|
89
161
|
|
|
90
162
|
## License
|
|
91
163
|
|
|
92
|
-
The SDK
|
|
93
|
-
|
|
164
|
+
The SDK uses the [MIT License](LICENSE). BlingFire retains its
|
|
165
|
+
[upstream license](vendor/LICENSE.blingfire). The package includes its WASM runtime
|
|
166
|
+
and downloads no code or models at runtime. See [vendor provenance](vendor/README.md).
|
package/dist/audio.js
CHANGED
|
@@ -20,7 +20,8 @@ const total = raw.reduce((a, b) => a + b, 0);
|
|
|
20
20
|
const coefficients = raw.map((x) => x / total);
|
|
21
21
|
function mulaw(sample) {
|
|
22
22
|
sample = Math.max(-32768, Math.min(32767, sample));
|
|
23
|
-
|
|
23
|
+
// G.711 uses one's complement for negative PCM before quantization.
|
|
24
|
+
const sign = sample < 0 ? 128 : 0, magnitude = Math.min(sample < 0 ? ~sample : sample, 32635) + 132;
|
|
24
25
|
const exponent = Math.max(0, Math.floor(Math.log2(magnitude)) - 7);
|
|
25
26
|
return ~(sign | (exponent << 4) | ((magnitude >> (exponent + 3)) & 15)) & 255;
|
|
26
27
|
}
|
package/dist/client.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { AudioFormat } from "./audio.js";
|
|
|
2
2
|
import { AudioStream, type TextSource } from "./stream.js";
|
|
3
3
|
export interface RimeOptions {
|
|
4
4
|
apiKey?: string | null;
|
|
5
|
+
/** Select "coda" (default) or "mistv3" for speech and discovery. */
|
|
5
6
|
model?: string;
|
|
6
7
|
endpoint?: string | null;
|
|
7
8
|
timeout?: number | null;
|
package/dist/client.js
CHANGED
|
@@ -58,7 +58,7 @@ export class Rime {
|
|
|
58
58
|
else if (!text || typeof text[Symbol.asyncIterator] !== "function")
|
|
59
59
|
throw new RimeInputError("text must be a string or an async iterable of strings");
|
|
60
60
|
const voice = options.voice === undefined || options.voice === null
|
|
61
|
-
?
|
|
61
|
+
? this.deployment.defaultVoice
|
|
62
62
|
: nonempty(options.voice, "voice");
|
|
63
63
|
const language = nonempty(options.language ?? "en", "language");
|
|
64
64
|
const format = options.audioFormat ?? AudioFormat.PCM_24000;
|
package/dist/policy.d.ts
CHANGED
package/dist/policy.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { RimeInputError } from "./errors.js";
|
|
2
|
+
const codaHostname = "coda.api.rime.ai";
|
|
2
3
|
export const policy = {
|
|
3
|
-
target:
|
|
4
|
-
audience:
|
|
4
|
+
target: `${codaHostname}:443`,
|
|
5
|
+
audience: codaHostname,
|
|
6
|
+
defaultVoice: "clementine",
|
|
5
7
|
exchangeUrl: "https://themis.api.rime.ai/v1/token",
|
|
6
8
|
sentenceBytes: 65536,
|
|
7
9
|
sourceChars: 1024,
|
|
@@ -16,11 +18,18 @@ export const policy = {
|
|
|
16
18
|
cleanupTimeout: 2,
|
|
17
19
|
};
|
|
18
20
|
export function resolve(model, endpoint) {
|
|
19
|
-
|
|
20
|
-
if (model
|
|
21
|
-
|
|
21
|
+
const deployment = { ...policy };
|
|
22
|
+
if (model === "mistv3") {
|
|
23
|
+
const hostname = "mist.api.rime.ai";
|
|
24
|
+
deployment.target = `${hostname}:443`;
|
|
25
|
+
deployment.audience = hostname;
|
|
26
|
+
deployment.defaultVoice = "astra";
|
|
27
|
+
}
|
|
28
|
+
else if (model !== "coda") {
|
|
29
|
+
throw new RimeInputError("model must be 'coda' or 'mistv3'");
|
|
30
|
+
}
|
|
22
31
|
if (endpoint === undefined || endpoint === null)
|
|
23
|
-
return
|
|
32
|
+
return deployment;
|
|
24
33
|
const error = "endpoint must be a hostname with an optional port (1-65535), without a scheme or path";
|
|
25
34
|
if (typeof endpoint !== "string" || /\s/.test(endpoint))
|
|
26
35
|
throw new RimeInputError(error);
|
|
@@ -35,7 +44,7 @@ export function resolve(model, endpoint) {
|
|
|
35
44
|
(!/^[0-9]{1,5}$/.test(port) || Number(port) < 1 || Number(port) > 65535)))
|
|
36
45
|
throw new RimeInputError(error);
|
|
37
46
|
return {
|
|
38
|
-
...
|
|
47
|
+
...deployment,
|
|
39
48
|
target: `${host.toLowerCase()}:${port === undefined ? 443 : Number(port)}`,
|
|
40
49
|
audience: host.toLowerCase(),
|
|
41
50
|
};
|
package/dist/transport.js
CHANGED
|
@@ -72,7 +72,7 @@ function nativeError(error, id) {
|
|
|
72
72
|
const metadata = "metadata" in error ? error.metadata : null;
|
|
73
73
|
return rpcError(error.code, id ?? (metadata instanceof grpc.Metadata ? requestId(metadata) : null));
|
|
74
74
|
}
|
|
75
|
-
return new errors.RimeStreamError("
|
|
75
|
+
return new errors.RimeStreamError("Rime transport failed", id, {
|
|
76
76
|
cause: error,
|
|
77
77
|
});
|
|
78
78
|
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rimelabs/sdk",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.3",
|
|
4
4
|
"description": "Rime streaming text-to-speech SDK for Node.js",
|
|
5
5
|
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/rimelabs/rime-sdk.git",
|
|
9
|
+
"directory": "typescript"
|
|
10
|
+
},
|
|
6
11
|
"type": "module",
|
|
7
12
|
"engines": {
|
|
8
13
|
"node": ">=22"
|