@sayna-ai/node-sdk 0.0.2
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/README.md +229 -0
- package/dist/errors.d.ts +38 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/index.d.ts +65 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +454 -0
- package/dist/index.js.map +12 -0
- package/dist/sayna-client.d.ts +303 -0
- package/dist/sayna-client.d.ts.map +1 -0
- package/dist/types.d.ts +255 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +62 -0
package/README.md
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
# @sayna/node-sdk
|
|
2
|
+
|
|
3
|
+
Sayna's Node.js SDK enables real-time voice interactions through WebSocket connections. Send audio for speech recognition, receive synthesized speech, and manage voice sessions from your Node.js applications.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- WebSocket-based real-time voice communication
|
|
8
|
+
- Speech-to-text (STT) with configurable providers
|
|
9
|
+
- Text-to-speech (TTS) with audio streaming
|
|
10
|
+
- LiveKit integration support
|
|
11
|
+
- Type-safe message handling
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install @sayna/node-sdk
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
import { SaynaClient } from "@sayna/node-sdk";
|
|
23
|
+
|
|
24
|
+
const client = new SaynaClient(
|
|
25
|
+
"https://api.sayna.ai",
|
|
26
|
+
{ provider: "deepgram", model: "nova-2" },
|
|
27
|
+
{ provider: "cartesia", voice_id: "example-voice" }
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
client.registerOnSttResult((result) => {
|
|
31
|
+
console.log("Transcription:", result.transcript);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
client.registerOnTtsAudio((audio) => {
|
|
35
|
+
// Handle audio buffer
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
await client.connect();
|
|
39
|
+
await client.speak("Hello, world!");
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## API
|
|
43
|
+
|
|
44
|
+
### REST API Methods
|
|
45
|
+
|
|
46
|
+
These methods use HTTP endpoints and don't require an active WebSocket connection:
|
|
47
|
+
|
|
48
|
+
### `await client.health()`
|
|
49
|
+
|
|
50
|
+
Performs a health check on the Sayna server.
|
|
51
|
+
|
|
52
|
+
**Returns**: `Promise<{ status: string }>` - Status object with "OK" when healthy.
|
|
53
|
+
|
|
54
|
+
**Example**:
|
|
55
|
+
```typescript
|
|
56
|
+
const health = await client.health();
|
|
57
|
+
console.log(health.status); // "OK"
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### `await client.getVoices()`
|
|
61
|
+
|
|
62
|
+
Retrieves the catalogue of text-to-speech voices grouped by provider.
|
|
63
|
+
|
|
64
|
+
**Returns**: `Promise<Record<string, Voice[]>>` - Object where keys are provider names and values are arrays of voice descriptors.
|
|
65
|
+
|
|
66
|
+
**Example**:
|
|
67
|
+
```typescript
|
|
68
|
+
const voices = await client.getVoices();
|
|
69
|
+
for (const [provider, voiceList] of Object.entries(voices)) {
|
|
70
|
+
console.log(`${provider}:`, voiceList.map(v => v.name));
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### `await client.speakRest(text, ttsConfig)`
|
|
75
|
+
|
|
76
|
+
Synthesizes text into audio using the REST API. This is a standalone method that doesn't require an active WebSocket connection.
|
|
77
|
+
|
|
78
|
+
| parameter | type | purpose |
|
|
79
|
+
| --- | --- | --- |
|
|
80
|
+
| `text` | `string` | Text to synthesize (must be non-empty). |
|
|
81
|
+
| `ttsConfig` | `TTSConfig` | Text-to-speech provider configuration. |
|
|
82
|
+
|
|
83
|
+
**Returns**: `Promise<ArrayBuffer>` - Raw audio data.
|
|
84
|
+
|
|
85
|
+
**Example**:
|
|
86
|
+
```typescript
|
|
87
|
+
const audioBuffer = await client.speakRest("Hello, world!", {
|
|
88
|
+
provider: "elevenlabs",
|
|
89
|
+
voice_id: "21m00Tcm4TlvDq8ikWAM",
|
|
90
|
+
model: "eleven_turbo_v2",
|
|
91
|
+
speaking_rate: 1.0,
|
|
92
|
+
audio_format: "mp3",
|
|
93
|
+
sample_rate: 24000,
|
|
94
|
+
connection_timeout: 30,
|
|
95
|
+
request_timeout: 60,
|
|
96
|
+
pronunciations: []
|
|
97
|
+
});
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### `await client.getLiveKitToken(roomName, participantName, participantIdentity)`
|
|
101
|
+
|
|
102
|
+
Issues a LiveKit access token for a participant.
|
|
103
|
+
|
|
104
|
+
| parameter | type | purpose |
|
|
105
|
+
| --- | --- | --- |
|
|
106
|
+
| `roomName` | `string` | LiveKit room to join or create. |
|
|
107
|
+
| `participantName` | `string` | Display name for the participant. |
|
|
108
|
+
| `participantIdentity` | `string` | Unique identifier for the participant. |
|
|
109
|
+
|
|
110
|
+
**Returns**: `Promise<LiveKitTokenResponse>` - Object containing token, room name, participant identity, and LiveKit URL.
|
|
111
|
+
|
|
112
|
+
**Example**:
|
|
113
|
+
```typescript
|
|
114
|
+
const tokenInfo = await client.getLiveKitToken(
|
|
115
|
+
"my-room",
|
|
116
|
+
"John Doe",
|
|
117
|
+
"user-123"
|
|
118
|
+
);
|
|
119
|
+
console.log("Token:", tokenInfo.token);
|
|
120
|
+
console.log("LiveKit URL:", tokenInfo.livekit_url);
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
### WebSocket API Methods
|
|
126
|
+
|
|
127
|
+
These methods require an active WebSocket connection:
|
|
128
|
+
|
|
129
|
+
### `new SaynaClient(url, sttConfig, ttsConfig, livekitConfig?, withoutAudio?)`
|
|
130
|
+
|
|
131
|
+
| parameter | type | purpose |
|
|
132
|
+
| --- | --- | --- |
|
|
133
|
+
| `url` | `string` | Sayna server URL (http://, https://, ws://, or wss://). |
|
|
134
|
+
| `sttConfig` | `STTConfig` | Speech-to-text provider configuration. |
|
|
135
|
+
| `ttsConfig` | `TTSConfig` | Text-to-speech provider configuration. |
|
|
136
|
+
| `livekitConfig` | `LiveKitConfig` | Optional LiveKit room configuration. |
|
|
137
|
+
| `withoutAudio` | `boolean` | Disable audio streaming (defaults to `false`). |
|
|
138
|
+
|
|
139
|
+
### `await client.connect()`
|
|
140
|
+
|
|
141
|
+
Establishes WebSocket connection and sends initial configuration. Resolves when server sends ready message.
|
|
142
|
+
|
|
143
|
+
### `client.registerOnSttResult(callback)`
|
|
144
|
+
|
|
145
|
+
Registers a callback for speech-to-text transcription results.
|
|
146
|
+
|
|
147
|
+
### `client.registerOnTtsAudio(callback)`
|
|
148
|
+
|
|
149
|
+
Registers a callback for text-to-speech audio data (ArrayBuffer).
|
|
150
|
+
|
|
151
|
+
### `client.registerOnError(callback)`
|
|
152
|
+
|
|
153
|
+
Registers a callback for error messages.
|
|
154
|
+
|
|
155
|
+
### `client.registerOnMessage(callback)`
|
|
156
|
+
|
|
157
|
+
Registers a callback for participant messages.
|
|
158
|
+
|
|
159
|
+
### `client.registerOnParticipantDisconnected(callback)`
|
|
160
|
+
|
|
161
|
+
Registers a callback for participant disconnection events.
|
|
162
|
+
|
|
163
|
+
### `client.registerOnTtsPlaybackComplete(callback)`
|
|
164
|
+
|
|
165
|
+
Registers a callback for TTS playback completion events.
|
|
166
|
+
|
|
167
|
+
### `await client.speak(text, flush?, allowInterruption?)`
|
|
168
|
+
|
|
169
|
+
Sends text to be synthesized as speech.
|
|
170
|
+
|
|
171
|
+
| parameter | type | default | purpose |
|
|
172
|
+
| --- | --- | --- | --- |
|
|
173
|
+
| `text` | `string` | - | Text to synthesize. |
|
|
174
|
+
| `flush` | `boolean` | `true` | Clear TTS queue before speaking. |
|
|
175
|
+
| `allowInterruption` | `boolean` | `true` | Allow speech to be interrupted. |
|
|
176
|
+
|
|
177
|
+
### `await client.onAudioInput(audioData)`
|
|
178
|
+
|
|
179
|
+
Sends raw audio data (ArrayBuffer) to the server for speech recognition.
|
|
180
|
+
|
|
181
|
+
### `await client.sendMessage(message, role, topic?, debug?)`
|
|
182
|
+
|
|
183
|
+
Sends a message to the Sayna session with role and optional metadata.
|
|
184
|
+
|
|
185
|
+
### `await client.clear()`
|
|
186
|
+
|
|
187
|
+
Clears the text-to-speech queue.
|
|
188
|
+
|
|
189
|
+
### `await client.ttsFlush(allowInterruption?)`
|
|
190
|
+
|
|
191
|
+
Flushes the TTS queue by sending an empty speak command.
|
|
192
|
+
|
|
193
|
+
### `await client.disconnect()`
|
|
194
|
+
|
|
195
|
+
Disconnects from the WebSocket server and cleans up resources.
|
|
196
|
+
|
|
197
|
+
### `client.ready`
|
|
198
|
+
|
|
199
|
+
Boolean indicating whether the client is ready to send/receive data.
|
|
200
|
+
|
|
201
|
+
### `client.connected`
|
|
202
|
+
|
|
203
|
+
Boolean indicating whether the WebSocket connection is active.
|
|
204
|
+
|
|
205
|
+
### `client.livekitRoomName`
|
|
206
|
+
|
|
207
|
+
LiveKit room name acknowledged by the server, if available (present when LiveKit is enabled).
|
|
208
|
+
|
|
209
|
+
### `client.livekitUrl`
|
|
210
|
+
|
|
211
|
+
LiveKit WebSocket URL configured on the server, if available.
|
|
212
|
+
|
|
213
|
+
### `client.saynaParticipantIdentity`
|
|
214
|
+
|
|
215
|
+
Identity assigned to the agent participant when LiveKit is enabled, if available.
|
|
216
|
+
|
|
217
|
+
### `client.saynaParticipantName`
|
|
218
|
+
|
|
219
|
+
Display name assigned to the agent participant when LiveKit is enabled, if available.
|
|
220
|
+
|
|
221
|
+
## Development
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
bun install
|
|
225
|
+
bun run typecheck
|
|
226
|
+
bun run build
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
The repository uses Bun for dependency management and builds. The `build` script emits ready-to-publish JavaScript and type definitions in `dist/`.
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base error class for all Sayna SDK errors.
|
|
3
|
+
*/
|
|
4
|
+
export declare class SaynaError extends Error {
|
|
5
|
+
constructor(message: string);
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Error thrown when attempting to use the client before it's connected.
|
|
9
|
+
*/
|
|
10
|
+
export declare class SaynaNotConnectedError extends SaynaError {
|
|
11
|
+
constructor(message?: string);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Error thrown when attempting operations before the client is ready.
|
|
15
|
+
*/
|
|
16
|
+
export declare class SaynaNotReadyError extends SaynaError {
|
|
17
|
+
constructor(message?: string);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Error thrown when WebSocket connection fails.
|
|
21
|
+
*/
|
|
22
|
+
export declare class SaynaConnectionError extends SaynaError {
|
|
23
|
+
readonly cause?: unknown;
|
|
24
|
+
constructor(message: string, cause?: unknown);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Error thrown when invalid parameters are provided.
|
|
28
|
+
*/
|
|
29
|
+
export declare class SaynaValidationError extends SaynaError {
|
|
30
|
+
constructor(message: string);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Error thrown when the server returns an error.
|
|
34
|
+
*/
|
|
35
|
+
export declare class SaynaServerError extends SaynaError {
|
|
36
|
+
constructor(message: string);
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,UAAW,SAAQ,KAAK;gBACvB,OAAO,EAAE,MAAM;CAK5B;AAED;;GAEG;AACH,qBAAa,sBAAuB,SAAQ,UAAU;gBACxC,OAAO,GAAE,MAA2C;CAKjE;AAED;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,UAAU;gBAE9C,OAAO,GAAE,MAA0F;CAMtG;AAED;;GAEG;AACH,qBAAa,oBAAqB,SAAQ,UAAU;IAClD,SAAyB,KAAK,CAAC,EAAE,OAAO,CAAC;gBAE7B,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO;CAM7C;AAED;;GAEG;AACH,qBAAa,oBAAqB,SAAQ,UAAU;gBACtC,OAAO,EAAE,MAAM;CAK5B;AAED;;GAEG;AACH,qBAAa,gBAAiB,SAAQ,UAAU;gBAClC,OAAO,EAAE,MAAM;CAK5B"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { SaynaClient } from "./sayna-client";
|
|
2
|
+
import { STTConfig, TTSConfig, LiveKitConfig } from "./types";
|
|
3
|
+
export * from "./sayna-client";
|
|
4
|
+
export * from "./types";
|
|
5
|
+
export * from "./errors";
|
|
6
|
+
/**
|
|
7
|
+
* Creates and connects a new SaynaClient instance.
|
|
8
|
+
*
|
|
9
|
+
* This is the recommended way to create a Sayna client. It handles both
|
|
10
|
+
* instantiation and connection, returning a ready-to-use client.
|
|
11
|
+
*
|
|
12
|
+
* @param url - The Sayna server URL (e.g., "https://api.sayna.ai")
|
|
13
|
+
* @param sttConfig - Speech-to-text configuration
|
|
14
|
+
* @param ttsConfig - Text-to-speech configuration
|
|
15
|
+
* @param livekitConfig - Optional LiveKit room configuration
|
|
16
|
+
* @param withoutAudio - If true, disables audio streaming (default: false)
|
|
17
|
+
*
|
|
18
|
+
* @returns Promise that resolves to a connected SaynaClient
|
|
19
|
+
*
|
|
20
|
+
* @throws {SaynaValidationError} If parameters are invalid
|
|
21
|
+
* @throws {SaynaConnectionError} If connection fails
|
|
22
|
+
* @throws {SaynaServerError} If server returns an error during setup
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* import { saynaConnect } from "@sayna/node-sdk";
|
|
27
|
+
*
|
|
28
|
+
* const client = await saynaConnect(
|
|
29
|
+
* "https://api.sayna.ai",
|
|
30
|
+
* {
|
|
31
|
+
* provider: "deepgram",
|
|
32
|
+
* language: "en-US",
|
|
33
|
+
* sample_rate: 16000,
|
|
34
|
+
* channels: 1,
|
|
35
|
+
* punctuation: true,
|
|
36
|
+
* encoding: "linear16",
|
|
37
|
+
* model: "nova-2"
|
|
38
|
+
* },
|
|
39
|
+
* {
|
|
40
|
+
* provider: "elevenlabs",
|
|
41
|
+
* voice_id: "21m00Tcm4TlvDq8ikWAM",
|
|
42
|
+
* speaking_rate: 1.0,
|
|
43
|
+
* audio_format: "pcm",
|
|
44
|
+
* sample_rate: 16000,
|
|
45
|
+
* connection_timeout: 5000,
|
|
46
|
+
* request_timeout: 10000,
|
|
47
|
+
* model: "eleven_turbo_v2",
|
|
48
|
+
* pronunciations: []
|
|
49
|
+
* }
|
|
50
|
+
* );
|
|
51
|
+
*
|
|
52
|
+
* // Register event handlers
|
|
53
|
+
* client.registerOnSttResult((result) => {
|
|
54
|
+
* console.log("Transcription:", result.transcript);
|
|
55
|
+
* });
|
|
56
|
+
*
|
|
57
|
+
* // Send text to be spoken
|
|
58
|
+
* await client.speak("Hello, world!");
|
|
59
|
+
*
|
|
60
|
+
* // Clean up
|
|
61
|
+
* await client.disconnect();
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
export declare function saynaConnect(url: string, sttConfig: STTConfig, ttsConfig: TTSConfig, livekitConfig?: LiveKitConfig, withoutAudio?: boolean): Promise<SaynaClient>;
|
|
65
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE9D,cAAc,gBAAgB,CAAC;AAC/B,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AAEzB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyDG;AACH,wBAAsB,YAAY,CAChC,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,SAAS,EACpB,SAAS,EAAE,SAAS,EACpB,aAAa,CAAC,EAAE,aAAa,EAC7B,YAAY,GAAE,OAAe,GAC5B,OAAO,CAAC,WAAW,CAAC,CAUtB"}
|