hume 0.13.4 → 0.13.5
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/api/resources/empathicVoice/types/SessionSettings.d.ts +2 -0
- package/api/resources/tts/types/SnippetAudioChunk.d.ts +5 -0
- package/dist/api/resources/empathicVoice/types/SessionSettings.d.ts +2 -0
- package/dist/api/resources/tts/types/SnippetAudioChunk.d.ts +5 -0
- package/dist/serialization/resources/empathicVoice/types/SessionSettings.d.ts +1 -0
- package/dist/serialization/resources/empathicVoice/types/SessionSettings.js +1 -0
- package/dist/serialization/resources/tts/types/SnippetAudioChunk.d.ts +1 -0
- package/dist/serialization/resources/tts/types/SnippetAudioChunk.js +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/wrapper/SilenceFiller.d.ts +85 -0
- package/dist/wrapper/SilenceFiller.js +203 -0
- package/dist/wrapper/collate.d.ts +36 -0
- package/dist/wrapper/collate.js +126 -0
- package/dist/wrapper/index.d.ts +2 -0
- package/dist/wrapper/index.js +5 -1
- package/package.json +1 -1
- package/serialization/resources/empathicVoice/types/SessionSettings.d.ts +1 -0
- package/serialization/resources/empathicVoice/types/SessionSettings.js +1 -0
- package/serialization/resources/tts/types/SnippetAudioChunk.d.ts +1 -0
- package/serialization/resources/tts/types/SnippetAudioChunk.js +1 -0
- package/version.d.ts +1 -1
- package/version.js +1 -1
- package/wrapper/SilenceFiller.d.ts +85 -0
- package/wrapper/SilenceFiller.js +203 -0
- package/wrapper/collate.d.ts +36 -0
- package/wrapper/collate.js +126 -0
- package/wrapper/index.d.ts +2 -0
- package/wrapper/index.js +5 -1
- package/.mock/definition/api.yml +0 -12
- package/.mock/definition/empathic-voice/__package__.yml +0 -2971
- package/.mock/definition/empathic-voice/chat.yml +0 -175
- package/.mock/definition/empathic-voice/chatGroups.yml +0 -627
- package/.mock/definition/empathic-voice/chatWebhooks.yml +0 -30
- package/.mock/definition/empathic-voice/chats.yml +0 -506
- package/.mock/definition/empathic-voice/configs.yml +0 -842
- package/.mock/definition/empathic-voice/prompts.yml +0 -558
- package/.mock/definition/empathic-voice/tools.yml +0 -626
- package/.mock/definition/expression-measurement/__package__.yml +0 -1
- package/.mock/definition/expression-measurement/batch/__package__.yml +0 -1803
- package/.mock/definition/expression-measurement/stream/__package__.yml +0 -113
- package/.mock/definition/expression-measurement/stream/stream.yml +0 -438
- package/.mock/definition/tts/__package__.yml +0 -709
- package/.mock/definition/tts/streamInput.yml +0 -56
- package/.mock/definition/tts/voices.yml +0 -143
- package/.mock/fern.config.json +0 -4
|
@@ -75,4 +75,6 @@ export interface SessionSettings {
|
|
|
75
75
|
* Using this field, you can personalize responses based on session-specific details. For more guidance, see our [guide on using dynamic variables](/docs/speech-to-speech-evi/features/dynamic-variables).
|
|
76
76
|
*/
|
|
77
77
|
variables?: Record<string, Hume.empathicVoice.SessionSettingsVariablesValue>;
|
|
78
|
+
/** Allows you to change the voice during an active chat. Updating the voice does not affect chat context or conversation history. */
|
|
79
|
+
voiceId?: string;
|
|
78
80
|
}
|
|
@@ -2,7 +2,12 @@
|
|
|
2
2
|
* This file was auto-generated by Fern from our API Definition.
|
|
3
3
|
*/
|
|
4
4
|
import * as Hume from "../../../index";
|
|
5
|
+
/**
|
|
6
|
+
* Metadata for a chunk of generated audio.
|
|
7
|
+
*/
|
|
5
8
|
export interface SnippetAudioChunk {
|
|
9
|
+
/** ID of the initiating request. */
|
|
10
|
+
requestId: string;
|
|
6
11
|
/** The generation ID of the parent snippet that this chunk corresponds to. */
|
|
7
12
|
generationId: string;
|
|
8
13
|
/** The ID of the parent snippet that this chunk corresponds to. */
|
|
@@ -75,4 +75,6 @@ export interface SessionSettings {
|
|
|
75
75
|
* Using this field, you can personalize responses based on session-specific details. For more guidance, see our [guide on using dynamic variables](/docs/speech-to-speech-evi/features/dynamic-variables).
|
|
76
76
|
*/
|
|
77
77
|
variables?: Record<string, Hume.empathicVoice.SessionSettingsVariablesValue>;
|
|
78
|
+
/** Allows you to change the voice during an active chat. Updating the voice does not affect chat context or conversation history. */
|
|
79
|
+
voiceId?: string;
|
|
78
80
|
}
|
|
@@ -2,7 +2,12 @@
|
|
|
2
2
|
* This file was auto-generated by Fern from our API Definition.
|
|
3
3
|
*/
|
|
4
4
|
import * as Hume from "../../../index";
|
|
5
|
+
/**
|
|
6
|
+
* Metadata for a chunk of generated audio.
|
|
7
|
+
*/
|
|
5
8
|
export interface SnippetAudioChunk {
|
|
9
|
+
/** ID of the initiating request. */
|
|
10
|
+
requestId: string;
|
|
6
11
|
/** The generation ID of the parent snippet that this chunk corresponds to. */
|
|
7
12
|
generationId: string;
|
|
8
13
|
/** The ID of the parent snippet that this chunk corresponds to. */
|
|
@@ -54,4 +54,5 @@ exports.SessionSettings = core.serialization.object({
|
|
|
54
54
|
builtinTools: core.serialization.property("builtin_tools", core.serialization.list(BuiltinToolConfig_1.BuiltinToolConfig).optional()),
|
|
55
55
|
metadata: core.serialization.record(core.serialization.string(), core.serialization.unknown()).optional(),
|
|
56
56
|
variables: core.serialization.record(core.serialization.string(), SessionSettingsVariablesValue_1.SessionSettingsVariablesValue).optional(),
|
|
57
|
+
voiceId: core.serialization.property("voice_id", core.serialization.string().optional()),
|
|
57
58
|
});
|
|
@@ -9,6 +9,7 @@ import { Snippet } from "./Snippet";
|
|
|
9
9
|
export declare const SnippetAudioChunk: core.serialization.ObjectSchema<serializers.tts.SnippetAudioChunk.Raw, Hume.tts.SnippetAudioChunk>;
|
|
10
10
|
export declare namespace SnippetAudioChunk {
|
|
11
11
|
interface Raw {
|
|
12
|
+
request_id: string;
|
|
12
13
|
generation_id: string;
|
|
13
14
|
snippet_id: string;
|
|
14
15
|
text: string;
|
|
@@ -41,6 +41,7 @@ const core = __importStar(require("../../../../core"));
|
|
|
41
41
|
const AudioFormatType_1 = require("./AudioFormatType");
|
|
42
42
|
const Snippet_1 = require("./Snippet");
|
|
43
43
|
exports.SnippetAudioChunk = core.serialization.object({
|
|
44
|
+
requestId: core.serialization.property("request_id", core.serialization.string()),
|
|
44
45
|
generationId: core.serialization.property("generation_id", core.serialization.string()),
|
|
45
46
|
snippetId: core.serialization.property("snippet_id", core.serialization.string()),
|
|
46
47
|
text: core.serialization.string(),
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const SDK_VERSION = "0.13.
|
|
1
|
+
export declare const SDK_VERSION = "0.13.5";
|
package/dist/version.js
CHANGED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { Readable } from "stream";
|
|
2
|
+
/**
|
|
3
|
+
* SilenceFiller is a Readable stream that intersperses incoming audio data
|
|
4
|
+
* with bytes of silence. This is important in some cases to keep an audio
|
|
5
|
+
* stream "alive". Audio players, such as ffmpeg, can interpret inactivity as
|
|
6
|
+
* meaning the stream is ended, or disconnected.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import { SilenceFiller } from 'hume';
|
|
11
|
+
*
|
|
12
|
+
* const BYTES_PER_SAMPLE = 2; // 16-bit samples
|
|
13
|
+
* const SAMPLE_RATE = 48000;
|
|
14
|
+
* const BUFFER_SIZE = Math.floor(SAMPLE_RATE * 0.1 * BYTES_PER_SAMPLE); // 100ms buffer
|
|
15
|
+
* const silenceFiller = new SilenceFiller(BUFFER_SIZE, SAMPLE_RATE, BYTES_PER_SAMPLE, 10);
|
|
16
|
+
*
|
|
17
|
+
* // Pipe silence filler output to audio player stdin
|
|
18
|
+
* silenceFiller.pipe(audioPlayer.stdin);
|
|
19
|
+
*
|
|
20
|
+
* // Handle pipe errors
|
|
21
|
+
* silenceFiller.on('error', (err) => {
|
|
22
|
+
* console.error("SilenceFiller error:", err);
|
|
23
|
+
* });
|
|
24
|
+
*
|
|
25
|
+
* // Write audio data as it arrives
|
|
26
|
+
* silenceFiller.writeAudio(audioBuffer);
|
|
27
|
+
*
|
|
28
|
+
* // End the stream when done
|
|
29
|
+
* await silenceFiller.endStream();
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export declare class SilenceFiller extends Readable {
|
|
33
|
+
private unclockedSilenceFiller;
|
|
34
|
+
private isStarted;
|
|
35
|
+
private pushInterval;
|
|
36
|
+
private bytesPerSample;
|
|
37
|
+
private pushIntervalMs;
|
|
38
|
+
/**
|
|
39
|
+
* Creates a new SilenceFiller instance.
|
|
40
|
+
*
|
|
41
|
+
* @param pushIntervalMs - The interval in milliseconds for pushing audio data (default: 5ms).
|
|
42
|
+
* @param sampleRate - The sample rate of the audio (e.g., 48000).
|
|
43
|
+
* @param bytesPerSample - The number of bytes per audio sample (e.g., 2 for 16-bit).
|
|
44
|
+
* @param bufferSize - How much to 'prebuffer'. If you set this too low there
|
|
45
|
+
* is a chance that playback will stutter, but if you set it too high
|
|
46
|
+
* playback will take longer to start.
|
|
47
|
+
*/
|
|
48
|
+
constructor(pushIntervalMs?: number, sampleRate?: number, bytesPerSample?: number, bufferSize?: number);
|
|
49
|
+
/**
|
|
50
|
+
* Writes audio data to the silence filler.
|
|
51
|
+
*
|
|
52
|
+
* @param audioBuffer - The audio buffer to write.
|
|
53
|
+
*/
|
|
54
|
+
writeAudio(audioBuffer: Buffer): void;
|
|
55
|
+
private startPushInterval;
|
|
56
|
+
private pushData;
|
|
57
|
+
_read(): void;
|
|
58
|
+
_destroy(error: Error | null, callback: (error?: Error | null) => void): void;
|
|
59
|
+
/**
|
|
60
|
+
* Ends the stream and drains all remaining audio data.
|
|
61
|
+
*
|
|
62
|
+
* @returns A promise that resolves when the stream has ended.
|
|
63
|
+
*/
|
|
64
|
+
endStream(): Promise<void>;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Does the actual calculation of how interspersing audio with silence
|
|
68
|
+
* is "pure" in the sense that it does not rely on the system clock.
|
|
69
|
+
* It's up to the caller to provide timestamps.
|
|
70
|
+
*
|
|
71
|
+
* @internal
|
|
72
|
+
*/
|
|
73
|
+
export declare class UnclockedSilenceFiller {
|
|
74
|
+
private audioQueue;
|
|
75
|
+
private totalBufferedBytes;
|
|
76
|
+
private startTimestamp;
|
|
77
|
+
private totalBytesSent;
|
|
78
|
+
donePrebuffering: boolean;
|
|
79
|
+
private bufferSize;
|
|
80
|
+
private sampleRate;
|
|
81
|
+
private bytesPerSample;
|
|
82
|
+
constructor(bufferSize: number, sampleRate: number, bytesPerSample: number);
|
|
83
|
+
writeAudio(audioBuffer: Buffer, timestamp: number): void;
|
|
84
|
+
readAudio(timestamp: number): Buffer | null;
|
|
85
|
+
}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.UnclockedSilenceFiller = exports.SilenceFiller = void 0;
|
|
4
|
+
const stream_1 = require("stream");
|
|
5
|
+
/**
|
|
6
|
+
* SilenceFiller is a Readable stream that intersperses incoming audio data
|
|
7
|
+
* with bytes of silence. This is important in some cases to keep an audio
|
|
8
|
+
* stream "alive". Audio players, such as ffmpeg, can interpret inactivity as
|
|
9
|
+
* meaning the stream is ended, or disconnected.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* import { SilenceFiller } from 'hume';
|
|
14
|
+
*
|
|
15
|
+
* const BYTES_PER_SAMPLE = 2; // 16-bit samples
|
|
16
|
+
* const SAMPLE_RATE = 48000;
|
|
17
|
+
* const BUFFER_SIZE = Math.floor(SAMPLE_RATE * 0.1 * BYTES_PER_SAMPLE); // 100ms buffer
|
|
18
|
+
* const silenceFiller = new SilenceFiller(BUFFER_SIZE, SAMPLE_RATE, BYTES_PER_SAMPLE, 10);
|
|
19
|
+
*
|
|
20
|
+
* // Pipe silence filler output to audio player stdin
|
|
21
|
+
* silenceFiller.pipe(audioPlayer.stdin);
|
|
22
|
+
*
|
|
23
|
+
* // Handle pipe errors
|
|
24
|
+
* silenceFiller.on('error', (err) => {
|
|
25
|
+
* console.error("SilenceFiller error:", err);
|
|
26
|
+
* });
|
|
27
|
+
*
|
|
28
|
+
* // Write audio data as it arrives
|
|
29
|
+
* silenceFiller.writeAudio(audioBuffer);
|
|
30
|
+
*
|
|
31
|
+
* // End the stream when done
|
|
32
|
+
* await silenceFiller.endStream();
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
class SilenceFiller extends stream_1.Readable {
|
|
36
|
+
/**
|
|
37
|
+
* Creates a new SilenceFiller instance.
|
|
38
|
+
*
|
|
39
|
+
* @param pushIntervalMs - The interval in milliseconds for pushing audio data (default: 5ms).
|
|
40
|
+
* @param sampleRate - The sample rate of the audio (e.g., 48000).
|
|
41
|
+
* @param bytesPerSample - The number of bytes per audio sample (e.g., 2 for 16-bit).
|
|
42
|
+
* @param bufferSize - How much to 'prebuffer'. If you set this too low there
|
|
43
|
+
* is a chance that playback will stutter, but if you set it too high
|
|
44
|
+
* playback will take longer to start.
|
|
45
|
+
*/
|
|
46
|
+
constructor(pushIntervalMs = 5, sampleRate = 48000, bytesPerSample = 2, bufferSize = 9600) {
|
|
47
|
+
super({ objectMode: false });
|
|
48
|
+
this.isStarted = false;
|
|
49
|
+
this.pushInterval = null;
|
|
50
|
+
this.unclockedSilenceFiller = new UnclockedSilenceFiller(bufferSize, sampleRate, bytesPerSample);
|
|
51
|
+
this.bytesPerSample = bytesPerSample;
|
|
52
|
+
this.pushIntervalMs = pushIntervalMs;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Writes audio data to the silence filler.
|
|
56
|
+
*
|
|
57
|
+
* @param audioBuffer - The audio buffer to write.
|
|
58
|
+
*/
|
|
59
|
+
writeAudio(audioBuffer) {
|
|
60
|
+
const now = Date.now();
|
|
61
|
+
try {
|
|
62
|
+
this.unclockedSilenceFiller.writeAudio(audioBuffer, now);
|
|
63
|
+
if (!this.isStarted && this.unclockedSilenceFiller.donePrebuffering) {
|
|
64
|
+
this.isStarted = true;
|
|
65
|
+
this.startPushInterval();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
console.error(`[SilenceFiller] Error writing audio:`, error);
|
|
70
|
+
this.emit("error", error);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
startPushInterval() {
|
|
74
|
+
this.pushInterval = setInterval(() => {
|
|
75
|
+
this.pushData();
|
|
76
|
+
}, this.pushIntervalMs);
|
|
77
|
+
}
|
|
78
|
+
pushData() {
|
|
79
|
+
if (!this.isStarted)
|
|
80
|
+
return;
|
|
81
|
+
try {
|
|
82
|
+
const now = Date.now();
|
|
83
|
+
const audioChunk = this.unclockedSilenceFiller.readAudio(now);
|
|
84
|
+
if (audioChunk && audioChunk.length > 0) {
|
|
85
|
+
// Ensure chunk size is aligned to bytesPerSample
|
|
86
|
+
const alignedChunkSize = Math.floor(audioChunk.length / this.bytesPerSample) * this.bytesPerSample;
|
|
87
|
+
if (alignedChunkSize > 0) {
|
|
88
|
+
const chunk = audioChunk.subarray(0, alignedChunkSize);
|
|
89
|
+
this.push(chunk);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
console.error(`[SilenceFiller] Error pushing data:`, error);
|
|
95
|
+
this.emit("error", error);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
_read() { }
|
|
99
|
+
_destroy(error, callback) {
|
|
100
|
+
super._destroy(error, callback);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Ends the stream and drains all remaining audio data.
|
|
104
|
+
*
|
|
105
|
+
* @returns A promise that resolves when the stream has ended.
|
|
106
|
+
*/
|
|
107
|
+
endStream() {
|
|
108
|
+
return new Promise((resolve) => {
|
|
109
|
+
// Stop pushing data
|
|
110
|
+
if (this.pushInterval) {
|
|
111
|
+
clearInterval(this.pushInterval);
|
|
112
|
+
this.pushInterval = null;
|
|
113
|
+
}
|
|
114
|
+
// Drain all remaining audio from SilenceFiller
|
|
115
|
+
const now = Date.now();
|
|
116
|
+
// Keep reading until no more audio is available
|
|
117
|
+
while (true) {
|
|
118
|
+
const remainingChunk = this.unclockedSilenceFiller.readAudio(now);
|
|
119
|
+
if (!remainingChunk || remainingChunk.length === 0) {
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
const alignedChunkSize = Math.floor(remainingChunk.length / this.bytesPerSample) * this.bytesPerSample;
|
|
123
|
+
if (alignedChunkSize > 0) {
|
|
124
|
+
const chunk = remainingChunk.subarray(0, alignedChunkSize);
|
|
125
|
+
this.push(chunk);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
this.push(null); // Signal end of stream
|
|
129
|
+
this.once("end", () => {
|
|
130
|
+
resolve();
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
exports.SilenceFiller = SilenceFiller;
|
|
136
|
+
/**
|
|
137
|
+
* Does the actual calculation of how interspersing audio with silence
|
|
138
|
+
* is "pure" in the sense that it does not rely on the system clock.
|
|
139
|
+
* It's up to the caller to provide timestamps.
|
|
140
|
+
*
|
|
141
|
+
* @internal
|
|
142
|
+
*/
|
|
143
|
+
class UnclockedSilenceFiller {
|
|
144
|
+
constructor(bufferSize, sampleRate, bytesPerSample) {
|
|
145
|
+
this.audioQueue = [];
|
|
146
|
+
this.totalBufferedBytes = 0;
|
|
147
|
+
this.startTimestamp = null;
|
|
148
|
+
this.totalBytesSent = 0;
|
|
149
|
+
this.donePrebuffering = false;
|
|
150
|
+
this.bufferSize = bufferSize;
|
|
151
|
+
this.sampleRate = sampleRate;
|
|
152
|
+
this.bytesPerSample = bytesPerSample;
|
|
153
|
+
}
|
|
154
|
+
writeAudio(audioBuffer, timestamp) {
|
|
155
|
+
this.audioQueue.push(audioBuffer);
|
|
156
|
+
this.totalBufferedBytes += audioBuffer.length;
|
|
157
|
+
if (this.startTimestamp === null) {
|
|
158
|
+
this.startTimestamp = timestamp;
|
|
159
|
+
}
|
|
160
|
+
if (!this.donePrebuffering && this.totalBufferedBytes >= this.bufferSize) {
|
|
161
|
+
this.donePrebuffering = true;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
readAudio(timestamp) {
|
|
165
|
+
if (this.startTimestamp === null || !this.donePrebuffering) {
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
const elapsedMs = timestamp - this.startTimestamp;
|
|
169
|
+
const targetBytesSent = Math.floor(((this.sampleRate * elapsedMs) / 1000) * this.bytesPerSample);
|
|
170
|
+
const bytesNeeded = targetBytesSent - this.totalBytesSent;
|
|
171
|
+
if (bytesNeeded <= 0) {
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
// Ensure bytesNeeded is a multiple of bytesPerSample
|
|
175
|
+
const alignedBytesNeeded = Math.floor(bytesNeeded / this.bytesPerSample) * this.bytesPerSample;
|
|
176
|
+
if (alignedBytesNeeded <= 0) {
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
let chunk = Buffer.alloc(0);
|
|
180
|
+
// Drain from queue until we have enough bytes
|
|
181
|
+
while (chunk.length < alignedBytesNeeded && this.audioQueue.length > 0) {
|
|
182
|
+
const nextBuffer = this.audioQueue.shift();
|
|
183
|
+
chunk = Buffer.concat([chunk, nextBuffer]);
|
|
184
|
+
this.totalBufferedBytes -= nextBuffer.length;
|
|
185
|
+
}
|
|
186
|
+
// If we have more than needed, put the excess back
|
|
187
|
+
if (chunk.length > alignedBytesNeeded) {
|
|
188
|
+
const excess = chunk.subarray(alignedBytesNeeded);
|
|
189
|
+
this.audioQueue.unshift(excess);
|
|
190
|
+
this.totalBufferedBytes += excess.length;
|
|
191
|
+
chunk = chunk.subarray(0, alignedBytesNeeded);
|
|
192
|
+
}
|
|
193
|
+
// Fill remaining with silence if needed
|
|
194
|
+
if (chunk.length < alignedBytesNeeded) {
|
|
195
|
+
const silenceNeeded = Buffer.alloc(alignedBytesNeeded - chunk.length, 0);
|
|
196
|
+
chunk = Buffer.concat([chunk, silenceNeeded]);
|
|
197
|
+
}
|
|
198
|
+
// Update total bytes sent
|
|
199
|
+
this.totalBytesSent += chunk.length;
|
|
200
|
+
return chunk;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
exports.UnclockedSilenceFiller = UnclockedSilenceFiller;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Takes an async iterator that yields interleaved items from different groups
|
|
3
|
+
* and produces an iterator that yields items in group order.
|
|
4
|
+
*
|
|
5
|
+
* Example:
|
|
6
|
+
* Input: A1, B1, A2, A3 (final), C1, C2, C3 (final), B2 (final)
|
|
7
|
+
* Output: A1, A2, A3, B1, B2, C1, C2, C3
|
|
8
|
+
*
|
|
9
|
+
* This is useful when using synthesizeJsonStreaming with num_generations > 1
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
*
|
|
14
|
+
* import { collate } from 'hume';
|
|
15
|
+
*
|
|
16
|
+
* const stream = hume.synthesizeJsonStreaming({
|
|
17
|
+
* ...
|
|
18
|
+
* })
|
|
19
|
+
*
|
|
20
|
+
* const contiguous = collate(
|
|
21
|
+
* stream
|
|
22
|
+
* (chunk) => chunk.generationId,
|
|
23
|
+
* (chunk) => chunk.isLastChunk
|
|
24
|
+
* );
|
|
25
|
+
*
|
|
26
|
+
* for await (const item of contiguous) {
|
|
27
|
+
* audioPlayer.write(item.audio)
|
|
28
|
+
* }
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* @param source - Async iterable that yields interleaved items.
|
|
32
|
+
* @param groupBy - Function to determine a "key" that determines the group identity for each item.
|
|
33
|
+
* @param isFinal - Function to determine if an item is the final item in its group.
|
|
34
|
+
* @returns An async iterable that yields items in group order.
|
|
35
|
+
*/
|
|
36
|
+
export declare function collate<TItem, TKey>(source: AsyncIterable<TItem>, groupBy: (x: TItem) => TKey, isFinal: (x: TItem) => boolean): AsyncIterable<TItem>;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __asyncValues = (this && this.__asyncValues) || function (o) {
|
|
3
|
+
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
4
|
+
var m = o[Symbol.asyncIterator], i;
|
|
5
|
+
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
|
|
6
|
+
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
|
|
7
|
+
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
|
8
|
+
};
|
|
9
|
+
var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }
|
|
10
|
+
var __asyncDelegator = (this && this.__asyncDelegator) || function (o) {
|
|
11
|
+
var i, p;
|
|
12
|
+
return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i;
|
|
13
|
+
function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: false } : f ? f(v) : v; } : f; }
|
|
14
|
+
};
|
|
15
|
+
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
|
|
16
|
+
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
17
|
+
var g = generator.apply(thisArg, _arguments || []), i, q = [];
|
|
18
|
+
return i = Object.create((typeof AsyncIterator === "function" ? AsyncIterator : Object).prototype), verb("next"), verb("throw"), verb("return", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i;
|
|
19
|
+
function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; }
|
|
20
|
+
function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } }
|
|
21
|
+
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
|
|
22
|
+
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
|
|
23
|
+
function fulfill(value) { resume("next", value); }
|
|
24
|
+
function reject(value) { resume("throw", value); }
|
|
25
|
+
function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
|
|
26
|
+
};
|
|
27
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
28
|
+
exports.collate = collate;
|
|
29
|
+
/**
|
|
30
|
+
* Takes an async iterator that yields interleaved items from different groups
|
|
31
|
+
* and produces an iterator that yields items in group order.
|
|
32
|
+
*
|
|
33
|
+
* Example:
|
|
34
|
+
* Input: A1, B1, A2, A3 (final), C1, C2, C3 (final), B2 (final)
|
|
35
|
+
* Output: A1, A2, A3, B1, B2, C1, C2, C3
|
|
36
|
+
*
|
|
37
|
+
* This is useful when using synthesizeJsonStreaming with num_generations > 1
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```typescript
|
|
41
|
+
*
|
|
42
|
+
* import { collate } from 'hume';
|
|
43
|
+
*
|
|
44
|
+
* const stream = hume.synthesizeJsonStreaming({
|
|
45
|
+
* ...
|
|
46
|
+
* })
|
|
47
|
+
*
|
|
48
|
+
* const contiguous = collate(
|
|
49
|
+
* stream
|
|
50
|
+
* (chunk) => chunk.generationId,
|
|
51
|
+
* (chunk) => chunk.isLastChunk
|
|
52
|
+
* );
|
|
53
|
+
*
|
|
54
|
+
* for await (const item of contiguous) {
|
|
55
|
+
* audioPlayer.write(item.audio)
|
|
56
|
+
* }
|
|
57
|
+
* ```
|
|
58
|
+
*
|
|
59
|
+
* @param source - Async iterable that yields interleaved items.
|
|
60
|
+
* @param groupBy - Function to determine a "key" that determines the group identity for each item.
|
|
61
|
+
* @param isFinal - Function to determine if an item is the final item in its group.
|
|
62
|
+
* @returns An async iterable that yields items in group order.
|
|
63
|
+
*/
|
|
64
|
+
function collate(source, groupBy, isFinal) {
|
|
65
|
+
return __asyncGenerator(this, arguments, function* collate_1() {
|
|
66
|
+
var _a, e_1, _b, _c;
|
|
67
|
+
const buffers = new Map();
|
|
68
|
+
const order = [];
|
|
69
|
+
let current;
|
|
70
|
+
const ensure = (k) => {
|
|
71
|
+
if (!buffers.has(k)) {
|
|
72
|
+
buffers.set(k, []);
|
|
73
|
+
order.push(k);
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
const flushGroup = function* (k) {
|
|
77
|
+
const buf = buffers.get(k);
|
|
78
|
+
if (!buf)
|
|
79
|
+
return;
|
|
80
|
+
for (const item of buf)
|
|
81
|
+
yield item;
|
|
82
|
+
buffers.delete(k);
|
|
83
|
+
};
|
|
84
|
+
const nextGroup = () => {
|
|
85
|
+
// pop the next group in first-seen order that still has a buffer
|
|
86
|
+
while (order.length && !buffers.has(order[0]))
|
|
87
|
+
order.shift();
|
|
88
|
+
return order.shift();
|
|
89
|
+
};
|
|
90
|
+
try {
|
|
91
|
+
for (var _d = true, source_1 = __asyncValues(source), source_1_1; source_1_1 = yield __await(source_1.next()), _a = source_1_1.done, !_a; _d = true) {
|
|
92
|
+
_c = source_1_1.value;
|
|
93
|
+
_d = false;
|
|
94
|
+
const item = _c;
|
|
95
|
+
const k = groupBy(item);
|
|
96
|
+
if (current === undefined)
|
|
97
|
+
current = k;
|
|
98
|
+
ensure(k);
|
|
99
|
+
buffers.get(k).push(item);
|
|
100
|
+
// if we just saw the final item for the current group, flush it and advance
|
|
101
|
+
if (k === current && isFinal(item)) {
|
|
102
|
+
yield __await(yield* __asyncDelegator(__asyncValues(flushGroup(current))));
|
|
103
|
+
current = nextGroup();
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
108
|
+
finally {
|
|
109
|
+
try {
|
|
110
|
+
if (!_d && !_a && (_b = source_1.return)) yield __await(_b.call(source_1));
|
|
111
|
+
}
|
|
112
|
+
finally { if (e_1) throw e_1.error; }
|
|
113
|
+
}
|
|
114
|
+
// stream ended; flush remaining groups in first-seen order
|
|
115
|
+
if (current !== undefined) {
|
|
116
|
+
if (buffers.has(current))
|
|
117
|
+
yield __await(yield* __asyncDelegator(__asyncValues(flushGroup(current))));
|
|
118
|
+
while (true) {
|
|
119
|
+
const k = nextGroup();
|
|
120
|
+
if (k === undefined)
|
|
121
|
+
break;
|
|
122
|
+
yield __await(yield* __asyncDelegator(__asyncValues(flushGroup(k))));
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
}
|
package/dist/wrapper/index.d.ts
CHANGED
|
@@ -9,3 +9,5 @@ export { getAudioStream } from "./getAudioStream";
|
|
|
9
9
|
export { MimeType, getBrowserSupportedMimeType } from "./getBrowserSupportedMimeType";
|
|
10
10
|
export { HumeClient } from "./HumeClient";
|
|
11
11
|
export { EVIWebAudioPlayer, EVIWebAudioPlayerFFTOptions, EVIWebAudioPlayerOptions } from "./EVIWebAudioPlayer";
|
|
12
|
+
export { collate } from "./collate";
|
|
13
|
+
export { SilenceFiller } from "./SilenceFiller";
|
package/dist/wrapper/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.EVIWebAudioPlayer = exports.HumeClient = exports.getBrowserSupportedMimeType = exports.MimeType = exports.getAudioStream = exports.fetchAccessToken = exports.checkForAudioTracks = exports.ensureSingleValidAudioTrack = exports.convertBlobToBase64 = exports.convertBase64ToBlob = exports.base64Encode = exports.base64Decode = void 0;
|
|
3
|
+
exports.SilenceFiller = exports.collate = exports.EVIWebAudioPlayer = exports.HumeClient = exports.getBrowserSupportedMimeType = exports.MimeType = exports.getAudioStream = exports.fetchAccessToken = exports.checkForAudioTracks = exports.ensureSingleValidAudioTrack = exports.convertBlobToBase64 = exports.convertBase64ToBlob = exports.base64Encode = exports.base64Decode = void 0;
|
|
4
4
|
var base64Decode_1 = require("./base64Decode");
|
|
5
5
|
Object.defineProperty(exports, "base64Decode", { enumerable: true, get: function () { return base64Decode_1.base64Decode; } });
|
|
6
6
|
var base64Encode_1 = require("./base64Encode");
|
|
@@ -24,3 +24,7 @@ var HumeClient_1 = require("./HumeClient");
|
|
|
24
24
|
Object.defineProperty(exports, "HumeClient", { enumerable: true, get: function () { return HumeClient_1.HumeClient; } });
|
|
25
25
|
var EVIWebAudioPlayer_1 = require("./EVIWebAudioPlayer");
|
|
26
26
|
Object.defineProperty(exports, "EVIWebAudioPlayer", { enumerable: true, get: function () { return EVIWebAudioPlayer_1.EVIWebAudioPlayer; } });
|
|
27
|
+
var collate_1 = require("./collate");
|
|
28
|
+
Object.defineProperty(exports, "collate", { enumerable: true, get: function () { return collate_1.collate; } });
|
|
29
|
+
var SilenceFiller_1 = require("./SilenceFiller");
|
|
30
|
+
Object.defineProperty(exports, "SilenceFiller", { enumerable: true, get: function () { return SilenceFiller_1.SilenceFiller; } });
|
package/package.json
CHANGED
|
@@ -54,4 +54,5 @@ exports.SessionSettings = core.serialization.object({
|
|
|
54
54
|
builtinTools: core.serialization.property("builtin_tools", core.serialization.list(BuiltinToolConfig_1.BuiltinToolConfig).optional()),
|
|
55
55
|
metadata: core.serialization.record(core.serialization.string(), core.serialization.unknown()).optional(),
|
|
56
56
|
variables: core.serialization.record(core.serialization.string(), SessionSettingsVariablesValue_1.SessionSettingsVariablesValue).optional(),
|
|
57
|
+
voiceId: core.serialization.property("voice_id", core.serialization.string().optional()),
|
|
57
58
|
});
|
|
@@ -9,6 +9,7 @@ import { Snippet } from "./Snippet";
|
|
|
9
9
|
export declare const SnippetAudioChunk: core.serialization.ObjectSchema<serializers.tts.SnippetAudioChunk.Raw, Hume.tts.SnippetAudioChunk>;
|
|
10
10
|
export declare namespace SnippetAudioChunk {
|
|
11
11
|
interface Raw {
|
|
12
|
+
request_id: string;
|
|
12
13
|
generation_id: string;
|
|
13
14
|
snippet_id: string;
|
|
14
15
|
text: string;
|
|
@@ -41,6 +41,7 @@ const core = __importStar(require("../../../../core"));
|
|
|
41
41
|
const AudioFormatType_1 = require("./AudioFormatType");
|
|
42
42
|
const Snippet_1 = require("./Snippet");
|
|
43
43
|
exports.SnippetAudioChunk = core.serialization.object({
|
|
44
|
+
requestId: core.serialization.property("request_id", core.serialization.string()),
|
|
44
45
|
generationId: core.serialization.property("generation_id", core.serialization.string()),
|
|
45
46
|
snippetId: core.serialization.property("snippet_id", core.serialization.string()),
|
|
46
47
|
text: core.serialization.string(),
|
package/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const SDK_VERSION = "0.13.
|
|
1
|
+
export declare const SDK_VERSION = "0.13.5";
|
package/version.js
CHANGED