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.
Files changed (46) hide show
  1. package/api/resources/empathicVoice/types/SessionSettings.d.ts +2 -0
  2. package/api/resources/tts/types/SnippetAudioChunk.d.ts +5 -0
  3. package/dist/api/resources/empathicVoice/types/SessionSettings.d.ts +2 -0
  4. package/dist/api/resources/tts/types/SnippetAudioChunk.d.ts +5 -0
  5. package/dist/serialization/resources/empathicVoice/types/SessionSettings.d.ts +1 -0
  6. package/dist/serialization/resources/empathicVoice/types/SessionSettings.js +1 -0
  7. package/dist/serialization/resources/tts/types/SnippetAudioChunk.d.ts +1 -0
  8. package/dist/serialization/resources/tts/types/SnippetAudioChunk.js +1 -0
  9. package/dist/version.d.ts +1 -1
  10. package/dist/version.js +1 -1
  11. package/dist/wrapper/SilenceFiller.d.ts +85 -0
  12. package/dist/wrapper/SilenceFiller.js +203 -0
  13. package/dist/wrapper/collate.d.ts +36 -0
  14. package/dist/wrapper/collate.js +126 -0
  15. package/dist/wrapper/index.d.ts +2 -0
  16. package/dist/wrapper/index.js +5 -1
  17. package/package.json +1 -1
  18. package/serialization/resources/empathicVoice/types/SessionSettings.d.ts +1 -0
  19. package/serialization/resources/empathicVoice/types/SessionSettings.js +1 -0
  20. package/serialization/resources/tts/types/SnippetAudioChunk.d.ts +1 -0
  21. package/serialization/resources/tts/types/SnippetAudioChunk.js +1 -0
  22. package/version.d.ts +1 -1
  23. package/version.js +1 -1
  24. package/wrapper/SilenceFiller.d.ts +85 -0
  25. package/wrapper/SilenceFiller.js +203 -0
  26. package/wrapper/collate.d.ts +36 -0
  27. package/wrapper/collate.js +126 -0
  28. package/wrapper/index.d.ts +2 -0
  29. package/wrapper/index.js +5 -1
  30. package/.mock/definition/api.yml +0 -12
  31. package/.mock/definition/empathic-voice/__package__.yml +0 -2971
  32. package/.mock/definition/empathic-voice/chat.yml +0 -175
  33. package/.mock/definition/empathic-voice/chatGroups.yml +0 -627
  34. package/.mock/definition/empathic-voice/chatWebhooks.yml +0 -30
  35. package/.mock/definition/empathic-voice/chats.yml +0 -506
  36. package/.mock/definition/empathic-voice/configs.yml +0 -842
  37. package/.mock/definition/empathic-voice/prompts.yml +0 -558
  38. package/.mock/definition/empathic-voice/tools.yml +0 -626
  39. package/.mock/definition/expression-measurement/__package__.yml +0 -1
  40. package/.mock/definition/expression-measurement/batch/__package__.yml +0 -1803
  41. package/.mock/definition/expression-measurement/stream/__package__.yml +0 -113
  42. package/.mock/definition/expression-measurement/stream/stream.yml +0 -438
  43. package/.mock/definition/tts/__package__.yml +0 -709
  44. package/.mock/definition/tts/streamInput.yml +0 -56
  45. package/.mock/definition/tts/voices.yml +0 -143
  46. 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. */
@@ -22,5 +22,6 @@ export declare namespace SessionSettings {
22
22
  builtin_tools?: BuiltinToolConfig.Raw[] | null;
23
23
  metadata?: Record<string, unknown> | null;
24
24
  variables?: Record<string, SessionSettingsVariablesValue.Raw> | null;
25
+ voice_id?: string | null;
25
26
  }
26
27
  }
@@ -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.4";
1
+ export declare const SDK_VERSION = "0.13.5";
package/dist/version.js CHANGED
@@ -1,4 +1,4 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SDK_VERSION = void 0;
4
- exports.SDK_VERSION = "0.13.4";
4
+ exports.SDK_VERSION = "0.13.5";
@@ -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
+ }
@@ -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";
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hume",
3
- "version": "0.13.4",
3
+ "version": "0.13.5",
4
4
  "private": false,
5
5
  "repository": "https://github.com/HumeAI/hume-typescript-sdk",
6
6
  "main": "./index.js",
@@ -22,5 +22,6 @@ export declare namespace SessionSettings {
22
22
  builtin_tools?: BuiltinToolConfig.Raw[] | null;
23
23
  metadata?: Record<string, unknown> | null;
24
24
  variables?: Record<string, SessionSettingsVariablesValue.Raw> | null;
25
+ voice_id?: string | null;
25
26
  }
26
27
  }
@@ -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.4";
1
+ export declare const SDK_VERSION = "0.13.5";
package/version.js CHANGED
@@ -1,4 +1,4 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SDK_VERSION = void 0;
4
- exports.SDK_VERSION = "0.13.4";
4
+ exports.SDK_VERSION = "0.13.5";