@unboundcx/sdk 4.13.97 → 4.13.98

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unboundcx/sdk",
3
- "version": "4.13.97",
3
+ "version": "4.13.98",
4
4
  "description": "Official JavaScript SDK for the Unbound API - A comprehensive toolkit for integrating with Unbound's communication, AI, and data management services",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -0,0 +1,155 @@
1
+ import { internalRequest } from '../../base.js';
2
+
3
+ /**
4
+ * Text-to-speech. `sdk.ai.tts.*`.
5
+ *
6
+ * @see app1-api src/services/ai/routes/tts.js
7
+ */
8
+ export class TextToSpeechService {
9
+ constructor(sdk) {
10
+ this.sdk = sdk;
11
+ }
12
+
13
+ /**
14
+ * Render text to speech and get back a storage id/url (buffered — waits
15
+ * for the whole file). For low-latency playback (e.g. a voice bot) use
16
+ * `stream()` instead.
17
+ * @param {Object} params
18
+ * @param {string} params.text
19
+ * @param {string} [params.voice]
20
+ * @param {string} [params.languageCode]
21
+ * @param {string} [params.ssmlGender]
22
+ * @param {string} [params.audioEncoding]
23
+ * @param {number} [params.speakingRate]
24
+ * @param {number} [params.pitch]
25
+ * @param {number} [params.volumeGainDb]
26
+ * @param {string[]} [params.effectsProfileIds]
27
+ * @param {boolean} [params.createAccessKey]
28
+ * @returns {Promise<Object>} `{ id, storageId, url? }`
29
+ */
30
+ async create({
31
+ text,
32
+ voice,
33
+ languageCode,
34
+ ssmlGender,
35
+ audioEncoding,
36
+ speakingRate,
37
+ pitch,
38
+ volumeGainDb,
39
+ effectsProfileIds,
40
+ createAccessKey,
41
+ }) {
42
+ this.sdk.validateParams(
43
+ {
44
+ text,
45
+ voice,
46
+ languageCode,
47
+ ssmlGender,
48
+ audioEncoding,
49
+ speakingRate,
50
+ pitch,
51
+ volumeGainDb,
52
+ effectsProfileIds,
53
+ createAccessKey,
54
+ },
55
+ {
56
+ text: { type: 'string', required: true },
57
+ voice: { type: 'string', required: false },
58
+ languageCode: { type: 'string', required: false },
59
+ ssmlGender: { type: 'string', required: false },
60
+ audioEncoding: { type: 'string', required: false },
61
+ speakingRate: { type: 'number', required: false },
62
+ pitch: { type: 'number', required: false },
63
+ volumeGainDb: { type: 'number', required: false },
64
+ effectsProfileIds: { type: 'array', required: false },
65
+ createAccessKey: { type: 'boolean', required: false },
66
+ },
67
+ );
68
+
69
+ const ttsData = { text };
70
+ if (voice) ttsData.voice = voice;
71
+ if (languageCode) ttsData.languageCode = languageCode;
72
+ if (ssmlGender) ttsData.ssmlGender = ssmlGender;
73
+ if (audioEncoding) ttsData.audioEncoding = audioEncoding;
74
+ if (speakingRate) ttsData.speakingRate = speakingRate;
75
+ if (pitch) ttsData.pitch = pitch;
76
+ if (volumeGainDb) ttsData.volumeGainDb = volumeGainDb;
77
+ if (effectsProfileIds) ttsData.effectsProfileIds = effectsProfileIds;
78
+ if (createAccessKey) ttsData.createAccessKey = createAccessKey;
79
+
80
+ const params = {
81
+ body: ttsData,
82
+ };
83
+
84
+ const result = await internalRequest(this.sdk, '/ai/tts', 'POST', params);
85
+ return result;
86
+ }
87
+
88
+ /**
89
+ * List available TTS voices
90
+ * @returns {Promise<Object>} { voices: Array, count: number, supportedEncodings: Array, supportedLanguages: Array }
91
+ */
92
+ async list() {
93
+ const result = await internalRequest(this.sdk, '/ai/tts', 'GET');
94
+ return result;
95
+ }
96
+
97
+ /**
98
+ * Stream TTS audio as it's generated — first bytes can arrive well before
99
+ * the whole utterance finishes rendering (Groq voices: TTFB ~0.2s).
100
+ * Always renders wav; shares its cache with `create()` when
101
+ * audioEncoding:'wav' is used there.
102
+ *
103
+ * Node: wrap the result in `Readable.fromWeb(result.body)` to get a
104
+ * normal Node stream (e.g. to pipe into ffmpeg). Browser: `result.body`
105
+ * is already a web ReadableStream you can read directly or hand to
106
+ * `new Response(result.body)` / a `<audio>` element via a Blob.
107
+ *
108
+ * Response headers of note: `x-tts-cache` (`hit`|`miss`) and `x-tts-id`
109
+ * (set on a cache hit, when the id is already known).
110
+ *
111
+ * @param {Object} params
112
+ * @param {string} params.text
113
+ * @param {string} [params.voice]
114
+ * @param {string} [params.languageCode]
115
+ * @returns {Promise<{body: ReadableStream, headers: Headers, status: number}>}
116
+ * @example
117
+ * const result = await sdk.ai.tts.stream({ text: 'Hi there', voice: 'hannah' });
118
+ * const nodeStream = Readable.fromWeb(result.body);
119
+ * nodeStream.pipe(ffmpegProcess.stdin);
120
+ */
121
+ async stream({ text, voice, languageCode }) {
122
+ this.sdk.validateParams(
123
+ { text, voice, languageCode },
124
+ {
125
+ text: { type: 'string', required: true },
126
+ voice: { type: 'string', required: false },
127
+ languageCode: { type: 'string', required: false },
128
+ },
129
+ );
130
+
131
+ const ttsData = { text };
132
+ if (voice) ttsData.voice = voice;
133
+ if (languageCode) ttsData.languageCode = languageCode;
134
+
135
+ const params = {
136
+ body: ttsData,
137
+ returnRawResponse: true,
138
+ };
139
+
140
+ // forceFetch: true — NATS transport can't carry a streamed body.
141
+ const response = await internalRequest(
142
+ this.sdk,
143
+ '/ai/tts/stream',
144
+ 'POST',
145
+ params,
146
+ true,
147
+ );
148
+
149
+ return {
150
+ body: response.body,
151
+ headers: response.headers,
152
+ status: response.status,
153
+ };
154
+ }
155
+ }
package/services/ai.js CHANGED
@@ -5,6 +5,7 @@ import { AssistService } from './ai/assist.js';
5
5
  import { VocabularyService } from './ai/vocabulary.js';
