Skip to content

Commit 5da606d

Browse files
SandraRodgersnaomi-lgbt
authored andcommitted
feat: finishing touches TTS live client
1 parent a3112bc commit 5da606d

5 files changed

Lines changed: 70 additions & 63 deletions

File tree

examples/node-speak-live/index.js

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,62 @@
1+
const fs = require("fs");
12
const { createClient, LiveTTSEvents } = require("../../dist/main/index");
2-
const fetch = require("cross-fetch");
33

44
const live = async () => {
55
const text = "Hello, how can I help you today?";
66

7-
const deepgram = createClient(process.env.DEEPGRAM_API_KEY, {
8-
global: { fetch: { options: { url: "https://api.beta.deepgram.com" } } },
9-
});
7+
const deepgram = createClient(process.env.DEEPGRAM_API_KEY);
8+
9+
const connection = deepgram.speak.live({ model: "aura-asteria-en" });
1010

11-
const connection = deepgram.speak.live({ text }, { model: "aura-asteria-en" });
11+
let audioBuffer = Buffer.alloc(0);
1212

1313
connection.on(LiveTTSEvents.Open, () => {
14+
console.log("Connection opened");
15+
16+
// Send text data for TTS synthesis
17+
connection.sendText(text);
18+
19+
// Send Flush message to the server after sending the text
20+
connection.flush();
21+
1422
connection.on(LiveTTSEvents.Close, () => {
15-
console.log("Connection closed.");
23+
console.log("Connection closed");
1624
});
1725

1826
connection.on(LiveTTSEvents.Metadata, (data) => {
19-
console.log(`Deepgram Metadata: ${data}`);
27+
console.dir(data, { depth: null });
2028
});
2129

2230
connection.on(LiveTTSEvents.Audio, (data) => {
23-
console.log(`Deepgram Audio: ${data}`);
31+
console.log("Deepgram audio data received");
32+
// Concatenate the audio chunks into a single buffer
33+
const buffer = Buffer.from(data);
34+
audioBuffer = Buffer.concat([audioBuffer, buffer]);
2435
});
2536

26-
connection.on(LiveTTSEvents.Flushed, (data) => {
37+
connection.on(LiveTTSEvents.Flushed, () => {
2738
console.log("Deepgram Flushed");
39+
// Write the buffered audio data to a file when the flush event is received
40+
writeFile();
2841
});
2942

3043
connection.on(LiveTTSEvents.Error, (err) => {
3144
console.error(err);
3245
});
46+
});
3347

34-
fetch(url)
35-
.then((r) => r.body)
36-
.then((res) => {
37-
res.on("readable", () => {
38-
connection.send(res.read());
39-
});
48+
const writeFile = () => {
49+
if (audioBuffer.length > 0) {
50+
fs.writeFile("output.mp3", audioBuffer, (err) => {
51+
if (err) {
52+
console.error("Error writing audio file:", err);
53+
} else {
54+
console.log("Audio file saved as output.mp3");
55+
}
4056
});
41-
});
57+
audioBuffer = Buffer.alloc(0); // Reset buffer after writing
58+
}
59+
};
4260
};
4361

4462
live();

src/packages/AbstractLiveClient.ts

Lines changed: 0 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import { CONNECTION_STATE, SOCKET_STATES } from "../lib/constants";
33
import type { DeepgramClientOptions, LiveSchema } from "../lib/types";
44
import type { WebSocket as WSWebSocket } from "ws";
55
import { isBun } from "../lib/helpers";
6-
import { LiveTTSEvents } from "../lib/enums";
76

87
/**
98
* Represents a constructor for a WebSocket-like object that can be used in the application.
@@ -277,48 +276,6 @@ export abstract class AbstractLiveClient extends AbstractClient {
277276
* @abstract Requires subclasses to set up context aware event handlers.
278277
*/
279278
abstract setupConnection(): void;
280-
281-
/**
282-
* Handles incoming messages from the WebSocket connection.
283-
* @param event - The MessageEvent object representing the received message.
284-
*/
285-
protected handleMessage(event: MessageEvent): void {
286-
if (typeof event.data === "string") {
287-
try {
288-
const data = JSON.parse(event.data);
289-
this.handleTextMessage(data);
290-
} catch (error) {
291-
this.emit(LiveTTSEvents.Error, {
292-
event,
293-
message: "Unable to parse `data` as JSON.",
294-
error,
295-
});
296-
}
297-
} else if (event.data instanceof ArrayBuffer) {
298-
this.handleBinaryMessage(event.data);
299-
} else {
300-
this.emit(LiveTTSEvents.Error, {
301-
event,
302-
message: "Received unknown data type.",
303-
});
304-
}
305-
}
306-
307-
/**
308-
* Handles text messages received from the WebSocket connection.
309-
* @param data - The parsed JSON data.
310-
*/
311-
protected handleTextMessage(data: any): void {
312-
// To be implemented by subclasses
313-
}
314-
315-
/**
316-
* Handles binary messages received from the WebSocket connection.
317-
* @param data - The binary data.
318-
*/
319-
protected handleBinaryMessage(data: ArrayBuffer): void {
320-
// To be implemented by subclasses
321-
}
322279
}
323280

324281
class WSWebSocketDummy {

src/packages/SpeakClient.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { AbstractClient } from "./AbstractClient";
22
import { SpeakLiveClient } from "./SpeakLiveClient";
33
import { SpeakRestClient } from "./SpeakRestClient";
44
import { SpeakSchema } from "../lib/types";
5+
import { TextSource } from "../lib/types";
56

67
/**
78
* The `SpeakClient` class extends the `AbstractClient` class and provides access to the "speak" namespace.
@@ -16,8 +17,10 @@ export class SpeakClient extends AbstractClient {
1617
/**
1718
* Returns a `SpeakRestClient` instance for interacting with the rest speak API.
1819
*/
19-
get request() {
20-
return new SpeakRestClient(this.options);
20+
public request(source: TextSource, options?: SpeakSchema, endpoint = ":version/speak") {
21+
const client = new SpeakRestClient(this.options);
22+
23+
return client.request(source, options, endpoint);
2124
}
2225

2326
/**

src/packages/SpeakLiveClient.ts

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,7 @@ import type { SpeakSchema, DeepgramClientOptions } from "../lib/types";
1111
*
1212
* The `configure` method allows you to send additional configuration options to the connected session.
1313
*
14-
*
1514
* The `requestClose` method requests the server to close the connection.
16-
*
1715
*/
1816
export class SpeakLiveClient extends AbstractLiveClient {
1917
public namespace: string = "speak";
@@ -133,4 +131,33 @@ export class SpeakLiveClient extends AbstractLiveClient {
133131
})
134132
);
135133
}
134+
135+
/**
136+
* Handles incoming messages from the WebSocket connection.
137+
* @param event - The MessageEvent object representing the received message.
138+
*/
139+
protected handleMessage(event: MessageEvent): void {
140+
if (typeof event.data === "string") {
141+
try {
142+
const data = JSON.parse(event.data);
143+
this.handleTextMessage(data);
144+
} catch (error) {
145+
this.emit(LiveTTSEvents.Error, {
146+
event,
147+
message: "Unable to parse `data` as JSON.",
148+
error,
149+
});
150+
}
151+
} else if (event.data instanceof ArrayBuffer) {
152+
this.handleBinaryMessage(event.data);
153+
} else if (Buffer.isBuffer(event.data)) {
154+
this.handleBinaryMessage(event.data.buffer);
155+
} else {
156+
console.log("Received unknown data type", event.data);
157+
this.emit(LiveTTSEvents.Error, {
158+
event,
159+
message: "Received unknown data type.",
160+
});
161+
}
162+
}
136163
}

src/packages/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,5 @@ export * from "./ModelsRestClient";
99
export * from "./ReadRestClient";
1010
export * from "./SelfHostedRestClient";
1111
export * from "./SpeakClient";
12+
export * from "./SpeakLiveClient";
13+
export * from "./SpeakRestClient";

0 commit comments

Comments
 (0)