phonic 0.4.0 → 0.5.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/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2024 Phonic, Inc.
1
+ Copyright (c) 2025 Phonic, Inc.
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
4
 
package/README.md CHANGED
@@ -8,6 +8,7 @@ Node.js library for the Phonic API.
8
8
  - [Get voices](#get-voices)
9
9
  - [Get voice by id](#get-voice-by-id)
10
10
  - [Text-to-speech via WebSocket](#text-to-speech-via-websocket)
11
+ - [Speech-to-speech via WebSocket](#speech-to-speech-via-websocket)
11
12
 
12
13
  ## Installation
13
14
 
@@ -19,7 +20,7 @@ npm i phonic
19
20
 
20
21
  Grab an API key from [Phonic settings](https://phonic.co/settings) and pass it to the Phonic constructor.
21
22
 
22
- ```js
23
+ ```ts
23
24
  import { Phonic } from "phonic";
24
25
 
25
26
  const phonic = new Phonic("ph_...");
@@ -29,7 +30,7 @@ const phonic = new Phonic("ph_...");
29
30
 
30
31
  ### Get voices
31
32
 
32
- ```js
33
+ ```ts
33
34
  const { data, error } = await phonic.voices.list({ model: "shasta" });
34
35
 
35
36
  if (error === null) {
@@ -40,7 +41,7 @@ if (error === null) {
40
41
 
41
42
  ### Get voice by id
42
43
 
43
- ```js
44
+ ```ts
44
45
  const { data, error } = await phonic.voices.get("meredith");
45
46
 
46
47
  if (error === null) {
@@ -48,11 +49,95 @@ if (error === null) {
48
49
  }
49
50
  ```
50
51
 
52
+ ### Speesh-to-speech via WebSocket
53
+
54
+ Open a WebSocket connection:
55
+
56
+ ```ts
57
+ const { data, error } = await phonic.sts.websocket();
58
+
59
+ if (error !== null) {
60
+ throw new Error(error.message);
61
+ }
62
+
63
+ // Here we know that the WebSocket connection is open.
64
+ const { phonicWebSocket } = data;
65
+ ```
66
+
67
+ Send config params for the conversation:
68
+
69
+ ```ts
70
+ phonicWebSocket.config({
71
+ input_format: "mulaw_8000",
72
+
73
+ // Optional fields
74
+ system_prompt: "You are a helpful assistant.",
75
+ welcome_message: "Hello, how can I help you?",
76
+ voice_id: "meredith",
77
+ output_format: "mulaw_8000"
78
+ });
79
+ ```
80
+
81
+ Stream input (user) audio chunks:
82
+
83
+ ```ts
84
+ phonicWebSocket.audioChunk({
85
+ audio: "...", // base64 encoded audio chunk
86
+ });
87
+ ```
88
+
89
+ Process messages that Phonic sends back to you:
90
+
91
+ ```ts
92
+ phonicWebSocket.onMessage((message) => {
93
+ switch (message.type) {
94
+ case "input_text": {
95
+ console.log(`User: ${message.text}`);
96
+ break;
97
+ }
98
+
99
+ case "audio_chunk": {
100
+ // Send the audio chunk to Twilio, for example:
101
+ ws.send(
102
+ JSON.stringify({
103
+ event: "media",
104
+ streamSid: "...",
105
+ media: {
106
+ payload: message.audio,
107
+ },
108
+ }),
109
+ );
110
+ break;
111
+ }
112
+ }
113
+ });
114
+ ```
115
+
116
+ To end the conversation, close the WebSocket:
117
+
118
+ ```ts
119
+ phonicWebSocket.close();
120
+ ```
121
+
122
+ You can also listen for close and error events:
123
+
124
+ ```ts
125
+ phonicWebSocket.onClose((event) => {
126
+ console.log(
127
+ `Phonic WebSocket closed with code ${event.code} and reason "${event.reason}"`,
128
+ );
129
+ });
130
+
131
+ phonicWebSocket.onError((event) => {
132
+ console.log(`Error from Phonic WebSocket: ${event.message}`);
133
+ });
134
+ ```
135
+
51
136
  ### Text-to-speech via WebSocket
52
137
 
53
138
  Open a WebSocket connection:
54
139
 
55
- ```js
140
+ ```ts
56
141
  const { data, error } = await phonic.tts.websocket({
57
142
  model: "shasta",
58
143
  output_format: "mulaw_8000",
@@ -69,7 +154,7 @@ const { phonicWebSocket } = data;
69
154
 
70
155
  Process audio chunks that Phonic sends back to you, by sending them to Twilio, for example:
71
156
 
72
- ```js
157
+ ```ts
73
158
  phonicWebSocket.onMessage((message) => {
74
159
  if (message.type === "audio_chunk") {
75
160
  ws.send(
@@ -87,7 +172,7 @@ phonicWebSocket.onMessage((message) => {
87
172
 
88
173
  Send text chunks to Phonic for audio generation as you receive them from LLM:
89
174
 
90
- ```js
175
+ ```ts
91
176
  const stream = await openai.chat.completions.create(...);
92
177
 
93
178
  for await (const chunk of stream) {
@@ -101,25 +186,25 @@ for await (const chunk of stream) {
101
186
 
102
187
  Tell Phonic to finish generating audio for all text chunks you've sent:
103
188
 
104
- ```js
189
+ ```ts
105
190
  phonicWebSocket.flush();
106
191
  ```
107
192
 
108
193
  You can also tell Phonic to stop sending audio chunks back, e.g. if the user interrupts the conversation:
109
194
 
110
- ```js
195
+ ```ts
111
196
  phonicWebSocket.stop();
112
197
  ```
113
198
 
114
199
  To close the WebSocket connection:
115
200
 
116
- ```js
201
+ ```ts
117
202
  phonicWebSocket.close();
118
203
  ```
119
204
 
120
205
  To know when the last audio chunk has been received:
121
206
 
122
- ```js
207
+ ```ts
123
208
  phonicWebSocket.onMessage((message) => {
124
209
  if (message.type === "flushed") {
125
210
  console.log("Last audio chunk received");
@@ -129,7 +214,7 @@ phonicWebSocket.onMessage((message) => {
129
214
 
130
215
  You can also listen for close and error events:
131
216
 
132
- ```js
217
+ ```ts
133
218
  phonicWebSocket.onClose((event) => {
134
219
  console.log(
135
220
  `Phonic WebSocket closed with code ${event.code} and reason "${event.reason}"`,
package/dist/index.d.mts CHANGED
@@ -18,12 +18,12 @@ type DataOrError<T> = Promise<{
18
18
  error: ErrorResponse;
19
19
  }>;
20
20
 
21
- type PhonicWebSocketParams = {
21
+ type PhonicTTSWebSocketParams = {
22
22
  model?: string;
23
23
  output_format?: string;
24
24
  voice_id?: string;
25
25
  };
26
- type PhonicWebSocketResponseMessage = {
26
+ type PhonicTTSWebSocketResponseMessage = {
27
27
  type: "config";
28
28
  model: string;
29
29
  output_format: string;
@@ -50,19 +50,19 @@ type PhonicWebSocketResponseMessage = {
50
50
  speed?: string;
51
51
  };
52
52
  };
53
- type OnMessageCallback = (message: PhonicWebSocketResponseMessage) => void;
54
- type OnCloseCallback = (event: WebSocket.CloseEvent) => void;
55
- type OnErrorCallback = (event: WebSocket.ErrorEvent) => void;
53
+ type OnMessageCallback$1 = (message: PhonicTTSWebSocketResponseMessage) => void;
54
+ type OnCloseCallback$1 = (event: WebSocket.CloseEvent) => void;
55
+ type OnErrorCallback$1 = (event: WebSocket.ErrorEvent) => void;
56
56
 
57
- declare class PhonicWebSocket {
57
+ declare class PhonicTTSWebSocket {
58
58
  private readonly ws;
59
59
  private onMessageCallback;
60
60
  private onCloseCallback;
61
61
  private onErrorCallback;
62
62
  constructor(ws: WebSocket);
63
- onMessage(callback: OnMessageCallback): void;
64
- onClose(callback: OnCloseCallback): void;
65
- onError(callback: OnErrorCallback): void;
63
+ onMessage(callback: OnMessageCallback$1): void;
64
+ onClose(callback: OnCloseCallback$1): void;
65
+ onError(callback: OnErrorCallback$1): void;
66
66
  generate(message: {
67
67
  text: string;
68
68
  speed?: number;
@@ -75,8 +75,8 @@ declare class PhonicWebSocket {
75
75
  declare class TextToSpeech {
76
76
  private readonly phonic;
77
77
  constructor(phonic: Phonic);
78
- websocket(params?: PhonicWebSocketParams): DataOrError<{
79
- phonicWebSocket: PhonicWebSocket;
78
+ websocket(params?: PhonicTTSWebSocketParams): DataOrError<{
79
+ phonicWebSocket: PhonicTTSWebSocket;
80
80
  }>;
81
81
  }
82
82
 
@@ -117,4 +117,51 @@ declare class Phonic {
117
117
  }>;
118
118
  }
119
119
 
120
- export { Phonic, PhonicWebSocket };
120
+ type PhonicSTSWebSocketResponseMessage = {
121
+ type: "input_text";
122
+ text: string;
123
+ } | {
124
+ type: "audio_chunk";
125
+ text: string;
126
+ audio: string;
127
+ } | {
128
+ type: "error";
129
+ error: {
130
+ message: string;
131
+ code?: string;
132
+ };
133
+ paramErrors?: {
134
+ system_prompt?: string;
135
+ welcome_message?: string;
136
+ voice_id?: string;
137
+ input_format?: string;
138
+ output_format?: string;
139
+ };
140
+ };
141
+ type OnMessageCallback = (message: PhonicSTSWebSocketResponseMessage) => void;
142
+ type OnCloseCallback = (event: WebSocket.CloseEvent) => void;
143
+ type OnErrorCallback = (event: WebSocket.ErrorEvent) => void;
144
+
145
+ declare class PhonicSTSWebSocket {
146
+ private readonly ws;
147
+ private onMessageCallback;
148
+ private onCloseCallback;
149
+ private onErrorCallback;
150
+ constructor(ws: WebSocket);
151
+ onMessage(callback: OnMessageCallback): void;
152
+ onClose(callback: OnCloseCallback): void;
153
+ onError(callback: OnErrorCallback): void;
154
+ config(message: {
155
+ system_prompt?: string;
156
+ welcome_message?: string;
157
+ voice_id?: string;
158
+ input_format?: "pcm_44100" | "mulaw_8000";
159
+ output_format?: "pcm_44100" | "mulaw_8000";
160
+ }): void;
161
+ audioChunk(message: {
162
+ audio: string;
163
+ }): void;
164
+ close(): void;
165
+ }
166
+
167
+ export { Phonic, PhonicSTSWebSocket, PhonicTTSWebSocket };
package/dist/index.d.ts CHANGED
@@ -18,12 +18,12 @@ type DataOrError<T> = Promise<{
18
18
  error: ErrorResponse;
19
19
  }>;
20
20
 
21
- type PhonicWebSocketParams = {
21
+ type PhonicTTSWebSocketParams = {
22
22
  model?: string;
23
23
  output_format?: string;
24
24
  voice_id?: string;
25
25
  };
26
- type PhonicWebSocketResponseMessage = {
26
+ type PhonicTTSWebSocketResponseMessage = {
27
27
  type: "config";
28
28
  model: string;
29
29
  output_format: string;
@@ -50,19 +50,19 @@ type PhonicWebSocketResponseMessage = {
50
50
  speed?: string;
51
51
  };
52
52
  };
53
- type OnMessageCallback = (message: PhonicWebSocketResponseMessage) => void;
54
- type OnCloseCallback = (event: WebSocket.CloseEvent) => void;
55
- type OnErrorCallback = (event: WebSocket.ErrorEvent) => void;
53
+ type OnMessageCallback$1 = (message: PhonicTTSWebSocketResponseMessage) => void;
54
+ type OnCloseCallback$1 = (event: WebSocket.CloseEvent) => void;
55
+ type OnErrorCallback$1 = (event: WebSocket.ErrorEvent) => void;
56
56
 
57
- declare class PhonicWebSocket {
57
+ declare class PhonicTTSWebSocket {
58
58
  private readonly ws;
59
59
  private onMessageCallback;
60
60
  private onCloseCallback;
61
61
  private onErrorCallback;
62
62
  constructor(ws: WebSocket);
63
- onMessage(callback: OnMessageCallback): void;
64
- onClose(callback: OnCloseCallback): void;
65
- onError(callback: OnErrorCallback): void;
63
+ onMessage(callback: OnMessageCallback$1): void;
64
+ onClose(callback: OnCloseCallback$1): void;
65
+ onError(callback: OnErrorCallback$1): void;
66
66
  generate(message: {
67
67
  text: string;
68
68
  speed?: number;
@@ -75,8 +75,8 @@ declare class PhonicWebSocket {
75
75
  declare class TextToSpeech {
76
76
  private readonly phonic;
77
77
  constructor(phonic: Phonic);
78
- websocket(params?: PhonicWebSocketParams): DataOrError<{
79
- phonicWebSocket: PhonicWebSocket;
78
+ websocket(params?: PhonicTTSWebSocketParams): DataOrError<{
79
+ phonicWebSocket: PhonicTTSWebSocket;
80
80
  }>;
81
81
  }
82
82
 
@@ -117,4 +117,51 @@ declare class Phonic {
117
117
  }>;
118
118
  }
119
119
 
120
- export { Phonic, PhonicWebSocket };
120
+ type PhonicSTSWebSocketResponseMessage = {
121
+ type: "input_text";
122
+ text: string;
123
+ } | {
124
+ type: "audio_chunk";
125
+ text: string;
126
+ audio: string;
127
+ } | {
128
+ type: "error";
129
+ error: {
130
+ message: string;
131
+ code?: string;
132
+ };
133
+ paramErrors?: {
134
+ system_prompt?: string;
135
+ welcome_message?: string;
136
+ voice_id?: string;
137
+ input_format?: string;
138
+ output_format?: string;
139
+ };
140
+ };
141
+ type OnMessageCallback = (message: PhonicSTSWebSocketResponseMessage) => void;
142
+ type OnCloseCallback = (event: WebSocket.CloseEvent) => void;
143
+ type OnErrorCallback = (event: WebSocket.ErrorEvent) => void;
144
+
145
+ declare class PhonicSTSWebSocket {
146
+ private readonly ws;
147
+ private onMessageCallback;
148
+ private onCloseCallback;
149
+ private onErrorCallback;
150
+ constructor(ws: WebSocket);
151
+ onMessage(callback: OnMessageCallback): void;
152
+ onClose(callback: OnCloseCallback): void;
153
+ onError(callback: OnErrorCallback): void;
154
+ config(message: {
155
+ system_prompt?: string;
156
+ welcome_message?: string;
157
+ voice_id?: string;
158
+ input_format?: "pcm_44100" | "mulaw_8000";
159
+ output_format?: "pcm_44100" | "mulaw_8000";
160
+ }): void;
161
+ audioChunk(message: {
162
+ audio: string;
163
+ }): void;
164
+ close(): void;
165
+ }
166
+
167
+ export { Phonic, PhonicSTSWebSocket, PhonicTTSWebSocket };
package/dist/index.js CHANGED
@@ -35,13 +35,13 @@ __export(index_exports, {
35
35
  module.exports = __toCommonJS(index_exports);
36
36
 
37
37
  // package.json
38
- var version = "0.4.0";
38
+ var version = "0.5.0";
39
39
 
40
40
  // src/tts/index.ts
41
41
  var import_ws = __toESM(require("ws"));
42
42
 
43
43
  // src/tts/websocket.ts
44
- var PhonicWebSocket = class {
44
+ var PhonicTTSWebSocket = class {
45
45
  constructor(ws) {
46
46
  this.ws = ws;
47
47
  this.ws.onmessage = (event) => {
@@ -51,7 +51,9 @@ var PhonicWebSocket = class {
51
51
  if (typeof event.data !== "string") {
52
52
  throw new Error("Received non-string message");
53
53
  }
54
- const dataObj = JSON.parse(event.data);
54
+ const dataObj = JSON.parse(
55
+ event.data
56
+ );
55
57
  this.onMessageCallback(dataObj);
56
58
  };
57
59
  this.ws.onclose = (event) => {
@@ -67,6 +69,8 @@ var PhonicWebSocket = class {
67
69
  this.onErrorCallback(event);
68
70
  };
69
71
  this.onMessage = this.onMessage.bind(this);
72
+ this.onClose = this.onClose.bind(this);
73
+ this.onError = this.onError.bind(this);
70
74
  this.generate = this.generate.bind(this);
71
75
  this.flush = this.flush.bind(this);
72
76
  this.stop = this.stop.bind(this);
@@ -118,7 +122,7 @@ var TextToSpeech = class {
118
122
  }
119
123
  });
120
124
  ws.onopen = () => {
121
- const phonicWebSocket = new PhonicWebSocket(ws);
125
+ const phonicWebSocket = new PhonicTTSWebSocket(ws);
122
126
  resolve({ data: { phonicWebSocket }, error: null });
123
127
  };
124
128
  ws.onerror = (error) => {
package/dist/index.mjs CHANGED
@@ -1,11 +1,11 @@
1
1
  // package.json
2
- var version = "0.4.0";
2
+ var version = "0.5.0";
3
3
 
4
4
  // src/tts/index.ts
5
5
  import WebSocket from "ws";
6
6
 
7
7
  // src/tts/websocket.ts
8
- var PhonicWebSocket = class {
8
+ var PhonicTTSWebSocket = class {
9
9
  constructor(ws) {
10
10
  this.ws = ws;
11
11
  this.ws.onmessage = (event) => {
@@ -15,7 +15,9 @@ var PhonicWebSocket = class {
15
15
  if (typeof event.data !== "string") {
16
16
  throw new Error("Received non-string message");
17
17
  }
18
- const dataObj = JSON.parse(event.data);
18
+ const dataObj = JSON.parse(
19
+ event.data
20
+ );
19
21
  this.onMessageCallback(dataObj);
20
22
  };
21
23
  this.ws.onclose = (event) => {
@@ -31,6 +33,8 @@ var PhonicWebSocket = class {
31
33
  this.onErrorCallback(event);
32
34
  };
33
35
  this.onMessage = this.onMessage.bind(this);
36
+ this.onClose = this.onClose.bind(this);
37
+ this.onError = this.onError.bind(this);
34
38
  this.generate = this.generate.bind(this);
35
39
  this.flush = this.flush.bind(this);
36
40
  this.stop = this.stop.bind(this);
@@ -82,7 +86,7 @@ var TextToSpeech = class {
82
86
  }
83
87
  });
84
88
  ws.onopen = () => {
85
- const phonicWebSocket = new PhonicWebSocket(ws);
89
+ const phonicWebSocket = new PhonicTTSWebSocket(ws);
86
90
  resolve({ data: { phonicWebSocket }, error: null });
87
91
  };
88
92
  ws.onerror = (error) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "phonic",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Phonic Node.js SDK",
5
5
  "scripts": {
6
6
  "build": "tsup",
@@ -33,13 +33,13 @@
33
33
  "url": "https://github.com/Phonic-Co/phonic-node/issues"
34
34
  },
35
35
  "dependencies": {
36
- "ws": "8.18.0"
36
+ "ws": "8.18.1"
37
37
  },
38
38
  "devDependencies": {
39
39
  "@biomejs/biome": "1.9.4",
40
- "@changesets/changelog-github": "0.5.0",
41
- "@changesets/cli": "2.27.12",
42
- "@types/bun": "1.2.2",
40
+ "@changesets/changelog-github": "0.5.1",
41
+ "@changesets/cli": "2.28.1",
42
+ "@types/bun": "1.2.3",
43
43
  "tsup": "8.3.6",
44
44
  "typescript": "5.7.3",
45
45
  "zod": "3.24.2"