@rimelabs/sdk 0.1.0-alpha.8 → 0.1.0-alpha.9
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 +7 -0
- package/README.md +151 -50
- package/docs/realtime.md +10 -16
- package/docs/tts.md +3 -7
- package/package.json +3 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.1.0-alpha.9](https://github.com/rimelabs/rime-sdk/compare/typescript-v0.1.0-alpha.8...typescript-v0.1.0-alpha.9) (2026-10-08)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* make package quickstarts usable without repository access ([#24](https://github.com/rimelabs/rime-sdk/issues/24)) ([3a30b83](https://github.com/rimelabs/rime-sdk/commit/3a30b83ecaad1740c84d1e8c005520522cf56d26))
|
|
9
|
+
|
|
3
10
|
## [0.1.0-alpha.8](https://github.com/rimelabs/rime-sdk/compare/typescript-v0.1.0-alpha.7...typescript-v0.1.0-alpha.8) (2026-10-08)
|
|
4
11
|
|
|
5
12
|
|
package/README.md
CHANGED
|
@@ -1,74 +1,175 @@
|
|
|
1
1
|
# Rime SDK for Node.js
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
Use Prism for conversations with audio input, typed turns, and tools.
|
|
3
|
+
Generate speech with TTS, or send speech to Prism and receive a spoken reply.
|
|
4
|
+
Both APIs use the `Rime` client. Your application handles audio capture and playback.
|
|
6
5
|
|
|
7
6
|
## Install
|
|
8
7
|
|
|
9
|
-
Requires Node.js 22 or later. This alpha package uses ESM and includes TypeScript
|
|
10
|
-
|
|
8
|
+
Requires Node.js 22 or later. This alpha package uses ESM and includes TypeScript types.
|
|
9
|
+
Run it on a server. Browser use is not supported.
|
|
11
10
|
|
|
12
11
|
```sh
|
|
13
|
-
|
|
12
|
+
mkdir rime-quickstart
|
|
13
|
+
cd rime-quickstart
|
|
14
|
+
npm init -y
|
|
15
|
+
npm install @rimelabs/sdk wavefile
|
|
14
16
|
export RIME_API_KEY="your-api-key"
|
|
15
17
|
```
|
|
16
18
|
|
|
17
|
-
|
|
18
|
-
does not load `.env` files.
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
19
|
+
Get a TTS API key from the [Rime dashboard](https://app.rime.ai/).
|
|
20
|
+
An explicit `new Rime({ apiKey: "..." })` overrides `RIME_API_KEY`. The SDK does not load `.env` files.
|
|
21
|
+
The commands below use a macOS or Linux shell.
|
|
22
|
+
|
|
23
|
+
These examples use JavaScript `.mjs` files so you can run them without a TypeScript build.
|
|
24
|
+
The additional [wavefile package](https://github.com/rochars/wavefile) reads and writes WAV files
|
|
25
|
+
for the examples. It is not required by the SDK.
|
|
26
|
+
|
|
27
|
+
## TTS: save speech
|
|
28
|
+
|
|
29
|
+
Save this as `tts.mjs`. It writes a playable `speech.wav` file with no audio-device dependencies.
|
|
30
|
+
|
|
31
|
+
```javascript
|
|
32
|
+
import { writeFileSync } from "node:fs";
|
|
33
|
+
import wavefile from "wavefile";
|
|
34
|
+
import { Rime } from "@rimelabs/sdk";
|
|
35
|
+
|
|
36
|
+
const client = new Rime({ timeout: 60 });
|
|
37
|
+
try {
|
|
38
|
+
const chunks = [];
|
|
39
|
+
for await (const chunk of client.tts.stream(
|
|
40
|
+
"Your appointment is confirmed for tomorrow.",
|
|
41
|
+
)) {
|
|
42
|
+
chunks.push(Buffer.from(chunk));
|
|
43
|
+
}
|
|
44
|
+
const pcm = Buffer.concat(chunks);
|
|
45
|
+
const samples = Array.from({ length: pcm.length / 2 }, (_, i) =>
|
|
46
|
+
pcm.readInt16LE(i * 2),
|
|
47
|
+
);
|
|
48
|
+
const wav = new wavefile.WaveFile();
|
|
49
|
+
wav.fromScratch(1, 24000, "16", samples);
|
|
50
|
+
writeFileSync("speech.wav", wav.toBuffer());
|
|
51
|
+
console.log("Saved speech.wav");
|
|
52
|
+
} finally {
|
|
53
|
+
await client.close();
|
|
54
|
+
}
|
|
28
55
|
```
|
|
29
56
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
Replace the example's async text source with your LLM's text stream. The SDK
|
|
35
|
-
handles sentence boundaries. Coda is the default; select Mist v3 with
|
|
36
|
-
`new Rime({ model: "mistv3" })`.
|
|
37
|
-
The [TTS guide](https://github.com/rimelabs/rime-sdk/blob/main/typescript/docs/tts.md)
|
|
38
|
-
covers voices, formats, and cancellation.
|
|
57
|
+
Run `node tts.mjs`, then open `speech.wav` in your audio player.
|
|
58
|
+
This short example collects the audio in memory before writing the file.
|
|
59
|
+
For long responses, write audio chunks as they arrive.
|
|
39
60
|
|
|
40
|
-
|
|
61
|
+
Coda is the default model. Use `new Rime({ model: "mistv3" })` for Mist v3, or pass
|
|
62
|
+
`{ voice: "your-voice" }` as the second argument to `client.tts.stream(...)` to select a voice.
|
|
63
|
+
The default output is mono 24 kHz PCM16. The example adds its WAV header.
|
|
64
|
+
To supply text from an LLM, pass an async iterable of strings instead of a string.
|
|
65
|
+
The SDK handles sentence boundaries.
|
|
41
66
|
|
|
42
|
-
|
|
43
|
-
the browser captures your microphone and plays replies. Use headphones, and
|
|
44
|
-
speak during a reply to interrupt it. The API key stays on the local server.
|
|
67
|
+
## Prism: send recorded speech
|
|
45
68
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
After the [example setup](https://github.com/rimelabs/rime-sdk/blob/main/examples/README.md#nodejs), run from the repository root:
|
|
69
|
+
Prism needs a deployment that serves its realtime API. Obtain the endpoint,
|
|
70
|
+
credentials, and voice from your deployment operator. The TTS endpoint does not serve Prism.
|
|
71
|
+
Set `RIME_API_KEY` to the credential for that deployment if it differs from your TTS key.
|
|
51
72
|
|
|
52
73
|
```sh
|
|
53
|
-
|
|
74
|
+
export PRISM_URL="wss://your-prism-host/v1/realtime"
|
|
75
|
+
export PRISM_VOICE="your-deployment-voice"
|
|
54
76
|
```
|
|
55
77
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
78
|
+
You can omit `PRISM_VOICE` if the deployment has a default voice.
|
|
79
|
+
Record a short question and export it as `question.wav`, using **16 kHz, mono, signed 16-bit PCM WAV**.
|
|
80
|
+
Save the following as `prism.mjs` beside that file. It sends the recording at capture speed,
|
|
81
|
+
then sends silence so Prism can detect the end of speech. The spoken reply goes to `reply.wav`.
|
|
82
|
+
|
|
83
|
+
```javascript
|
|
84
|
+
import { readFileSync, writeFileSync } from "node:fs";
|
|
85
|
+
import { setTimeout as sleep } from "node:timers/promises";
|
|
86
|
+
import wavefile from "wavefile";
|
|
87
|
+
import { Rime, RimeRealtimeError } from "@rimelabs/sdk";
|
|
88
|
+
|
|
89
|
+
const input = new wavefile.WaveFile(readFileSync("question.wav"));
|
|
90
|
+
if (
|
|
91
|
+
input.container !== "RIFF" ||
|
|
92
|
+
input.fmt.audioFormat !== 1 ||
|
|
93
|
+
input.fmt.numChannels !== 1 ||
|
|
94
|
+
input.fmt.sampleRate !== 16000 ||
|
|
95
|
+
input.bitDepth !== "16"
|
|
96
|
+
) {
|
|
97
|
+
throw new Error("question.wav must be 16 kHz mono PCM16");
|
|
98
|
+
}
|
|
99
|
+
const data = Buffer.from(input.data.samples);
|
|
100
|
+
if (!data.length || data.length % 2)
|
|
101
|
+
throw new Error("question.wav has no complete PCM16 audio");
|
|
102
|
+
const endpoint = process.env.PRISM_URL;
|
|
103
|
+
if (!endpoint)
|
|
104
|
+
throw new Error("Set PRISM_URL to your deployment's /v1/realtime URL");
|
|
105
|
+
|
|
106
|
+
const client = new Rime();
|
|
107
|
+
const stop = new AbortController();
|
|
108
|
+
const deadline = setTimeout(() => {
|
|
109
|
+
stop.abort();
|
|
110
|
+
void client.close();
|
|
111
|
+
}, 60_000);
|
|
112
|
+
let sending;
|
|
113
|
+
let reading;
|
|
114
|
+
try {
|
|
115
|
+
const session = await client.realtime.connect({
|
|
116
|
+
endpoint,
|
|
117
|
+
voice: process.env.PRISM_VOICE,
|
|
118
|
+
instructions: "Give short, clear answers.",
|
|
119
|
+
});
|
|
120
|
+
sending = (async () => {
|
|
121
|
+
for (let offset = 0; ; offset += 1280) {
|
|
122
|
+
const frame = Buffer.alloc(1280);
|
|
123
|
+
if (offset < data.length)
|
|
124
|
+
data.copy(frame, 0, offset, Math.min(offset + 1280, data.length));
|
|
125
|
+
await session.sendAudio({ data: frame });
|
|
126
|
+
await sleep(40, undefined, { signal: stop.signal });
|
|
127
|
+
}
|
|
128
|
+
})();
|
|
129
|
+
const chunks = [];
|
|
130
|
+
reading = (async () => {
|
|
131
|
+
for await (const { payload } of session.events) {
|
|
132
|
+
if (payload.kind === "audio.delta")
|
|
133
|
+
chunks.push(Buffer.from(payload.audio.data));
|
|
134
|
+
if (payload.kind === "error") throw new RimeRealtimeError(payload.error);
|
|
135
|
+
if (payload.kind === "response.ended") {
|
|
136
|
+
if (payload.status !== "completed") {
|
|
137
|
+
throw new Error(`Response ${payload.status}: ${payload.reason}`);
|
|
138
|
+
}
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
throw new Error("Session closed before the reply ended");
|
|
143
|
+
})();
|
|
144
|
+
await Promise.race([sending, reading]);
|
|
145
|
+
const pcm = Buffer.concat(chunks);
|
|
146
|
+
const samples = Array.from({ length: pcm.length / 2 }, (_, i) =>
|
|
147
|
+
pcm.readInt16LE(i * 2),
|
|
148
|
+
);
|
|
149
|
+
const wav = new wavefile.WaveFile();
|
|
150
|
+
wav.fromScratch(1, 24000, "16", samples);
|
|
151
|
+
writeFileSync("reply.wav", wav.toBuffer());
|
|
152
|
+
console.log("Saved reply.wav");
|
|
153
|
+
} finally {
|
|
154
|
+
stop.abort();
|
|
155
|
+
clearTimeout(deadline);
|
|
156
|
+
await client.close();
|
|
157
|
+
await Promise.allSettled([sending, reading]);
|
|
158
|
+
}
|
|
61
159
|
```
|
|
62
160
|
|
|
63
|
-
Run `prism
|
|
64
|
-
|
|
65
|
-
|
|
161
|
+
Run `node prism.mjs`, then open `reply.wav`. This example has a 60-second deadline
|
|
162
|
+
and collects the reply in memory. It saves audio without playing it, so it sends no playback receipt.
|
|
163
|
+
For live conversations, your application must capture microphone audio, play replies,
|
|
164
|
+
stop playback on interruption, and report the actual played position to Prism.
|
|
165
|
+
Keep the API key on your server when you add a browser interface.
|
|
66
166
|
TTS settings do not configure Prism sessions.
|
|
67
167
|
|
|
68
|
-
##
|
|
168
|
+
## Help and licenses
|
|
169
|
+
|
|
170
|
+
See [Rime documentation](https://docs.rime.ai/) for API keys, TTS models, and deployment information.
|
|
171
|
+
The examples above run with the installed package. No source checkout is required.
|
|
69
172
|
|
|
70
|
-
SDK code uses the
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
Its WASM runtime ships with the package; the SDK downloads no code or models at
|
|
74
|
-
runtime. See [vendor provenance](https://github.com/rimelabs/rime-sdk/blob/main/typescript/vendor/README.md).
|
|
173
|
+
SDK code uses the MIT license. The Prism protocol module uses Apache 2.0.
|
|
174
|
+
BlingFire retains its MIT license. License texts and notices are included in the package.
|
|
175
|
+
Its WASM runtime ships with the package. The SDK downloads no code or models at runtime.
|
package/docs/realtime.md
CHANGED
|
@@ -4,16 +4,12 @@ Keep one event consumer running while your application sends input, runs tools,
|
|
|
4
4
|
and plays audio. The SDK manages the protocol state. Your application owns
|
|
5
5
|
microphone capture, tool execution, and playback.
|
|
6
6
|
|
|
7
|
-
Start with the [
|
|
8
|
-
|
|
9
|
-
[recorded-speech example](https://github.com/rimelabs/rime-sdk/blob/main/examples/typescript/realtime/recorded.ts)
|
|
10
|
-
saves a spoken reply without audio hardware. See the
|
|
11
|
-
[example setup](https://github.com/rimelabs/rime-sdk/blob/main/examples/README.md)
|
|
12
|
-
for commands, device requirements, and the voice tool example.
|
|
7
|
+
Start with the [recorded-speech quick start](../README.md#prism-send-recorded-speech)
|
|
8
|
+
to save a spoken reply without audio hardware.
|
|
13
9
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
10
|
+
For live conversations, keep the session open after normal cancellation and
|
|
11
|
+
report playback from the output clock. Saving a file is not playback.
|
|
12
|
+
Typed turns also support mixed text and voice applications.
|
|
17
13
|
|
|
18
14
|
## Connect
|
|
19
15
|
|
|
@@ -112,10 +108,9 @@ Use `JSON.stringify(...)` for a structured result. Call
|
|
|
112
108
|
`continueReply(payload.call)` when the assistant should answer; a tool call
|
|
113
109
|
reference also carries its parent response identity.
|
|
114
110
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
so they do not block the Node.js event loop.
|
|
111
|
+
Keep the event consumer running while submitting tool results and requesting
|
|
112
|
+
continuation. Run slow tools asynchronously or in a worker so they do not block
|
|
113
|
+
the event loop.
|
|
119
114
|
|
|
120
115
|
A new user turn or proactive reply supersedes the old tool round. Late results
|
|
121
116
|
can still be recorded. Use `requestReply({ toolCall: call })` to ask the assistant
|
|
@@ -221,6 +216,5 @@ Keep up with the event stream. The queue holds 256 events; incoming messages
|
|
|
221
216
|
are limited to 1 MiB. A slow consumer ends the session. There is no automatic
|
|
222
217
|
reconnect, history replay, or live configuration update.
|
|
223
218
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
still need validation for the deployment you use.
|
|
219
|
+
Local peer tests cover the SDK protocol handling. Validate the gateway handshake
|
|
220
|
+
and endpoint behavior for the deployment you use.
|
package/docs/tts.md
CHANGED
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
# TTS for Node.js
|
|
2
2
|
|
|
3
3
|
You supply text; the SDK handles sentence boundaries and streams audio back.
|
|
4
|
-
Your application owns playback. Start with the
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
For a playable file, use [save speech](https://github.com/rimelabs/rime-sdk/blob/main/examples/typescript/tts/save.ts).
|
|
8
|
-
For immediate playback and cancellation, use [stream and play](https://github.com/rimelabs/rime-sdk/blob/main/examples/typescript/tts/play.ts).
|
|
9
|
-
Both accept the same SDK text stream; device dependencies stay in the examples.
|
|
4
|
+
Your application owns playback. Start with the complete WAV example in the
|
|
5
|
+
[package quick start](../README.md#tts-save-speech).
|
|
10
6
|
|
|
11
7
|
## Stream incoming text
|
|
12
8
|
|
|
@@ -21,7 +17,7 @@ async function* text() {
|
|
|
21
17
|
|
|
22
18
|
Use `client.tts.stream(text())` with the same file write and cleanup.
|
|
23
19
|
The SDK handles sentence boundaries. Do not await `tts.stream()`; the first
|
|
24
|
-
iterator read starts work.
|
|
20
|
+
iterator read starts work. The quick start collects chunks before writing a WAV file.
|
|
25
21
|
|
|
26
22
|
## Configuration
|
|
27
23
|
|
package/package.json
CHANGED
|
@@ -1,13 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rimelabs/sdk",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.9",
|
|
4
4
|
"description": "Rime streaming TTS and Prism realtime 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
|
-
},
|
|
11
6
|
"type": "module",
|
|
12
7
|
"engines": {
|
|
13
8
|
"node": ">=22"
|
|
@@ -49,5 +44,6 @@
|
|
|
49
44
|
"prettier": "3.9.8",
|
|
50
45
|
"typescript": "^5.9.0",
|
|
51
46
|
"yaml": "^2.9.1"
|
|
52
|
-
}
|
|
47
|
+
},
|
|
48
|
+
"homepage": "https://docs.rime.ai/"
|
|
53
49
|
}
|