@lokutor/sdk 1.0.0 → 1.1.0
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/dist/index.d.mts +5 -8
- package/dist/index.d.ts +5 -8
- package/dist/index.js +43 -37
- package/dist/index.mjs +43 -37
- package/package.json +3 -6
package/dist/index.d.mts
CHANGED
|
@@ -47,7 +47,7 @@ interface LokutorConfig {
|
|
|
47
47
|
serverUrl?: string;
|
|
48
48
|
onTranscription?: (text: string) => void;
|
|
49
49
|
onResponse?: (text: string) => void;
|
|
50
|
-
onAudio?: (data:
|
|
50
|
+
onAudio?: (data: Uint8Array) => void;
|
|
51
51
|
onStatus?: (status: string) => void;
|
|
52
52
|
onError?: (error: any) => void;
|
|
53
53
|
}
|
|
@@ -98,7 +98,7 @@ declare class VoiceAgentClient {
|
|
|
98
98
|
* Send raw PCM audio data to the server
|
|
99
99
|
* @param audioData Int16 PCM audio buffer
|
|
100
100
|
*/
|
|
101
|
-
sendAudio(audioData:
|
|
101
|
+
sendAudio(audioData: Uint8Array): void;
|
|
102
102
|
/**
|
|
103
103
|
* Handle incoming binary data (audio response)
|
|
104
104
|
*/
|
|
@@ -109,7 +109,7 @@ declare class VoiceAgentClient {
|
|
|
109
109
|
private handleTextMessage;
|
|
110
110
|
private audioListeners;
|
|
111
111
|
private emit;
|
|
112
|
-
onAudio(callback: (data:
|
|
112
|
+
onAudio(callback: (data: Uint8Array) => void): void;
|
|
113
113
|
/**
|
|
114
114
|
* Disconnect from the server
|
|
115
115
|
*/
|
|
@@ -121,9 +121,6 @@ declare class VoiceAgentClient {
|
|
|
121
121
|
declare class TTSClient {
|
|
122
122
|
private apiKey;
|
|
123
123
|
private serverUrl;
|
|
124
|
-
private onAudioCallback?;
|
|
125
|
-
private onVisemesCallback?;
|
|
126
|
-
private onErrorCallback?;
|
|
127
124
|
constructor(config: {
|
|
128
125
|
apiKey: string;
|
|
129
126
|
serverUrl?: string;
|
|
@@ -141,7 +138,7 @@ declare class TTSClient {
|
|
|
141
138
|
speed?: number;
|
|
142
139
|
steps?: number;
|
|
143
140
|
visemes?: boolean;
|
|
144
|
-
onAudio?: (data:
|
|
141
|
+
onAudio?: (data: Uint8Array) => void;
|
|
145
142
|
onVisemes?: (visemes: any[]) => void;
|
|
146
143
|
onError?: (error: any) => void;
|
|
147
144
|
}): Promise<void>;
|
|
@@ -157,7 +154,7 @@ declare function simpleConversation(config: LokutorConfig & {
|
|
|
157
154
|
*/
|
|
158
155
|
declare function simpleTTS(options: SynthesizeOptions & {
|
|
159
156
|
apiKey: string;
|
|
160
|
-
onAudio: (buf:
|
|
157
|
+
onAudio: (buf: Uint8Array) => void;
|
|
161
158
|
}): Promise<void>;
|
|
162
159
|
|
|
163
160
|
export { AUDIO_CONFIG, DEFAULT_URLS, Language, type LokutorConfig, type SynthesizeOptions, TTSClient, VoiceAgentClient, VoiceStyle, simpleConversation, simpleTTS };
|
package/dist/index.d.ts
CHANGED
|
@@ -47,7 +47,7 @@ interface LokutorConfig {
|
|
|
47
47
|
serverUrl?: string;
|
|
48
48
|
onTranscription?: (text: string) => void;
|
|
49
49
|
onResponse?: (text: string) => void;
|
|
50
|
-
onAudio?: (data:
|
|
50
|
+
onAudio?: (data: Uint8Array) => void;
|
|
51
51
|
onStatus?: (status: string) => void;
|
|
52
52
|
onError?: (error: any) => void;
|
|
53
53
|
}
|
|
@@ -98,7 +98,7 @@ declare class VoiceAgentClient {
|
|
|
98
98
|
* Send raw PCM audio data to the server
|
|
99
99
|
* @param audioData Int16 PCM audio buffer
|
|
100
100
|
*/
|
|
101
|
-
sendAudio(audioData:
|
|
101
|
+
sendAudio(audioData: Uint8Array): void;
|
|
102
102
|
/**
|
|
103
103
|
* Handle incoming binary data (audio response)
|
|
104
104
|
*/
|
|
@@ -109,7 +109,7 @@ declare class VoiceAgentClient {
|
|
|
109
109
|
private handleTextMessage;
|
|
110
110
|
private audioListeners;
|
|
111
111
|
private emit;
|
|
112
|
-
onAudio(callback: (data:
|
|
112
|
+
onAudio(callback: (data: Uint8Array) => void): void;
|
|
113
113
|
/**
|
|
114
114
|
* Disconnect from the server
|
|
115
115
|
*/
|
|
@@ -121,9 +121,6 @@ declare class VoiceAgentClient {
|
|
|
121
121
|
declare class TTSClient {
|
|
122
122
|
private apiKey;
|
|
123
123
|
private serverUrl;
|
|
124
|
-
private onAudioCallback?;
|
|
125
|
-
private onVisemesCallback?;
|
|
126
|
-
private onErrorCallback?;
|
|
127
124
|
constructor(config: {
|
|
128
125
|
apiKey: string;
|
|
129
126
|
serverUrl?: string;
|
|
@@ -141,7 +138,7 @@ declare class TTSClient {
|
|
|
141
138
|
speed?: number;
|
|
142
139
|
steps?: number;
|
|
143
140
|
visemes?: boolean;
|
|
144
|
-
onAudio?: (data:
|
|
141
|
+
onAudio?: (data: Uint8Array) => void;
|
|
145
142
|
onVisemes?: (visemes: any[]) => void;
|
|
146
143
|
onError?: (error: any) => void;
|
|
147
144
|
}): Promise<void>;
|
|
@@ -157,7 +154,7 @@ declare function simpleConversation(config: LokutorConfig & {
|
|
|
157
154
|
*/
|
|
158
155
|
declare function simpleTTS(options: SynthesizeOptions & {
|
|
159
156
|
apiKey: string;
|
|
160
|
-
onAudio: (buf:
|
|
157
|
+
onAudio: (buf: Uint8Array) => void;
|
|
161
158
|
}): Promise<void>;
|
|
162
159
|
|
|
163
160
|
export { AUDIO_CONFIG, DEFAULT_URLS, Language, type LokutorConfig, type SynthesizeOptions, TTSClient, VoiceAgentClient, VoiceStyle, simpleConversation, simpleTTS };
|
package/dist/index.js
CHANGED
|
@@ -67,7 +67,14 @@ var DEFAULT_URLS = {
|
|
|
67
67
|
};
|
|
68
68
|
|
|
69
69
|
// src/client.ts
|
|
70
|
-
|
|
70
|
+
function base64ToUint8Array(base64) {
|
|
71
|
+
const binaryString = atob(base64);
|
|
72
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
73
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
74
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
75
|
+
}
|
|
76
|
+
return bytes;
|
|
77
|
+
}
|
|
71
78
|
var VoiceAgentClient = class {
|
|
72
79
|
ws = null;
|
|
73
80
|
apiKey;
|
|
@@ -100,36 +107,36 @@ var VoiceAgentClient = class {
|
|
|
100
107
|
async connect() {
|
|
101
108
|
return new Promise((resolve, reject) => {
|
|
102
109
|
try {
|
|
103
|
-
|
|
104
|
-
const headers = {};
|
|
110
|
+
let url = this.serverUrl;
|
|
105
111
|
if (this.apiKey) {
|
|
106
|
-
|
|
112
|
+
const separator = url.includes("?") ? "&" : "?";
|
|
113
|
+
url += `${separator}api_key=${this.apiKey}`;
|
|
107
114
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
this.ws.
|
|
115
|
+
console.log(`\u{1F517} Connecting to ${this.serverUrl}...`);
|
|
116
|
+
this.ws = new WebSocket(url);
|
|
117
|
+
this.ws.binaryType = "arraybuffer";
|
|
118
|
+
this.ws.onopen = () => {
|
|
112
119
|
this.isConnected = true;
|
|
113
120
|
console.log("\u2705 Connected to voice agent!");
|
|
114
121
|
this.sendConfig();
|
|
115
122
|
resolve(true);
|
|
116
|
-
}
|
|
117
|
-
this.ws.
|
|
118
|
-
if (
|
|
119
|
-
this.handleBinaryMessage(data);
|
|
123
|
+
};
|
|
124
|
+
this.ws.onmessage = async (event) => {
|
|
125
|
+
if (event.data instanceof ArrayBuffer) {
|
|
126
|
+
this.handleBinaryMessage(new Uint8Array(event.data));
|
|
120
127
|
} else {
|
|
121
|
-
this.handleTextMessage(data.toString());
|
|
128
|
+
this.handleTextMessage(event.data.toString());
|
|
122
129
|
}
|
|
123
|
-
}
|
|
124
|
-
this.ws.
|
|
130
|
+
};
|
|
131
|
+
this.ws.onerror = (err) => {
|
|
125
132
|
console.error("\u274C WebSocket error:", err);
|
|
126
133
|
if (this.onError) this.onError(err);
|
|
127
134
|
if (!this.isConnected) reject(err);
|
|
128
|
-
}
|
|
129
|
-
this.ws.
|
|
135
|
+
};
|
|
136
|
+
this.ws.onclose = () => {
|
|
130
137
|
this.isConnected = false;
|
|
131
138
|
console.log("Disconnected");
|
|
132
|
-
}
|
|
139
|
+
};
|
|
133
140
|
} catch (err) {
|
|
134
141
|
if (this.onError) this.onError(err);
|
|
135
142
|
reject(err);
|
|
@@ -152,7 +159,7 @@ var VoiceAgentClient = class {
|
|
|
152
159
|
*/
|
|
153
160
|
sendAudio(audioData) {
|
|
154
161
|
if (this.ws && this.isConnected) {
|
|
155
|
-
this.ws.send(audioData
|
|
162
|
+
this.ws.send(audioData);
|
|
156
163
|
}
|
|
157
164
|
}
|
|
158
165
|
/**
|
|
@@ -170,7 +177,7 @@ var VoiceAgentClient = class {
|
|
|
170
177
|
switch (msg.type) {
|
|
171
178
|
case "audio":
|
|
172
179
|
if (msg.data) {
|
|
173
|
-
const buffer =
|
|
180
|
+
const buffer = base64ToUint8Array(msg.data);
|
|
174
181
|
this.handleBinaryMessage(buffer);
|
|
175
182
|
}
|
|
176
183
|
break;
|
|
@@ -224,9 +231,6 @@ var VoiceAgentClient = class {
|
|
|
224
231
|
var TTSClient = class {
|
|
225
232
|
apiKey;
|
|
226
233
|
serverUrl;
|
|
227
|
-
onAudioCallback;
|
|
228
|
-
onVisemesCallback;
|
|
229
|
-
onErrorCallback;
|
|
230
234
|
constructor(config) {
|
|
231
235
|
this.apiKey = config.apiKey;
|
|
232
236
|
this.serverUrl = config.serverUrl || DEFAULT_URLS.TTS;
|
|
@@ -240,12 +244,14 @@ var TTSClient = class {
|
|
|
240
244
|
synthesize(options) {
|
|
241
245
|
return new Promise((resolve, reject) => {
|
|
242
246
|
try {
|
|
243
|
-
|
|
247
|
+
let url = this.serverUrl;
|
|
244
248
|
if (this.apiKey) {
|
|
245
|
-
|
|
249
|
+
const separator = url.includes("?") ? "&" : "?";
|
|
250
|
+
url += `${separator}api_key=${this.apiKey}`;
|
|
246
251
|
}
|
|
247
|
-
const ws = new
|
|
248
|
-
ws.
|
|
252
|
+
const ws = new WebSocket(url);
|
|
253
|
+
ws.binaryType = "arraybuffer";
|
|
254
|
+
ws.onopen = () => {
|
|
249
255
|
const req = {
|
|
250
256
|
text: options.text,
|
|
251
257
|
voice: options.voice || "F1" /* F1 */,
|
|
@@ -255,27 +261,27 @@ var TTSClient = class {
|
|
|
255
261
|
visemes: options.visemes || false
|
|
256
262
|
};
|
|
257
263
|
ws.send(JSON.stringify(req));
|
|
258
|
-
}
|
|
259
|
-
ws.
|
|
260
|
-
if (
|
|
261
|
-
if (options.onAudio) options.onAudio(data);
|
|
264
|
+
};
|
|
265
|
+
ws.onmessage = async (event) => {
|
|
266
|
+
if (event.data instanceof ArrayBuffer) {
|
|
267
|
+
if (options.onAudio) options.onAudio(new Uint8Array(event.data));
|
|
262
268
|
} else {
|
|
263
269
|
try {
|
|
264
|
-
const msg = JSON.parse(data.toString());
|
|
270
|
+
const msg = JSON.parse(event.data.toString());
|
|
265
271
|
if (Array.isArray(msg) && options.onVisemes) {
|
|
266
272
|
options.onVisemes(msg);
|
|
267
273
|
}
|
|
268
274
|
} catch (e) {
|
|
269
275
|
}
|
|
270
276
|
}
|
|
271
|
-
}
|
|
272
|
-
ws.
|
|
277
|
+
};
|
|
278
|
+
ws.onerror = (err) => {
|
|
273
279
|
if (options.onError) options.onError(err);
|
|
274
280
|
reject(err);
|
|
275
|
-
}
|
|
276
|
-
ws.
|
|
281
|
+
};
|
|
282
|
+
ws.onclose = () => {
|
|
277
283
|
resolve();
|
|
278
|
-
}
|
|
284
|
+
};
|
|
279
285
|
} catch (err) {
|
|
280
286
|
if (options.onError) options.onError(err);
|
|
281
287
|
reject(err);
|
package/dist/index.mjs
CHANGED
|
@@ -34,7 +34,14 @@ var DEFAULT_URLS = {
|
|
|
34
34
|
};
|
|
35
35
|
|
|
36
36
|
// src/client.ts
|
|
37
|
-
|
|
37
|
+
function base64ToUint8Array(base64) {
|
|
38
|
+
const binaryString = atob(base64);
|
|
39
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
40
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
41
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
42
|
+
}
|
|
43
|
+
return bytes;
|
|
44
|
+
}
|
|
38
45
|
var VoiceAgentClient = class {
|
|
39
46
|
ws = null;
|
|
40
47
|
apiKey;
|
|
@@ -67,36 +74,36 @@ var VoiceAgentClient = class {
|
|
|
67
74
|
async connect() {
|
|
68
75
|
return new Promise((resolve, reject) => {
|
|
69
76
|
try {
|
|
70
|
-
|
|
71
|
-
const headers = {};
|
|
77
|
+
let url = this.serverUrl;
|
|
72
78
|
if (this.apiKey) {
|
|
73
|
-
|
|
79
|
+
const separator = url.includes("?") ? "&" : "?";
|
|
80
|
+
url += `${separator}api_key=${this.apiKey}`;
|
|
74
81
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
this.ws.
|
|
82
|
+
console.log(`\u{1F517} Connecting to ${this.serverUrl}...`);
|
|
83
|
+
this.ws = new WebSocket(url);
|
|
84
|
+
this.ws.binaryType = "arraybuffer";
|
|
85
|
+
this.ws.onopen = () => {
|
|
79
86
|
this.isConnected = true;
|
|
80
87
|
console.log("\u2705 Connected to voice agent!");
|
|
81
88
|
this.sendConfig();
|
|
82
89
|
resolve(true);
|
|
83
|
-
}
|
|
84
|
-
this.ws.
|
|
85
|
-
if (
|
|
86
|
-
this.handleBinaryMessage(data);
|
|
90
|
+
};
|
|
91
|
+
this.ws.onmessage = async (event) => {
|
|
92
|
+
if (event.data instanceof ArrayBuffer) {
|
|
93
|
+
this.handleBinaryMessage(new Uint8Array(event.data));
|
|
87
94
|
} else {
|
|
88
|
-
this.handleTextMessage(data.toString());
|
|
95
|
+
this.handleTextMessage(event.data.toString());
|
|
89
96
|
}
|
|
90
|
-
}
|
|
91
|
-
this.ws.
|
|
97
|
+
};
|
|
98
|
+
this.ws.onerror = (err) => {
|
|
92
99
|
console.error("\u274C WebSocket error:", err);
|
|
93
100
|
if (this.onError) this.onError(err);
|
|
94
101
|
if (!this.isConnected) reject(err);
|
|
95
|
-
}
|
|
96
|
-
this.ws.
|
|
102
|
+
};
|
|
103
|
+
this.ws.onclose = () => {
|
|
97
104
|
this.isConnected = false;
|
|
98
105
|
console.log("Disconnected");
|
|
99
|
-
}
|
|
106
|
+
};
|
|
100
107
|
} catch (err) {
|
|
101
108
|
if (this.onError) this.onError(err);
|
|
102
109
|
reject(err);
|
|
@@ -119,7 +126,7 @@ var VoiceAgentClient = class {
|
|
|
119
126
|
*/
|
|
120
127
|
sendAudio(audioData) {
|
|
121
128
|
if (this.ws && this.isConnected) {
|
|
122
|
-
this.ws.send(audioData
|
|
129
|
+
this.ws.send(audioData);
|
|
123
130
|
}
|
|
124
131
|
}
|
|
125
132
|
/**
|
|
@@ -137,7 +144,7 @@ var VoiceAgentClient = class {
|
|
|
137
144
|
switch (msg.type) {
|
|
138
145
|
case "audio":
|
|
139
146
|
if (msg.data) {
|
|
140
|
-
const buffer =
|
|
147
|
+
const buffer = base64ToUint8Array(msg.data);
|
|
141
148
|
this.handleBinaryMessage(buffer);
|
|
142
149
|
}
|
|
143
150
|
break;
|
|
@@ -191,9 +198,6 @@ var VoiceAgentClient = class {
|
|
|
191
198
|
var TTSClient = class {
|
|
192
199
|
apiKey;
|
|
193
200
|
serverUrl;
|
|
194
|
-
onAudioCallback;
|
|
195
|
-
onVisemesCallback;
|
|
196
|
-
onErrorCallback;
|
|
197
201
|
constructor(config) {
|
|
198
202
|
this.apiKey = config.apiKey;
|
|
199
203
|
this.serverUrl = config.serverUrl || DEFAULT_URLS.TTS;
|
|
@@ -207,12 +211,14 @@ var TTSClient = class {
|
|
|
207
211
|
synthesize(options) {
|
|
208
212
|
return new Promise((resolve, reject) => {
|
|
209
213
|
try {
|
|
210
|
-
|
|
214
|
+
let url = this.serverUrl;
|
|
211
215
|
if (this.apiKey) {
|
|
212
|
-
|
|
216
|
+
const separator = url.includes("?") ? "&" : "?";
|
|
217
|
+
url += `${separator}api_key=${this.apiKey}`;
|
|
213
218
|
}
|
|
214
|
-
const ws = new WebSocket(
|
|
215
|
-
ws.
|
|
219
|
+
const ws = new WebSocket(url);
|
|
220
|
+
ws.binaryType = "arraybuffer";
|
|
221
|
+
ws.onopen = () => {
|
|
216
222
|
const req = {
|
|
217
223
|
text: options.text,
|
|
218
224
|
voice: options.voice || "F1" /* F1 */,
|
|
@@ -222,27 +228,27 @@ var TTSClient = class {
|
|
|
222
228
|
visemes: options.visemes || false
|
|
223
229
|
};
|
|
224
230
|
ws.send(JSON.stringify(req));
|
|
225
|
-
}
|
|
226
|
-
ws.
|
|
227
|
-
if (
|
|
228
|
-
if (options.onAudio) options.onAudio(data);
|
|
231
|
+
};
|
|
232
|
+
ws.onmessage = async (event) => {
|
|
233
|
+
if (event.data instanceof ArrayBuffer) {
|
|
234
|
+
if (options.onAudio) options.onAudio(new Uint8Array(event.data));
|
|
229
235
|
} else {
|
|
230
236
|
try {
|
|
231
|
-
const msg = JSON.parse(data.toString());
|
|
237
|
+
const msg = JSON.parse(event.data.toString());
|
|
232
238
|
if (Array.isArray(msg) && options.onVisemes) {
|
|
233
239
|
options.onVisemes(msg);
|
|
234
240
|
}
|
|
235
241
|
} catch (e) {
|
|
236
242
|
}
|
|
237
243
|
}
|
|
238
|
-
}
|
|
239
|
-
ws.
|
|
244
|
+
};
|
|
245
|
+
ws.onerror = (err) => {
|
|
240
246
|
if (options.onError) options.onError(err);
|
|
241
247
|
reject(err);
|
|
242
|
-
}
|
|
243
|
-
ws.
|
|
248
|
+
};
|
|
249
|
+
ws.onclose = () => {
|
|
244
250
|
resolve();
|
|
245
|
-
}
|
|
251
|
+
};
|
|
246
252
|
} catch (err) {
|
|
247
253
|
if (options.onError) options.onError(err);
|
|
248
254
|
reject(err);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lokutor/sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "JavaScript/TypeScript SDK for Lokutor Real-time Voice AI",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -27,14 +27,11 @@
|
|
|
27
27
|
],
|
|
28
28
|
"author": "Lokutor AI",
|
|
29
29
|
"license": "MIT",
|
|
30
|
-
"dependencies": {
|
|
31
|
-
"ws": "^8.16.0"
|
|
32
|
-
},
|
|
30
|
+
"dependencies": {},
|
|
33
31
|
"devDependencies": {
|
|
34
32
|
"@types/node": "^20.10.0",
|
|
35
|
-
"@types/ws": "^8.5.10",
|
|
36
33
|
"tsup": "^8.0.1",
|
|
37
34
|
"typescript": "^5.3.2",
|
|
38
35
|
"vitest": "^1.0.1"
|
|
39
36
|
}
|
|
40
|
-
}
|
|
37
|
+
}
|