6
6
  import { EmailService } from './ai/email.js';
7
7
  import { ModelsService } from './ai/models.js';
8
+ import { TextToSpeechService } from './ai/tts.js';
8
9
  import { translate as translateItems } from './ai/translate.js';
9
10
  import {
10
11
  getSettings as getAiSettings,
@@ -487,79 +488,6 @@ export class GenerativeService {
487
488
  // }
488
489
  }
489
490
 
490
- export class TextToSpeechService {
491
- constructor(sdk) {
492
- this.sdk = sdk;
493
- }
494
-
495
- async create({
496
- text,
497
- voice,
498
- languageCode,
499
- ssmlGender,
500
- audioEncoding,
501
- speakingRate,
502
- pitch,
503
- volumeGainDb,
504
- effectsProfileIds,
505
- createAccessKey,
506
- }) {
507
- this.sdk.validateParams(
508
- {
509
- text,
510
- voice,
511
- languageCode,
512
- ssmlGender,
513
- audioEncoding,
514
- speakingRate,
515
- pitch,
516
- volumeGainDb,
517
- effectsProfileIds,
518
- createAccessKey,
519
- },
520
- {
521
- text: { type: 'string', required: true },
522
- voice: { type: 'string', required: false },
523
- languageCode: { type: 'string', required: false },
524
- ssmlGender: { type: 'string', required: false },
525
- audioEncoding: { type: 'string', required: false },
526
- speakingRate: { type: 'number', required: false },
527
- pitch: { type: 'number', required: false },
528
- volumeGainDb: { type: 'number', required: false },
529
- effectsProfileIds: { type: 'array', required: false },
530
- createAccessKey: { type: 'boolean', required: false },
531
- },
532
- );
533
-
534
- const ttsData = { text };
535
- if (voice) ttsData.voice = voice;
536
- if (languageCode) ttsData.languageCode = languageCode;
537
- if (ssmlGender) ttsData.ssmlGender = ssmlGender;
538
- if (audioEncoding) ttsData.audioEncoding = audioEncoding;
539
- if (speakingRate) ttsData.speakingRate = speakingRate;
540
- if (pitch) ttsData.pitch = pitch;
541
- if (volumeGainDb) ttsData.volumeGainDb = volumeGainDb;
542
- if (effectsProfileIds) ttsData.effectsProfileIds = effectsProfileIds;
543
- if (createAccessKey) ttsData.createAccessKey = createAccessKey;
544
-
545
- const params = {
546
- body: ttsData,
547
- };
548
-
549
- const result = await internalRequest(this.sdk, '/ai/tts', 'POST', params);
550
- return result;
551
- }
552
-
553
- /**
554
- * List available TTS voices
555
- * @returns {Promise<Object>} { voices: Array, count: number, supportedEncodings: Array, supportedLanguages: Array }
556
- */
557
- async list() {
558
- const result = await internalRequest(this.sdk, '/ai/tts', 'GET');
559
- return result;
560
- }
561
- }
562
-
563
491
  export class SpeechToTextService {
564
492
  constructor(sdk) {
565
493
  this.sdk = sdk;