phonic 0.14.0 → 0.16.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/README.md +7 -8
- package/dist/index.d.mts +15 -8
- package/dist/index.d.ts +15 -8
- package/dist/index.js +71 -106
- package/dist/index.mjs +71 -106
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -65,7 +65,10 @@ if (error === null) {
|
|
|
65
65
|
### Get conversation by external id
|
|
66
66
|
|
|
67
67
|
```ts
|
|
68
|
-
const { data, error } = await phonic.conversations.getByExternalId(
|
|
68
|
+
const { data, error } = await phonic.conversations.getByExternalId({
|
|
69
|
+
project: "main",
|
|
70
|
+
externalId: "CAdb9c032c809fec7feb932ea4c96d71e1"
|
|
71
|
+
});
|
|
69
72
|
|
|
70
73
|
if (error === null) {
|
|
71
74
|
console.log(data.conversation);
|
|
@@ -76,6 +79,7 @@ if (error === null) {
|
|
|
76
79
|
|
|
77
80
|
```ts
|
|
78
81
|
const { data, error } = await phonic.conversations.list({
|
|
82
|
+
project: "main",
|
|
79
83
|
durationMin: 10, // sec
|
|
80
84
|
durationMax: 20, // sec
|
|
81
85
|
startedAtMin: "2025-04-17", // 00:00:00 UTC time is assumed
|
|
@@ -92,21 +96,16 @@ if (error === null) {
|
|
|
92
96
|
To start a conversation, open a WebSocket connection:
|
|
93
97
|
|
|
94
98
|
```ts
|
|
95
|
-
const
|
|
99
|
+
const phonicWebSocket = phonic.sts.websocket({
|
|
96
100
|
input_format: "mulaw_8000",
|
|
97
101
|
|
|
98
102
|
// Optional fields
|
|
103
|
+
project: "main",
|
|
99
104
|
system_prompt: "You are a helpful assistant.",
|
|
100
105
|
welcome_message: "Hello, how can I help you?",
|
|
101
106
|
voice_id: "meredith",
|
|
102
107
|
output_format: "mulaw_8000"
|
|
103
108
|
});
|
|
104
|
-
|
|
105
|
-
if (error !== null) {
|
|
106
|
-
throw new Error(`Failed to start conversation: ${error.message}`);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
const { phonicWebSocket } = data;
|
|
110
109
|
```
|
|
111
110
|
|
|
112
111
|
Stream input (user) audio chunks:
|
package/dist/index.d.mts
CHANGED
|
@@ -63,8 +63,12 @@ declare class Conversations {
|
|
|
63
63
|
private readonly phonic;
|
|
64
64
|
constructor(phonic: Phonic);
|
|
65
65
|
get(id: string): DataOrError<ConversationSuccessResponse>;
|
|
66
|
-
getByExternalId(externalId
|
|
67
|
-
|
|
66
|
+
getByExternalId({ project, externalId, }: {
|
|
67
|
+
project?: string;
|
|
68
|
+
externalId: string;
|
|
69
|
+
}): DataOrError<ConversationSuccessResponse>;
|
|
70
|
+
list({ project, durationMin, durationMax, startedAtMin, startedAtMax, }: {
|
|
71
|
+
project?: string;
|
|
68
72
|
durationMin?: number;
|
|
69
73
|
durationMax?: number;
|
|
70
74
|
startedAtMin?: ISODate | ISODateTime$1;
|
|
@@ -73,7 +77,7 @@ declare class Conversations {
|
|
|
73
77
|
}
|
|
74
78
|
|
|
75
79
|
type PhonicSTSConfig = {
|
|
76
|
-
|
|
80
|
+
project: string;
|
|
77
81
|
input_format: "pcm_44100" | "mulaw_8000";
|
|
78
82
|
system_prompt?: string;
|
|
79
83
|
welcome_message?: string;
|
|
@@ -92,6 +96,9 @@ type PhonicSTSWebSocketResponseMessage = {
|
|
|
92
96
|
} | {
|
|
93
97
|
type: "is_user_speaking";
|
|
94
98
|
isUserSpeaking: boolean;
|
|
99
|
+
} | {
|
|
100
|
+
type: "interrupted_response";
|
|
101
|
+
interruptedResponse: string;
|
|
95
102
|
} | {
|
|
96
103
|
type: "error";
|
|
97
104
|
error: {
|
|
@@ -112,10 +119,13 @@ type OnErrorCallback = (event: WebSocket.ErrorEvent) => void;
|
|
|
112
119
|
|
|
113
120
|
declare class PhonicSTSWebSocket {
|
|
114
121
|
private readonly ws;
|
|
122
|
+
private readonly config;
|
|
115
123
|
private onMessageCallback;
|
|
116
124
|
private onCloseCallback;
|
|
117
125
|
private onErrorCallback;
|
|
118
|
-
|
|
126
|
+
private buffer;
|
|
127
|
+
private isOpen;
|
|
128
|
+
constructor(ws: WebSocket, config: PhonicSTSConfig);
|
|
119
129
|
onMessage(callback: OnMessageCallback): void;
|
|
120
130
|
onClose(callback: OnCloseCallback): void;
|
|
121
131
|
onError(callback: OnErrorCallback): void;
|
|
@@ -134,10 +144,7 @@ declare class PhonicSTSWebSocket {
|
|
|
134
144
|
declare class SpeechToSpeech {
|
|
135
145
|
private readonly phonic;
|
|
136
146
|
constructor(phonic: Phonic);
|
|
137
|
-
|
|
138
|
-
websocket(config: PhonicSTSConfig): DataOrError<{
|
|
139
|
-
phonicWebSocket: PhonicSTSWebSocket;
|
|
140
|
-
}>;
|
|
147
|
+
websocket(config: PhonicSTSConfig): PhonicSTSWebSocket;
|
|
141
148
|
}
|
|
142
149
|
|
|
143
150
|
type Voice = {
|
package/dist/index.d.ts
CHANGED
|
@@ -63,8 +63,12 @@ declare class Conversations {
|
|
|
63
63
|
private readonly phonic;
|
|
64
64
|
constructor(phonic: Phonic);
|
|
65
65
|
get(id: string): DataOrError<ConversationSuccessResponse>;
|
|
66
|
-
getByExternalId(externalId
|
|
67
|
-
|
|
66
|
+
getByExternalId({ project, externalId, }: {
|
|
67
|
+
project?: string;
|
|
68
|
+
externalId: string;
|
|
69
|
+
}): DataOrError<ConversationSuccessResponse>;
|
|
70
|
+
list({ project, durationMin, durationMax, startedAtMin, startedAtMax, }: {
|
|
71
|
+
project?: string;
|
|
68
72
|
durationMin?: number;
|
|
69
73
|
durationMax?: number;
|
|
70
74
|
startedAtMin?: ISODate | ISODateTime$1;
|
|
@@ -73,7 +77,7 @@ declare class Conversations {
|
|
|
73
77
|
}
|
|
74
78
|
|
|
75
79
|
type PhonicSTSConfig = {
|
|
76
|
-
|
|
80
|
+
project: string;
|
|
77
81
|
input_format: "pcm_44100" | "mulaw_8000";
|
|
78
82
|
system_prompt?: string;
|
|
79
83
|
welcome_message?: string;
|
|
@@ -92,6 +96,9 @@ type PhonicSTSWebSocketResponseMessage = {
|
|
|
92
96
|
} | {
|
|
93
97
|
type: "is_user_speaking";
|
|
94
98
|
isUserSpeaking: boolean;
|
|
99
|
+
} | {
|
|
100
|
+
type: "interrupted_response";
|
|
101
|
+
interruptedResponse: string;
|
|
95
102
|
} | {
|
|
96
103
|
type: "error";
|
|
97
104
|
error: {
|
|
@@ -112,10 +119,13 @@ type OnErrorCallback = (event: WebSocket.ErrorEvent) => void;
|
|
|
112
119
|
|
|
113
120
|
declare class PhonicSTSWebSocket {
|
|
114
121
|
private readonly ws;
|
|
122
|
+
private readonly config;
|
|
115
123
|
private onMessageCallback;
|
|
116
124
|
private onCloseCallback;
|
|
117
125
|
private onErrorCallback;
|
|
118
|
-
|
|
126
|
+
private buffer;
|
|
127
|
+
private isOpen;
|
|
128
|
+
constructor(ws: WebSocket, config: PhonicSTSConfig);
|
|
119
129
|
onMessage(callback: OnMessageCallback): void;
|
|
120
130
|
onClose(callback: OnCloseCallback): void;
|
|
121
131
|
onError(callback: OnErrorCallback): void;
|
|
@@ -134,10 +144,7 @@ declare class PhonicSTSWebSocket {
|
|
|
134
144
|
declare class SpeechToSpeech {
|
|
135
145
|
private readonly phonic;
|
|
136
146
|
constructor(phonic: Phonic);
|
|
137
|
-
|
|
138
|
-
websocket(config: PhonicSTSConfig): DataOrError<{
|
|
139
|
-
phonicWebSocket: PhonicSTSWebSocket;
|
|
140
|
-
}>;
|
|
147
|
+
websocket(config: PhonicSTSConfig): PhonicSTSWebSocket;
|
|
141
148
|
}
|
|
142
149
|
|
|
143
150
|
type Voice = {
|
package/dist/index.js
CHANGED
|
@@ -35,7 +35,7 @@ __export(index_exports, {
|
|
|
35
35
|
module.exports = __toCommonJS(index_exports);
|
|
36
36
|
|
|
37
37
|
// package.json
|
|
38
|
-
var version = "0.
|
|
38
|
+
var version = "0.16.0";
|
|
39
39
|
|
|
40
40
|
// src/conversations/index.ts
|
|
41
41
|
var Conversations = class {
|
|
@@ -48,8 +48,12 @@ var Conversations = class {
|
|
|
48
48
|
);
|
|
49
49
|
return response;
|
|
50
50
|
}
|
|
51
|
-
async getByExternalId(
|
|
51
|
+
async getByExternalId({
|
|
52
|
+
project,
|
|
53
|
+
externalId
|
|
54
|
+
}) {
|
|
52
55
|
const queryString = new URLSearchParams({
|
|
56
|
+
...project !== void 0 && { project },
|
|
53
57
|
external_id: externalId
|
|
54
58
|
}).toString();
|
|
55
59
|
const response = await this.phonic.get(
|
|
@@ -58,12 +62,14 @@ var Conversations = class {
|
|
|
58
62
|
return response;
|
|
59
63
|
}
|
|
60
64
|
async list({
|
|
65
|
+
project,
|
|
61
66
|
durationMin,
|
|
62
67
|
durationMax,
|
|
63
68
|
startedAtMin,
|
|
64
69
|
startedAtMax
|
|
65
70
|
}) {
|
|
66
71
|
const queryString = new URLSearchParams({
|
|
72
|
+
...project !== void 0 && { project },
|
|
67
73
|
...durationMin !== void 0 && { duration_min: String(durationMin) },
|
|
68
74
|
...durationMax !== void 0 && { duration_max: String(durationMax) },
|
|
69
75
|
...startedAtMin !== void 0 && { started_at_min: startedAtMin },
|
|
@@ -81,8 +87,21 @@ var import_ws = __toESM(require("ws"));
|
|
|
81
87
|
|
|
82
88
|
// src/sts/websocket.ts
|
|
83
89
|
var PhonicSTSWebSocket = class {
|
|
84
|
-
constructor(ws) {
|
|
90
|
+
constructor(ws, config) {
|
|
85
91
|
this.ws = ws;
|
|
92
|
+
this.config = config;
|
|
93
|
+
this.buffer.push(
|
|
94
|
+
JSON.stringify({
|
|
95
|
+
type: "config",
|
|
96
|
+
...this.config
|
|
97
|
+
})
|
|
98
|
+
);
|
|
99
|
+
this.ws.onopen = () => {
|
|
100
|
+
for (const message of this.buffer) {
|
|
101
|
+
this.ws.send(message);
|
|
102
|
+
}
|
|
103
|
+
this.isOpen = true;
|
|
104
|
+
};
|
|
86
105
|
this.ws.onmessage = (event) => {
|
|
87
106
|
if (this.onMessageCallback === null) {
|
|
88
107
|
return;
|
|
@@ -116,6 +135,8 @@ var PhonicSTSWebSocket = class {
|
|
|
116
135
|
onMessageCallback = null;
|
|
117
136
|
onCloseCallback = null;
|
|
118
137
|
onErrorCallback = null;
|
|
138
|
+
buffer = [];
|
|
139
|
+
isOpen = false;
|
|
119
140
|
onMessage(callback) {
|
|
120
141
|
this.onMessageCallback = callback;
|
|
121
142
|
}
|
|
@@ -126,28 +147,37 @@ var PhonicSTSWebSocket = class {
|
|
|
126
147
|
this.onErrorCallback = callback;
|
|
127
148
|
}
|
|
128
149
|
audioChunk({ audio }) {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
150
|
+
const audiochunkMessage = JSON.stringify({
|
|
151
|
+
type: "audio_chunk",
|
|
152
|
+
audio
|
|
153
|
+
});
|
|
154
|
+
if (this.isOpen) {
|
|
155
|
+
this.ws.send(audiochunkMessage);
|
|
156
|
+
} else {
|
|
157
|
+
this.buffer.push(audiochunkMessage);
|
|
158
|
+
}
|
|
135
159
|
}
|
|
136
160
|
updateSystemPrompt({ systemPrompt }) {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
161
|
+
const updateSystemPromptMessage = JSON.stringify({
|
|
162
|
+
type: "update_system_prompt",
|
|
163
|
+
system_prompt: systemPrompt
|
|
164
|
+
});
|
|
165
|
+
if (this.isOpen) {
|
|
166
|
+
this.ws.send(updateSystemPromptMessage);
|
|
167
|
+
} else {
|
|
168
|
+
this.buffer.push(updateSystemPromptMessage);
|
|
169
|
+
}
|
|
143
170
|
}
|
|
144
171
|
setExternalId({ externalId }) {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
172
|
+
const setExternalIdMessage = JSON.stringify({
|
|
173
|
+
type: "set_external_id",
|
|
174
|
+
external_id: externalId
|
|
175
|
+
});
|
|
176
|
+
if (this.isOpen) {
|
|
177
|
+
this.ws.send(setExternalIdMessage);
|
|
178
|
+
} else {
|
|
179
|
+
this.buffer.push(setExternalIdMessage);
|
|
180
|
+
}
|
|
151
181
|
}
|
|
152
182
|
close(code) {
|
|
153
183
|
this.ws.close(code ?? 1e3);
|
|
@@ -155,64 +185,11 @@ var PhonicSTSWebSocket = class {
|
|
|
155
185
|
};
|
|
156
186
|
|
|
157
187
|
// src/sts/index.ts
|
|
158
|
-
var phonicApiCloseCodes = {
|
|
159
|
-
insuffucientCapacityAvailable: 4004
|
|
160
|
-
};
|
|
161
188
|
var SpeechToSpeech = class {
|
|
162
189
|
constructor(phonic) {
|
|
163
190
|
this.phonic = phonic;
|
|
164
191
|
}
|
|
165
|
-
|
|
166
|
-
return new Promise((resolve) => {
|
|
167
|
-
const ws = new import_ws.default(phonicApiWsUrl, {
|
|
168
|
-
headers: this.phonic.headers
|
|
169
|
-
});
|
|
170
|
-
ws.onopen = () => {
|
|
171
|
-
ws.send(
|
|
172
|
-
JSON.stringify({
|
|
173
|
-
type: "config",
|
|
174
|
-
...config
|
|
175
|
-
})
|
|
176
|
-
);
|
|
177
|
-
};
|
|
178
|
-
ws.onmessage = (event) => {
|
|
179
|
-
if (typeof event.data !== "string") {
|
|
180
|
-
throw new Error("Received non-string message");
|
|
181
|
-
}
|
|
182
|
-
const dataObj = JSON.parse(
|
|
183
|
-
event.data
|
|
184
|
-
);
|
|
185
|
-
if (dataObj.type === "ready_to_start_conversation") {
|
|
186
|
-
resolve({
|
|
187
|
-
data: {
|
|
188
|
-
phonicWebSocket: new PhonicSTSWebSocket(ws)
|
|
189
|
-
},
|
|
190
|
-
error: null
|
|
191
|
-
});
|
|
192
|
-
}
|
|
193
|
-
};
|
|
194
|
-
ws.onerror = (error) => {
|
|
195
|
-
resolve({
|
|
196
|
-
data: null,
|
|
197
|
-
error: {
|
|
198
|
-
message: error.message
|
|
199
|
-
}
|
|
200
|
-
});
|
|
201
|
-
};
|
|
202
|
-
ws.onclose = (event) => {
|
|
203
|
-
if (event.code === phonicApiCloseCodes.insuffucientCapacityAvailable) {
|
|
204
|
-
resolve({
|
|
205
|
-
data: null,
|
|
206
|
-
error: {
|
|
207
|
-
message: event.reason,
|
|
208
|
-
code: "insuffucient_capacity_available"
|
|
209
|
-
}
|
|
210
|
-
});
|
|
211
|
-
}
|
|
212
|
-
};
|
|
213
|
-
});
|
|
214
|
-
}
|
|
215
|
-
async websocket(config) {
|
|
192
|
+
websocket(config) {
|
|
216
193
|
const wsBaseUrl = this.phonic.baseUrl.replace(/^http/, "ws");
|
|
217
194
|
const queryString = new URLSearchParams({
|
|
218
195
|
...this.phonic.__downstreamWebSocketUrl !== null && {
|
|
@@ -220,31 +197,10 @@ var SpeechToSpeech = class {
|
|
|
220
197
|
}
|
|
221
198
|
}).toString();
|
|
222
199
|
const phonicApiWsUrl = `${wsBaseUrl}/v1/sts/ws?${queryString}`;
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
const connectResult = await this.connectToPhonicAPI(
|
|
228
|
-
phonicApiWsUrl,
|
|
229
|
-
config
|
|
230
|
-
);
|
|
231
|
-
if (connectResult.data !== null) {
|
|
232
|
-
return connectResult;
|
|
233
|
-
}
|
|
234
|
-
if (connectResult.error.code === "insuffucient_capacity_available") {
|
|
235
|
-
if (retryNumber >= maxRetries) {
|
|
236
|
-
return connectResult;
|
|
237
|
-
}
|
|
238
|
-
console.info(
|
|
239
|
-
`${connectResult.error.message}, will retry in ${retryDelay / 1e3}sec`
|
|
240
|
-
);
|
|
241
|
-
await new Promise((resolve) => setTimeout(resolve, retryDelay));
|
|
242
|
-
retryNumber += 1;
|
|
243
|
-
console.info(`Retrying... ${retryNumber}/${maxRetries}`);
|
|
244
|
-
continue;
|
|
245
|
-
}
|
|
246
|
-
return connectResult;
|
|
247
|
-
}
|
|
200
|
+
const ws = new import_ws.default(phonicApiWsUrl, {
|
|
201
|
+
headers: this.phonic.headers
|
|
202
|
+
});
|
|
203
|
+
return new PhonicSTSWebSocket(ws, config);
|
|
248
204
|
}
|
|
249
205
|
};
|
|
250
206
|
|
|
@@ -304,18 +260,27 @@ var Phonic = class {
|
|
|
304
260
|
headers: this.headers,
|
|
305
261
|
...options
|
|
306
262
|
});
|
|
307
|
-
if (
|
|
308
|
-
const
|
|
309
|
-
|
|
263
|
+
if (response.ok) {
|
|
264
|
+
const data = await response.json();
|
|
265
|
+
return { data, error: null };
|
|
266
|
+
}
|
|
267
|
+
try {
|
|
268
|
+
const data = await response.json();
|
|
269
|
+
const errorMessage = data.error.message || response.statusText;
|
|
270
|
+
return {
|
|
271
|
+
data: null,
|
|
272
|
+
error: {
|
|
273
|
+
message: errorMessage
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
} catch (error) {
|
|
310
277
|
return {
|
|
311
278
|
data: null,
|
|
312
279
|
error: {
|
|
313
|
-
message: statusText
|
|
280
|
+
message: response.statusText
|
|
314
281
|
}
|
|
315
282
|
};
|
|
316
283
|
}
|
|
317
|
-
const data = await response.json();
|
|
318
|
-
return { data, error: null };
|
|
319
284
|
} catch (error) {
|
|
320
285
|
console.error(error);
|
|
321
286
|
return {
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// package.json
|
|
2
|
-
var version = "0.
|
|
2
|
+
var version = "0.16.0";
|
|
3
3
|
|
|
4
4
|
// src/conversations/index.ts
|
|
5
5
|
var Conversations = class {
|
|
@@ -12,8 +12,12 @@ var Conversations = class {
|
|
|
12
12
|
);
|
|
13
13
|
return response;
|
|
14
14
|
}
|
|
15
|
-
async getByExternalId(
|
|
15
|
+
async getByExternalId({
|
|
16
|
+
project,
|
|
17
|
+
externalId
|
|
18
|
+
}) {
|
|
16
19
|
const queryString = new URLSearchParams({
|
|
20
|
+
...project !== void 0 && { project },
|
|
17
21
|
external_id: externalId
|
|
18
22
|
}).toString();
|
|
19
23
|
const response = await this.phonic.get(
|
|
@@ -22,12 +26,14 @@ var Conversations = class {
|
|
|
22
26
|
return response;
|
|
23
27
|
}
|
|
24
28
|
async list({
|
|
29
|
+
project,
|
|
25
30
|
durationMin,
|
|
26
31
|
durationMax,
|
|
27
32
|
startedAtMin,
|
|
28
33
|
startedAtMax
|
|
29
34
|
}) {
|
|
30
35
|
const queryString = new URLSearchParams({
|
|
36
|
+
...project !== void 0 && { project },
|
|
31
37
|
...durationMin !== void 0 && { duration_min: String(durationMin) },
|
|
32
38
|
...durationMax !== void 0 && { duration_max: String(durationMax) },
|
|
33
39
|
...startedAtMin !== void 0 && { started_at_min: startedAtMin },
|
|
@@ -45,8 +51,21 @@ import WebSocket from "ws";
|
|
|
45
51
|
|
|
46
52
|
// src/sts/websocket.ts
|
|
47
53
|
var PhonicSTSWebSocket = class {
|
|
48
|
-
constructor(ws) {
|
|
54
|
+
constructor(ws, config) {
|
|
49
55
|
this.ws = ws;
|
|
56
|
+
this.config = config;
|
|
57
|
+
this.buffer.push(
|
|
58
|
+
JSON.stringify({
|
|
59
|
+
type: "config",
|
|
60
|
+
...this.config
|
|
61
|
+
})
|
|
62
|
+
);
|
|
63
|
+
this.ws.onopen = () => {
|
|
64
|
+
for (const message of this.buffer) {
|
|
65
|
+
this.ws.send(message);
|
|
66
|
+
}
|
|
67
|
+
this.isOpen = true;
|
|
68
|
+
};
|
|
50
69
|
this.ws.onmessage = (event) => {
|
|
51
70
|
if (this.onMessageCallback === null) {
|
|
52
71
|
return;
|
|
@@ -80,6 +99,8 @@ var PhonicSTSWebSocket = class {
|
|
|
80
99
|
onMessageCallback = null;
|
|
81
100
|
onCloseCallback = null;
|
|
82
101
|
onErrorCallback = null;
|
|
102
|
+
buffer = [];
|
|
103
|
+
isOpen = false;
|
|
83
104
|
onMessage(callback) {
|
|
84
105
|
this.onMessageCallback = callback;
|
|
85
106
|
}
|
|
@@ -90,28 +111,37 @@ var PhonicSTSWebSocket = class {
|
|
|
90
111
|
this.onErrorCallback = callback;
|
|
91
112
|
}
|
|
92
113
|
audioChunk({ audio }) {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
114
|
+
const audiochunkMessage = JSON.stringify({
|
|
115
|
+
type: "audio_chunk",
|
|
116
|
+
audio
|
|
117
|
+
});
|
|
118
|
+
if (this.isOpen) {
|
|
119
|
+
this.ws.send(audiochunkMessage);
|
|
120
|
+
} else {
|
|
121
|
+
this.buffer.push(audiochunkMessage);
|
|
122
|
+
}
|
|
99
123
|
}
|
|
100
124
|
updateSystemPrompt({ systemPrompt }) {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
125
|
+
const updateSystemPromptMessage = JSON.stringify({
|
|
126
|
+
type: "update_system_prompt",
|
|
127
|
+
system_prompt: systemPrompt
|
|
128
|
+
});
|
|
129
|
+
if (this.isOpen) {
|
|
130
|
+
this.ws.send(updateSystemPromptMessage);
|
|
131
|
+
} else {
|
|
132
|
+
this.buffer.push(updateSystemPromptMessage);
|
|
133
|
+
}
|
|
107
134
|
}
|
|
108
135
|
setExternalId({ externalId }) {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
136
|
+
const setExternalIdMessage = JSON.stringify({
|
|
137
|
+
type: "set_external_id",
|
|
138
|
+
external_id: externalId
|
|
139
|
+
});
|
|
140
|
+
if (this.isOpen) {
|
|
141
|
+
this.ws.send(setExternalIdMessage);
|
|
142
|
+
} else {
|
|
143
|
+
this.buffer.push(setExternalIdMessage);
|
|
144
|
+
}
|
|
115
145
|
}
|
|
116
146
|
close(code) {
|
|
117
147
|
this.ws.close(code ?? 1e3);
|
|
@@ -119,64 +149,11 @@ var PhonicSTSWebSocket = class {
|
|
|
119
149
|
};
|
|
120
150
|
|
|
121
151
|
// src/sts/index.ts
|
|
122
|
-
var phonicApiCloseCodes = {
|
|
123
|
-
insuffucientCapacityAvailable: 4004
|
|
124
|
-
};
|
|
125
152
|
var SpeechToSpeech = class {
|
|
126
153
|
constructor(phonic) {
|
|
127
154
|
this.phonic = phonic;
|
|
128
155
|
}
|
|
129
|
-
|
|
130
|
-
return new Promise((resolve) => {
|
|
131
|
-
const ws = new WebSocket(phonicApiWsUrl, {
|
|
132
|
-
headers: this.phonic.headers
|
|
133
|
-
});
|
|
134
|
-
ws.onopen = () => {
|
|
135
|
-
ws.send(
|
|
136
|
-
JSON.stringify({
|
|
137
|
-
type: "config",
|
|
138
|
-
...config
|
|
139
|
-
})
|
|
140
|
-
);
|
|
141
|
-
};
|
|
142
|
-
ws.onmessage = (event) => {
|
|
143
|
-
if (typeof event.data !== "string") {
|
|
144
|
-
throw new Error("Received non-string message");
|
|
145
|
-
}
|
|
146
|
-
const dataObj = JSON.parse(
|
|
147
|
-
event.data
|
|
148
|
-
);
|
|
149
|
-
if (dataObj.type === "ready_to_start_conversation") {
|
|
150
|
-
resolve({
|
|
151
|
-
data: {
|
|
152
|
-
phonicWebSocket: new PhonicSTSWebSocket(ws)
|
|
153
|
-
},
|
|
154
|
-
error: null
|
|
155
|
-
});
|
|
156
|
-
}
|
|
157
|
-
};
|
|
158
|
-
ws.onerror = (error) => {
|
|
159
|
-
resolve({
|
|
160
|
-
data: null,
|
|
161
|
-
error: {
|
|
162
|
-
message: error.message
|
|
163
|
-
}
|
|
164
|
-
});
|
|
165
|
-
};
|
|
166
|
-
ws.onclose = (event) => {
|
|
167
|
-
if (event.code === phonicApiCloseCodes.insuffucientCapacityAvailable) {
|
|
168
|
-
resolve({
|
|
169
|
-
data: null,
|
|
170
|
-
error: {
|
|
171
|
-
message: event.reason,
|
|
172
|
-
code: "insuffucient_capacity_available"
|
|
173
|
-
}
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
};
|
|
177
|
-
});
|
|
178
|
-
}
|
|
179
|
-
async websocket(config) {
|
|
156
|
+
websocket(config) {
|
|
180
157
|
const wsBaseUrl = this.phonic.baseUrl.replace(/^http/, "ws");
|
|
181
158
|
const queryString = new URLSearchParams({
|
|
182
159
|
...this.phonic.__downstreamWebSocketUrl !== null && {
|
|
@@ -184,31 +161,10 @@ var SpeechToSpeech = class {
|
|
|
184
161
|
}
|
|
185
162
|
}).toString();
|
|
186
163
|
const phonicApiWsUrl = `${wsBaseUrl}/v1/sts/ws?${queryString}`;
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
const connectResult = await this.connectToPhonicAPI(
|
|
192
|
-
phonicApiWsUrl,
|
|
193
|
-
config
|
|
194
|
-
);
|
|
195
|
-
if (connectResult.data !== null) {
|
|
196
|
-
return connectResult;
|
|
197
|
-
}
|
|
198
|
-
if (connectResult.error.code === "insuffucient_capacity_available") {
|
|
199
|
-
if (retryNumber >= maxRetries) {
|
|
200
|
-
return connectResult;
|
|
201
|
-
}
|
|
202
|
-
console.info(
|
|
203
|
-
`${connectResult.error.message}, will retry in ${retryDelay / 1e3}sec`
|
|
204
|
-
);
|
|
205
|
-
await new Promise((resolve) => setTimeout(resolve, retryDelay));
|
|
206
|
-
retryNumber += 1;
|
|
207
|
-
console.info(`Retrying... ${retryNumber}/${maxRetries}`);
|
|
208
|
-
continue;
|
|
209
|
-
}
|
|
210
|
-
return connectResult;
|
|
211
|
-
}
|
|
164
|
+
const ws = new WebSocket(phonicApiWsUrl, {
|
|
165
|
+
headers: this.phonic.headers
|
|
166
|
+
});
|
|
167
|
+
return new PhonicSTSWebSocket(ws, config);
|
|
212
168
|
}
|
|
213
169
|
};
|
|
214
170
|
|
|
@@ -268,18 +224,27 @@ var Phonic = class {
|
|
|
268
224
|
headers: this.headers,
|
|
269
225
|
...options
|
|
270
226
|
});
|
|
271
|
-
if (
|
|
272
|
-
const
|
|
273
|
-
|
|
227
|
+
if (response.ok) {
|
|
228
|
+
const data = await response.json();
|
|
229
|
+
return { data, error: null };
|
|
230
|
+
}
|
|
231
|
+
try {
|
|
232
|
+
const data = await response.json();
|
|
233
|
+
const errorMessage = data.error.message || response.statusText;
|
|
234
|
+
return {
|
|
235
|
+
data: null,
|
|
236
|
+
error: {
|
|
237
|
+
message: errorMessage
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
} catch (error) {
|
|
274
241
|
return {
|
|
275
242
|
data: null,
|
|
276
243
|
error: {
|
|
277
|
-
message: statusText
|
|
244
|
+
message: response.statusText
|
|
278
245
|
}
|
|
279
246
|
};
|
|
280
247
|
}
|
|
281
|
-
const data = await response.json();
|
|
282
|
-
return { data, error: null };
|
|
283
248
|
} catch (error) {
|
|
284
249
|
console.error(error);
|
|
285
250
|
return {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "phonic",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"description": "Phonic Node.js SDK",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"build": "tsup",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"@changesets/cli": "2.28.1",
|
|
42
42
|
"@types/bun": "1.2.8",
|
|
43
43
|
"tsup": "8.4.0",
|
|
44
|
-
"typescript": "5.8.
|
|
44
|
+
"typescript": "5.8.3",
|
|
45
45
|
"zod": "3.24.2"
|
|
46
46
|
},
|
|
47
47
|
"files": ["dist/**"],
|