@ssml-builder-js/azure-tts-client 2.4.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/CHANGELOG.md ADDED
@@ -0,0 +1,57 @@
1
+ # @ssml-builder-js/azure-tts-client
2
+
3
+ ## 2.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Add SSML text-node translation helpers and Azure semantic validation, improve Azure TTS endpoint and logger handling, support React 18 peer dependencies, and complete independent package publishing metadata.
8
+
9
+ ## 2.3.0
10
+
11
+ ## 2.2.0
12
+
13
+ ### Minor Changes
14
+
15
+ - e124614: ---
16
+
17
+ "@ssml-builder-js/ssml-editor-elements": minor
18
+ "@ssml-builder-js/ssml-editor-react": minor
19
+ "@ssml-builder-js/ssml-core": minor
20
+ "@ssml-builder-js/azure-tts-client": minor
21
+ "playground": minor
22
+
23
+ ***
24
+
25
+ - **Web Components サポート (`@ssml-builder-js/ssml-editor-elements`) の追加**
26
+ - フレームワーク非依存で利用可能な `<ssml-editor>` カスタム要素(Custom Element)パッケージを新設。
27
+ - ルートパッケージからのエクスポート(`ssml-builder-js/elements`)および Playground での React / Web Components 切り替え動作環境を整備。
28
+ - **多言語音声モデル(Voice)ごとの感情スタイル動的フィルタリングの拡充**
29
+ - 日本語(`ja-JP`)、英語(`en-US`)、中国語(`zh-CN`)、韓国語、欧州言語等の Neural 音声モデルに対応する発話スタイル一覧を公式仕様に合わせて網羅。
30
+ - 感情非対応の音声モデルに対する disabled 表示・フォールバック処理を実装。
31
+ - **スタイル選択 UI の `<optgroup>` カテゴリ分類**
32
+ - `ProsodyPopovers` 内のスタイル選択肢を「感情・トーン(Emotions)」「会話・シナリオ(Scenarios)」「メディア・報道(Media)」にグループ化し、視認性と操作性を向上。
33
+ - **ツールバーのアクティブタグ状態表示 (Active State Feedback)**
34
+
35
+ - エディタ内のカーソル位置(キャレット)を囲む SSML タグをリアルタイムに検知し、対応するツールバーボタン(Prosody, Style 等)をハイライト表示する機能を追加。
36
+
37
+ - モノレポ各パッケージのビルド設定(tsup)および型定義エクスポート(dts)を最適化。
38
+
39
+ ## 2.1.0
40
+
41
+ ### Patch Changes
42
+
43
+ - 845a6d3: - **`<mstts:express-as>` のスタイル動的フィルタリング:** 親要素の `<voice name="...">` に応じて利用可能な感情スタイル(`style`)のみを自動補完・Popover 選択肢へ動的に絞り込む機能を追加。
44
+ - **Quick Fix (CodeAction) の拡張:** 未閉じタグの自動補完挿入および無効な属性値の 1 クリック修正に対応。
45
+ - **自動補完およびエディタ内部設計の最適化:** 入力時の Range 置換精度の改善および Popover コンポーネント・状態管理のモジュール分離を実施。
46
+
47
+ ## 2.0.0
48
+
49
+ ### Major Changes
50
+
51
+ - 4935073: ---
52
+
53
+ ## 1.0.0
54
+
55
+ ### Major Changes
56
+
57
+ - 6c78e70: chore: initial release
@@ -0,0 +1,41 @@
1
+ interface TtsConfig {
2
+ endpoint?: string;
3
+ subscriptionKey: string;
4
+ region: string;
5
+ outputFormat?: string;
6
+ }
7
+ interface AzureTtsLogger {
8
+ debug?: (...args: unknown[]) => void;
9
+ info?: (...args: unknown[]) => void;
10
+ warn?: (...args: unknown[]) => void;
11
+ error?: (...args: unknown[]) => void;
12
+ }
13
+ interface AzureTtsClientOptions {
14
+ subscriptionKey: string;
15
+ region: string;
16
+ endpoint?: string;
17
+ outputFormat?: string;
18
+ logger?: AzureTtsLogger;
19
+ }
20
+
21
+ declare class AzureTtsError extends Error {
22
+ readonly status: number;
23
+ readonly statusText: string;
24
+ readonly responseBody: string;
25
+ readonly requestId: string | null;
26
+ constructor(status: number, statusText: string, responseBody: string, requestId: string | null);
27
+ }
28
+ declare class AzureTtsSdkError extends AzureTtsError {
29
+ readonly errorDetails: string;
30
+ constructor(errorDetails: string);
31
+ }
32
+
33
+ declare class AzureTtsClient {
34
+ #private;
35
+ constructor(options: AzureTtsClientOptions);
36
+ synthesize(ssml: string): Promise<ArrayBuffer>;
37
+ }
38
+
39
+ declare function synthesizeSpeech(ssml: string, config: TtsConfig): Promise<ArrayBuffer>;
40
+
41
+ export { AzureTtsClient, type AzureTtsClientOptions, AzureTtsError, type AzureTtsLogger, AzureTtsSdkError, type TtsConfig, synthesizeSpeech };
@@ -0,0 +1,41 @@
1
+ interface TtsConfig {
2
+ endpoint?: string;
3
+ subscriptionKey: string;
4
+ region: string;
5
+ outputFormat?: string;
6
+ }
7
+ interface AzureTtsLogger {
8
+ debug?: (...args: unknown[]) => void;
9
+ info?: (...args: unknown[]) => void;
10
+ warn?: (...args: unknown[]) => void;
11
+ error?: (...args: unknown[]) => void;
12
+ }
13
+ interface AzureTtsClientOptions {
14
+ subscriptionKey: string;
15
+ region: string;
16
+ endpoint?: string;
17
+ outputFormat?: string;
18
+ logger?: AzureTtsLogger;
19
+ }
20
+
21
+ declare class AzureTtsError extends Error {
22
+ readonly status: number;
23
+ readonly statusText: string;
24
+ readonly responseBody: string;
25
+ readonly requestId: string | null;
26
+ constructor(status: number, statusText: string, responseBody: string, requestId: string | null);
27
+ }
28
+ declare class AzureTtsSdkError extends AzureTtsError {
29
+ readonly errorDetails: string;
30
+ constructor(errorDetails: string);
31
+ }
32
+
33
+ declare class AzureTtsClient {
34
+ #private;
35
+ constructor(options: AzureTtsClientOptions);
36
+ synthesize(ssml: string): Promise<ArrayBuffer>;
37
+ }
38
+
39
+ declare function synthesizeSpeech(ssml: string, config: TtsConfig): Promise<ArrayBuffer>;
40
+
41
+ export { AzureTtsClient, type AzureTtsClientOptions, AzureTtsError, type AzureTtsLogger, AzureTtsSdkError, type TtsConfig, synthesizeSpeech };
package/dist/index.js ADDED
@@ -0,0 +1,209 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __typeError = (msg) => {
9
+ throw TypeError(msg);
10
+ };
11
+ var __export = (target, all) => {
12
+ for (var name in all)
13
+ __defProp(target, name, { get: all[name], enumerable: true });
14
+ };
15
+ var __copyProps = (to, from, except, desc) => {
16
+ if (from && typeof from === "object" || typeof from === "function") {
17
+ for (let key of __getOwnPropNames(from))
18
+ if (!__hasOwnProp.call(to, key) && key !== except)
19
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
20
+ }
21
+ return to;
22
+ };
23
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
24
+ // If the importer is in node compatibility mode or this is not an ESM
25
+ // file that has been converted to a CommonJS file using a Babel-
26
+ // compatible transform (i.e. "__esModule" has not been set), then set
27
+ // "default" to the CommonJS "module.exports" for node compatibility.
28
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
29
+ mod
30
+ ));
31
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
32
+ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
33
+ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
34
+ var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
35
+ var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
36
+
37
+ // src/index.ts
38
+ var index_exports = {};
39
+ __export(index_exports, {
40
+ AzureTtsClient: () => AzureTtsClient,
41
+ AzureTtsError: () => AzureTtsError,
42
+ AzureTtsSdkError: () => AzureTtsSdkError,
43
+ synthesizeSpeech: () => synthesizeSpeech
44
+ });
45
+ module.exports = __toCommonJS(index_exports);
46
+
47
+ // src/errors.ts
48
+ var AzureTtsError = class extends Error {
49
+ constructor(status, statusText, responseBody, requestId) {
50
+ super(`Azure TTS request failed: ${status} ${statusText}`);
51
+ this.name = "AzureTtsError";
52
+ this.status = status;
53
+ this.statusText = statusText;
54
+ this.responseBody = responseBody;
55
+ this.requestId = requestId;
56
+ }
57
+ };
58
+ var AzureTtsSdkError = class extends AzureTtsError {
59
+ constructor(errorDetails) {
60
+ super(0, "Speech SDK", errorDetails, null);
61
+ this.name = "AzureTtsSdkError";
62
+ this.message = `Azure TTS synthesis failed: ${errorDetails}`;
63
+ this.errorDetails = errorDetails;
64
+ }
65
+ };
66
+ function createSpeechSdkError(error) {
67
+ const message = error instanceof Error ? error.message : String(error);
68
+ return new AzureTtsSdkError(message);
69
+ }
70
+
71
+ // src/synthesis.ts
72
+ var SpeechSDK2 = __toESM(require("microsoft-cognitiveservices-speech-sdk"));
73
+
74
+ // src/speechConfig.ts
75
+ var import_microsoft_cognitiveservices_speech_sdk = require("microsoft-cognitiveservices-speech-sdk");
76
+
77
+ // src/outputFormats.ts
78
+ var SpeechSDK = __toESM(require("microsoft-cognitiveservices-speech-sdk"));
79
+ var DEFAULT_OUTPUT_FORMAT = "audio-16khz-128kbitrate-mono-mp3";
80
+ var OUTPUT_FORMATS = {
81
+ "raw-8khz-8bit-mono-mulaw": SpeechSDK.SpeechSynthesisOutputFormat.Raw8Khz8BitMonoMULaw,
82
+ "riff-16khz-16kbps-mono-siren": SpeechSDK.SpeechSynthesisOutputFormat.Riff16Khz16KbpsMonoSiren,
83
+ "audio-16khz-16kbps-mono-siren": SpeechSDK.SpeechSynthesisOutputFormat.Audio16Khz16KbpsMonoSiren,
84
+ "audio-16khz-32kbitrate-mono-mp3": SpeechSDK.SpeechSynthesisOutputFormat.Audio16Khz32KBitRateMonoMp3,
85
+ "audio-16khz-128kbitrate-mono-mp3": SpeechSDK.SpeechSynthesisOutputFormat.Audio16Khz128KBitRateMonoMp3,
86
+ "audio-16khz-64kbitrate-mono-mp3": SpeechSDK.SpeechSynthesisOutputFormat.Audio16Khz64KBitRateMonoMp3,
87
+ "audio-24khz-48kbitrate-mono-mp3": SpeechSDK.SpeechSynthesisOutputFormat.Audio24Khz48KBitRateMonoMp3,
88
+ "audio-24khz-96kbitrate-mono-mp3": SpeechSDK.SpeechSynthesisOutputFormat.Audio24Khz96KBitRateMonoMp3,
89
+ "audio-24khz-160kbitrate-mono-mp3": SpeechSDK.SpeechSynthesisOutputFormat.Audio24Khz160KBitRateMonoMp3,
90
+ "raw-16khz-16bit-mono-truesilk": SpeechSDK.SpeechSynthesisOutputFormat.Raw16Khz16BitMonoTrueSilk,
91
+ "riff-16khz-16bit-mono-pcm": SpeechSDK.SpeechSynthesisOutputFormat.Riff16Khz16BitMonoPcm,
92
+ "riff-8khz-16bit-mono-pcm": SpeechSDK.SpeechSynthesisOutputFormat.Riff8Khz16BitMonoPcm,
93
+ "riff-24khz-16bit-mono-pcm": SpeechSDK.SpeechSynthesisOutputFormat.Riff24Khz16BitMonoPcm,
94
+ "riff-8khz-8bit-mono-mulaw": SpeechSDK.SpeechSynthesisOutputFormat.Riff8Khz8BitMonoMULaw,
95
+ "raw-16khz-16bit-mono-pcm": SpeechSDK.SpeechSynthesisOutputFormat.Raw16Khz16BitMonoPcm,
96
+ "raw-24khz-16bit-mono-pcm": SpeechSDK.SpeechSynthesisOutputFormat.Raw24Khz16BitMonoPcm,
97
+ "raw-8khz-16bit-mono-pcm": SpeechSDK.SpeechSynthesisOutputFormat.Raw8Khz16BitMonoPcm,
98
+ "ogg-16khz-16bit-mono-opus": SpeechSDK.SpeechSynthesisOutputFormat.Ogg16Khz16BitMonoOpus,
99
+ "ogg-24khz-16bit-mono-opus": SpeechSDK.SpeechSynthesisOutputFormat.Ogg24Khz16BitMonoOpus,
100
+ "raw-48khz-16bit-mono-pcm": SpeechSDK.SpeechSynthesisOutputFormat.Raw48Khz16BitMonoPcm,
101
+ "riff-48khz-16bit-mono-pcm": SpeechSDK.SpeechSynthesisOutputFormat.Riff48Khz16BitMonoPcm,
102
+ "audio-48khz-96kbitrate-mono-mp3": SpeechSDK.SpeechSynthesisOutputFormat.Audio48Khz96KBitRateMonoMp3,
103
+ "audio-48khz-192kbitrate-mono-mp3": SpeechSDK.SpeechSynthesisOutputFormat.Audio48Khz192KBitRateMonoMp3,
104
+ "ogg-48khz-16bit-mono-opus": SpeechSDK.SpeechSynthesisOutputFormat.Ogg48Khz16BitMonoOpus,
105
+ "webm-16khz-16bit-mono-opus": SpeechSDK.SpeechSynthesisOutputFormat.Webm16Khz16BitMonoOpus,
106
+ "webm-24khz-16bit-mono-opus": SpeechSDK.SpeechSynthesisOutputFormat.Webm24Khz16BitMonoOpus,
107
+ "webm-24khz-16bit-24kbps-mono-opus": SpeechSDK.SpeechSynthesisOutputFormat.Webm24Khz16Bit24KbpsMonoOpus,
108
+ "raw-24khz-16bit-mono-truesilk": SpeechSDK.SpeechSynthesisOutputFormat.Raw24Khz16BitMonoTrueSilk,
109
+ "raw-8khz-8bit-mono-alaw": SpeechSDK.SpeechSynthesisOutputFormat.Raw8Khz8BitMonoALaw,
110
+ "riff-8khz-8bit-mono-alaw": SpeechSDK.SpeechSynthesisOutputFormat.Riff8Khz8BitMonoALaw,
111
+ "audio-16khz-16bit-32kbps-mono-opus": SpeechSDK.SpeechSynthesisOutputFormat.Audio16Khz16Bit32KbpsMonoOpus,
112
+ "audio-24khz-16bit-48kbps-mono-opus": SpeechSDK.SpeechSynthesisOutputFormat.Audio24Khz16Bit48KbpsMonoOpus,
113
+ "audio-24khz-16bit-24kbps-mono-opus": SpeechSDK.SpeechSynthesisOutputFormat.Audio24Khz16Bit24KbpsMonoOpus,
114
+ "raw-22050hz-16bit-mono-pcm": SpeechSDK.SpeechSynthesisOutputFormat.Raw22050Hz16BitMonoPcm,
115
+ "riff-22050hz-16bit-mono-pcm": SpeechSDK.SpeechSynthesisOutputFormat.Riff22050Hz16BitMonoPcm,
116
+ "raw-44100hz-16bit-mono-pcm": SpeechSDK.SpeechSynthesisOutputFormat.Raw44100Hz16BitMonoPcm,
117
+ "riff-44100hz-16bit-mono-pcm": SpeechSDK.SpeechSynthesisOutputFormat.Riff44100Hz16BitMonoPcm,
118
+ "amr-wb-16000hz": SpeechSDK.SpeechSynthesisOutputFormat.AmrWb16000Hz,
119
+ "g722-16khz-64kbps": SpeechSDK.SpeechSynthesisOutputFormat.G72216Khz64Kbps
120
+ };
121
+ function resolveOutputFormat(outputFormat) {
122
+ const resolvedFormat = OUTPUT_FORMATS[outputFormat];
123
+ if (resolvedFormat === void 0) {
124
+ throw new Error(`Unsupported Azure Speech output format: ${outputFormat}`);
125
+ }
126
+ return resolvedFormat;
127
+ }
128
+
129
+ // src/speechConfig.ts
130
+ function resolveEndpoint(config) {
131
+ const endpoint = config.endpoint?.trim() || "https://{region}.tts.speech.microsoft.com/cognitiveservices/v1";
132
+ return endpoint.replace(/\{region\}/g, encodeURIComponent(config.region));
133
+ }
134
+ function createSpeechConfig(config) {
135
+ const { outputFormat = DEFAULT_OUTPUT_FORMAT, subscriptionKey } = config;
136
+ const endpoint = new URL(resolveEndpoint(config));
137
+ const speechConfig = import_microsoft_cognitiveservices_speech_sdk.SpeechConfig.fromEndpoint(endpoint, subscriptionKey);
138
+ speechConfig.speechSynthesisOutputFormat = resolveOutputFormat(outputFormat);
139
+ return speechConfig;
140
+ }
141
+
142
+ // src/synthesis.ts
143
+ function closeSpeechResources(speechConfig, synthesizer) {
144
+ try {
145
+ synthesizer.close();
146
+ } catch {
147
+ }
148
+ try {
149
+ speechConfig.close();
150
+ } catch {
151
+ }
152
+ }
153
+ async function synthesizeSpeech(ssml, config) {
154
+ const speechConfig = createSpeechConfig(config);
155
+ const synthesizer = new SpeechSDK2.SpeechSynthesizer(speechConfig, null);
156
+ return await new Promise((resolve, reject) => {
157
+ let resourcesClosed = false;
158
+ const closeResources = () => {
159
+ if (resourcesClosed) return;
160
+ resourcesClosed = true;
161
+ closeSpeechResources(speechConfig, synthesizer);
162
+ };
163
+ const rejectWithError = (error) => {
164
+ closeResources();
165
+ reject(createSpeechSdkError(error));
166
+ };
167
+ const cb = (result) => {
168
+ const { reason, errorDetails } = result;
169
+ if (reason !== SpeechSDK2.ResultReason.SynthesizingAudioCompleted) {
170
+ const err = errorDetails || `Speech synthesis failed with reason ${reason}.`;
171
+ rejectWithError(err);
172
+ return;
173
+ }
174
+ closeResources();
175
+ resolve(result.audioData);
176
+ };
177
+ try {
178
+ synthesizer.speakSsmlAsync(ssml, cb, rejectWithError);
179
+ } catch (error) {
180
+ rejectWithError(error);
181
+ }
182
+ });
183
+ }
184
+
185
+ // src/client.ts
186
+ var ENDPOINT_TEMPLATE = "https://{region}.tts.speech.microsoft.com/cognitiveservices/v1";
187
+ var _options;
188
+ var AzureTtsClient = class {
189
+ constructor(options) {
190
+ __privateAdd(this, _options);
191
+ __privateSet(this, _options, options);
192
+ }
193
+ async synthesize(ssml) {
194
+ const { region, subscriptionKey, outputFormat } = __privateGet(this, _options);
195
+ const endpoint = __privateGet(this, _options).endpoint?.trim() || ENDPOINT_TEMPLATE.replace("{region}", region);
196
+ __privateGet(this, _options).logger?.debug?.("Using Azure TTS endpoint:", endpoint);
197
+ const config = { endpoint, region, subscriptionKey, outputFormat };
198
+ return synthesizeSpeech(ssml, config);
199
+ }
200
+ };
201
+ _options = new WeakMap();
202
+ // Annotate the CommonJS export names for ESM import in node:
203
+ 0 && (module.exports = {
204
+ AzureTtsClient,
205
+ AzureTtsError,
206
+ AzureTtsSdkError,
207
+ synthesizeSpeech
208
+ });
209
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/synthesis.ts","../src/speechConfig.ts","../src/outputFormats.ts","../src/client.ts"],"sourcesContent":["/**\n * azure-tts-client: Azure Text-to-Speech client for SSML playback.\n */\n\nexport type { AzureTtsClientOptions, AzureTtsLogger, TtsConfig } from \"./types.ts\";\nexport { AzureTtsError, AzureTtsSdkError } from \"./errors.ts\";\nexport { AzureTtsClient } from \"./client.ts\";\nexport { synthesizeSpeech } from \"./synthesis.ts\";\n","export class AzureTtsError extends Error {\n readonly status: number;\n readonly statusText: string;\n readonly responseBody: string;\n readonly requestId: string | null;\n\n constructor(status: number, statusText: string, responseBody: string, requestId: string | null) {\n super(`Azure TTS request failed: ${status} ${statusText}`);\n this.name = \"AzureTtsError\";\n this.status = status;\n this.statusText = statusText;\n this.responseBody = responseBody;\n this.requestId = requestId;\n }\n}\n\nexport class AzureTtsSdkError extends AzureTtsError {\n readonly errorDetails: string;\n\n constructor(errorDetails: string) {\n super(0, \"Speech SDK\", errorDetails, null);\n this.name = \"AzureTtsSdkError\";\n this.message = `Azure TTS synthesis failed: ${errorDetails}`;\n this.errorDetails = errorDetails;\n }\n}\n\nexport function createSpeechSdkError(error: unknown): AzureTtsSdkError {\n const message = error instanceof Error ? error.message : String(error);\n return new AzureTtsSdkError(message);\n}\n","import * as SpeechSDK from \"microsoft-cognitiveservices-speech-sdk\";\nimport { createSpeechSdkError } from \"./errors.ts\";\nimport { createSpeechConfig } from \"./speechConfig.ts\";\nimport type { TtsConfig } from \"./types.ts\";\n\nfunction closeSpeechResources(speechConfig: SpeechSDK.SpeechConfig, synthesizer: SpeechSDK.SpeechSynthesizer): void {\n try {\n synthesizer.close();\n } catch {}\n\n try {\n speechConfig.close();\n } catch {}\n}\n\nexport async function synthesizeSpeech(ssml: string, config: TtsConfig): Promise<ArrayBuffer> {\n const speechConfig = createSpeechConfig(config);\n const synthesizer = new SpeechSDK.SpeechSynthesizer(speechConfig, null);\n\n return await new Promise<ArrayBuffer>((resolve, reject) => {\n let resourcesClosed = false;\n const closeResources = () => {\n if (resourcesClosed) return;\n resourcesClosed = true;\n closeSpeechResources(speechConfig, synthesizer);\n };\n const rejectWithError = (error: unknown) => {\n closeResources();\n reject(createSpeechSdkError(error));\n };\n\n const cb = (result: SpeechSDK.SpeechSynthesisResult) => {\n const { reason, errorDetails } = result;\n if (reason !== SpeechSDK.ResultReason.SynthesizingAudioCompleted) {\n const err = errorDetails || `Speech synthesis failed with reason ${reason}.`;\n rejectWithError(err);\n return;\n }\n closeResources();\n resolve(result.audioData);\n };\n\n try {\n synthesizer.speakSsmlAsync(ssml, cb, rejectWithError);\n } catch (error) {\n rejectWithError(error);\n }\n });\n}\n","import { SpeechConfig } from \"microsoft-cognitiveservices-speech-sdk\";\nimport { DEFAULT_OUTPUT_FORMAT, resolveOutputFormat } from \"./outputFormats.ts\";\nimport type { TtsConfig } from \"./types.ts\";\n\nexport function resolveEndpoint(config: TtsConfig): string {\n const endpoint = config.endpoint?.trim() || \"https://{region}.tts.speech.microsoft.com/cognitiveservices/v1\";\n return endpoint.replace(/\\{region\\}/g, encodeURIComponent(config.region));\n}\n\nexport function createSpeechConfig(config: TtsConfig): SpeechConfig {\n const { outputFormat = DEFAULT_OUTPUT_FORMAT, subscriptionKey } = config;\n\n const endpoint = new URL(resolveEndpoint(config));\n const speechConfig = SpeechConfig.fromEndpoint(endpoint, subscriptionKey);\n speechConfig.speechSynthesisOutputFormat = resolveOutputFormat(outputFormat);\n return speechConfig;\n}\n","import * as SpeechSDK from \"microsoft-cognitiveservices-speech-sdk\";\n\nexport const DEFAULT_OUTPUT_FORMAT = \"audio-16khz-128kbitrate-mono-mp3\";\n\nconst OUTPUT_FORMATS: Record<string, SpeechSDK.SpeechSynthesisOutputFormat> = {\n \"raw-8khz-8bit-mono-mulaw\": SpeechSDK.SpeechSynthesisOutputFormat.Raw8Khz8BitMonoMULaw,\n \"riff-16khz-16kbps-mono-siren\": SpeechSDK.SpeechSynthesisOutputFormat.Riff16Khz16KbpsMonoSiren,\n \"audio-16khz-16kbps-mono-siren\": SpeechSDK.SpeechSynthesisOutputFormat.Audio16Khz16KbpsMonoSiren,\n \"audio-16khz-32kbitrate-mono-mp3\": SpeechSDK.SpeechSynthesisOutputFormat.Audio16Khz32KBitRateMonoMp3,\n \"audio-16khz-128kbitrate-mono-mp3\": SpeechSDK.SpeechSynthesisOutputFormat.Audio16Khz128KBitRateMonoMp3,\n \"audio-16khz-64kbitrate-mono-mp3\": SpeechSDK.SpeechSynthesisOutputFormat.Audio16Khz64KBitRateMonoMp3,\n \"audio-24khz-48kbitrate-mono-mp3\": SpeechSDK.SpeechSynthesisOutputFormat.Audio24Khz48KBitRateMonoMp3,\n \"audio-24khz-96kbitrate-mono-mp3\": SpeechSDK.SpeechSynthesisOutputFormat.Audio24Khz96KBitRateMonoMp3,\n \"audio-24khz-160kbitrate-mono-mp3\": SpeechSDK.SpeechSynthesisOutputFormat.Audio24Khz160KBitRateMonoMp3,\n \"raw-16khz-16bit-mono-truesilk\": SpeechSDK.SpeechSynthesisOutputFormat.Raw16Khz16BitMonoTrueSilk,\n \"riff-16khz-16bit-mono-pcm\": SpeechSDK.SpeechSynthesisOutputFormat.Riff16Khz16BitMonoPcm,\n \"riff-8khz-16bit-mono-pcm\": SpeechSDK.SpeechSynthesisOutputFormat.Riff8Khz16BitMonoPcm,\n \"riff-24khz-16bit-mono-pcm\": SpeechSDK.SpeechSynthesisOutputFormat.Riff24Khz16BitMonoPcm,\n \"riff-8khz-8bit-mono-mulaw\": SpeechSDK.SpeechSynthesisOutputFormat.Riff8Khz8BitMonoMULaw,\n \"raw-16khz-16bit-mono-pcm\": SpeechSDK.SpeechSynthesisOutputFormat.Raw16Khz16BitMonoPcm,\n \"raw-24khz-16bit-mono-pcm\": SpeechSDK.SpeechSynthesisOutputFormat.Raw24Khz16BitMonoPcm,\n \"raw-8khz-16bit-mono-pcm\": SpeechSDK.SpeechSynthesisOutputFormat.Raw8Khz16BitMonoPcm,\n \"ogg-16khz-16bit-mono-opus\": SpeechSDK.SpeechSynthesisOutputFormat.Ogg16Khz16BitMonoOpus,\n \"ogg-24khz-16bit-mono-opus\": SpeechSDK.SpeechSynthesisOutputFormat.Ogg24Khz16BitMonoOpus,\n \"raw-48khz-16bit-mono-pcm\": SpeechSDK.SpeechSynthesisOutputFormat.Raw48Khz16BitMonoPcm,\n \"riff-48khz-16bit-mono-pcm\": SpeechSDK.SpeechSynthesisOutputFormat.Riff48Khz16BitMonoPcm,\n \"audio-48khz-96kbitrate-mono-mp3\": SpeechSDK.SpeechSynthesisOutputFormat.Audio48Khz96KBitRateMonoMp3,\n \"audio-48khz-192kbitrate-mono-mp3\": SpeechSDK.SpeechSynthesisOutputFormat.Audio48Khz192KBitRateMonoMp3,\n \"ogg-48khz-16bit-mono-opus\": SpeechSDK.SpeechSynthesisOutputFormat.Ogg48Khz16BitMonoOpus,\n \"webm-16khz-16bit-mono-opus\": SpeechSDK.SpeechSynthesisOutputFormat.Webm16Khz16BitMonoOpus,\n \"webm-24khz-16bit-mono-opus\": SpeechSDK.SpeechSynthesisOutputFormat.Webm24Khz16BitMonoOpus,\n \"webm-24khz-16bit-24kbps-mono-opus\": SpeechSDK.SpeechSynthesisOutputFormat.Webm24Khz16Bit24KbpsMonoOpus,\n \"raw-24khz-16bit-mono-truesilk\": SpeechSDK.SpeechSynthesisOutputFormat.Raw24Khz16BitMonoTrueSilk,\n \"raw-8khz-8bit-mono-alaw\": SpeechSDK.SpeechSynthesisOutputFormat.Raw8Khz8BitMonoALaw,\n \"riff-8khz-8bit-mono-alaw\": SpeechSDK.SpeechSynthesisOutputFormat.Riff8Khz8BitMonoALaw,\n \"audio-16khz-16bit-32kbps-mono-opus\": SpeechSDK.SpeechSynthesisOutputFormat.Audio16Khz16Bit32KbpsMonoOpus,\n \"audio-24khz-16bit-48kbps-mono-opus\": SpeechSDK.SpeechSynthesisOutputFormat.Audio24Khz16Bit48KbpsMonoOpus,\n \"audio-24khz-16bit-24kbps-mono-opus\": SpeechSDK.SpeechSynthesisOutputFormat.Audio24Khz16Bit24KbpsMonoOpus,\n \"raw-22050hz-16bit-mono-pcm\": SpeechSDK.SpeechSynthesisOutputFormat.Raw22050Hz16BitMonoPcm,\n \"riff-22050hz-16bit-mono-pcm\": SpeechSDK.SpeechSynthesisOutputFormat.Riff22050Hz16BitMonoPcm,\n \"raw-44100hz-16bit-mono-pcm\": SpeechSDK.SpeechSynthesisOutputFormat.Raw44100Hz16BitMonoPcm,\n \"riff-44100hz-16bit-mono-pcm\": SpeechSDK.SpeechSynthesisOutputFormat.Riff44100Hz16BitMonoPcm,\n \"amr-wb-16000hz\": SpeechSDK.SpeechSynthesisOutputFormat.AmrWb16000Hz,\n \"g722-16khz-64kbps\": SpeechSDK.SpeechSynthesisOutputFormat.G72216Khz64Kbps,\n};\n\nexport function resolveOutputFormat(outputFormat: string): SpeechSDK.SpeechSynthesisOutputFormat {\n const resolvedFormat = OUTPUT_FORMATS[outputFormat];\n if (resolvedFormat === undefined) {\n throw new Error(`Unsupported Azure Speech output format: ${outputFormat}`);\n }\n\n return resolvedFormat;\n}\n","import { synthesizeSpeech } from \"./synthesis.ts\";\nimport type { AzureTtsClientOptions } from \"./types.ts\";\n\nconst ENDPOINT_TEMPLATE = \"https://{region}.tts.speech.microsoft.com/cognitiveservices/v1\";\n\nexport class AzureTtsClient {\n readonly #options: AzureTtsClientOptions;\n\n constructor(options: AzureTtsClientOptions) {\n this.#options = options;\n }\n\n async synthesize(ssml: string): Promise<ArrayBuffer> {\n const { region, subscriptionKey, outputFormat } = this.#options;\n const endpoint = this.#options.endpoint?.trim() || ENDPOINT_TEMPLATE.replace(\"{region}\", region);\n this.#options.logger?.debug?.(\"Using Azure TTS endpoint:\", endpoint);\n\n const config = { endpoint, region, subscriptionKey, outputFormat };\n return synthesizeSpeech(ssml, config);\n }\n}\n"],"mappings":"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","names":["SpeechSDK"]}
package/dist/index.mjs ADDED
@@ -0,0 +1,170 @@
1
+ var __typeError = (msg) => {
2
+ throw TypeError(msg);
3
+ };
4
+ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
5
+ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
6
+ var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
7
+ var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
8
+
9
+ // src/errors.ts
10
+ var AzureTtsError = class extends Error {
11
+ constructor(status, statusText, responseBody, requestId) {
12
+ super(`Azure TTS request failed: ${status} ${statusText}`);
13
+ this.name = "AzureTtsError";
14
+ this.status = status;
15
+ this.statusText = statusText;
16
+ this.responseBody = responseBody;
17
+ this.requestId = requestId;
18
+ }
19
+ };
20
+ var AzureTtsSdkError = class extends AzureTtsError {
21
+ constructor(errorDetails) {
22
+ super(0, "Speech SDK", errorDetails, null);
23
+ this.name = "AzureTtsSdkError";
24
+ this.message = `Azure TTS synthesis failed: ${errorDetails}`;
25
+ this.errorDetails = errorDetails;
26
+ }
27
+ };
28
+ function createSpeechSdkError(error) {
29
+ const message = error instanceof Error ? error.message : String(error);
30
+ return new AzureTtsSdkError(message);
31
+ }
32
+
33
+ // src/synthesis.ts
34
+ import * as SpeechSDK2 from "microsoft-cognitiveservices-speech-sdk";
35
+
36
+ // src/speechConfig.ts
37
+ import { SpeechConfig } from "microsoft-cognitiveservices-speech-sdk";
38
+
39
+ // src/outputFormats.ts
40
+ import * as SpeechSDK from "microsoft-cognitiveservices-speech-sdk";
41
+ var DEFAULT_OUTPUT_FORMAT = "audio-16khz-128kbitrate-mono-mp3";
42
+ var OUTPUT_FORMATS = {
43
+ "raw-8khz-8bit-mono-mulaw": SpeechSDK.SpeechSynthesisOutputFormat.Raw8Khz8BitMonoMULaw,
44
+ "riff-16khz-16kbps-mono-siren": SpeechSDK.SpeechSynthesisOutputFormat.Riff16Khz16KbpsMonoSiren,
45
+ "audio-16khz-16kbps-mono-siren": SpeechSDK.SpeechSynthesisOutputFormat.Audio16Khz16KbpsMonoSiren,
46
+ "audio-16khz-32kbitrate-mono-mp3": SpeechSDK.SpeechSynthesisOutputFormat.Audio16Khz32KBitRateMonoMp3,
47
+ "audio-16khz-128kbitrate-mono-mp3": SpeechSDK.SpeechSynthesisOutputFormat.Audio16Khz128KBitRateMonoMp3,
48
+ "audio-16khz-64kbitrate-mono-mp3": SpeechSDK.SpeechSynthesisOutputFormat.Audio16Khz64KBitRateMonoMp3,
49
+ "audio-24khz-48kbitrate-mono-mp3": SpeechSDK.SpeechSynthesisOutputFormat.Audio24Khz48KBitRateMonoMp3,
50
+ "audio-24khz-96kbitrate-mono-mp3": SpeechSDK.SpeechSynthesisOutputFormat.Audio24Khz96KBitRateMonoMp3,
51
+ "audio-24khz-160kbitrate-mono-mp3": SpeechSDK.SpeechSynthesisOutputFormat.Audio24Khz160KBitRateMonoMp3,
52
+ "raw-16khz-16bit-mono-truesilk": SpeechSDK.SpeechSynthesisOutputFormat.Raw16Khz16BitMonoTrueSilk,
53
+ "riff-16khz-16bit-mono-pcm": SpeechSDK.SpeechSynthesisOutputFormat.Riff16Khz16BitMonoPcm,
54
+ "riff-8khz-16bit-mono-pcm": SpeechSDK.SpeechSynthesisOutputFormat.Riff8Khz16BitMonoPcm,
55
+ "riff-24khz-16bit-mono-pcm": SpeechSDK.SpeechSynthesisOutputFormat.Riff24Khz16BitMonoPcm,
56
+ "riff-8khz-8bit-mono-mulaw": SpeechSDK.SpeechSynthesisOutputFormat.Riff8Khz8BitMonoMULaw,
57
+ "raw-16khz-16bit-mono-pcm": SpeechSDK.SpeechSynthesisOutputFormat.Raw16Khz16BitMonoPcm,
58
+ "raw-24khz-16bit-mono-pcm": SpeechSDK.SpeechSynthesisOutputFormat.Raw24Khz16BitMonoPcm,
59
+ "raw-8khz-16bit-mono-pcm": SpeechSDK.SpeechSynthesisOutputFormat.Raw8Khz16BitMonoPcm,
60
+ "ogg-16khz-16bit-mono-opus": SpeechSDK.SpeechSynthesisOutputFormat.Ogg16Khz16BitMonoOpus,
61
+ "ogg-24khz-16bit-mono-opus": SpeechSDK.SpeechSynthesisOutputFormat.Ogg24Khz16BitMonoOpus,
62
+ "raw-48khz-16bit-mono-pcm": SpeechSDK.SpeechSynthesisOutputFormat.Raw48Khz16BitMonoPcm,
63
+ "riff-48khz-16bit-mono-pcm": SpeechSDK.SpeechSynthesisOutputFormat.Riff48Khz16BitMonoPcm,
64
+ "audio-48khz-96kbitrate-mono-mp3": SpeechSDK.SpeechSynthesisOutputFormat.Audio48Khz96KBitRateMonoMp3,
65
+ "audio-48khz-192kbitrate-mono-mp3": SpeechSDK.SpeechSynthesisOutputFormat.Audio48Khz192KBitRateMonoMp3,
66
+ "ogg-48khz-16bit-mono-opus": SpeechSDK.SpeechSynthesisOutputFormat.Ogg48Khz16BitMonoOpus,
67
+ "webm-16khz-16bit-mono-opus": SpeechSDK.SpeechSynthesisOutputFormat.Webm16Khz16BitMonoOpus,
68
+ "webm-24khz-16bit-mono-opus": SpeechSDK.SpeechSynthesisOutputFormat.Webm24Khz16BitMonoOpus,
69
+ "webm-24khz-16bit-24kbps-mono-opus": SpeechSDK.SpeechSynthesisOutputFormat.Webm24Khz16Bit24KbpsMonoOpus,
70
+ "raw-24khz-16bit-mono-truesilk": SpeechSDK.SpeechSynthesisOutputFormat.Raw24Khz16BitMonoTrueSilk,
71
+ "raw-8khz-8bit-mono-alaw": SpeechSDK.SpeechSynthesisOutputFormat.Raw8Khz8BitMonoALaw,
72
+ "riff-8khz-8bit-mono-alaw": SpeechSDK.SpeechSynthesisOutputFormat.Riff8Khz8BitMonoALaw,
73
+ "audio-16khz-16bit-32kbps-mono-opus": SpeechSDK.SpeechSynthesisOutputFormat.Audio16Khz16Bit32KbpsMonoOpus,
74
+ "audio-24khz-16bit-48kbps-mono-opus": SpeechSDK.SpeechSynthesisOutputFormat.Audio24Khz16Bit48KbpsMonoOpus,
75
+ "audio-24khz-16bit-24kbps-mono-opus": SpeechSDK.SpeechSynthesisOutputFormat.Audio24Khz16Bit24KbpsMonoOpus,
76
+ "raw-22050hz-16bit-mono-pcm": SpeechSDK.SpeechSynthesisOutputFormat.Raw22050Hz16BitMonoPcm,
77
+ "riff-22050hz-16bit-mono-pcm": SpeechSDK.SpeechSynthesisOutputFormat.Riff22050Hz16BitMonoPcm,
78
+ "raw-44100hz-16bit-mono-pcm": SpeechSDK.SpeechSynthesisOutputFormat.Raw44100Hz16BitMonoPcm,
79
+ "riff-44100hz-16bit-mono-pcm": SpeechSDK.SpeechSynthesisOutputFormat.Riff44100Hz16BitMonoPcm,
80
+ "amr-wb-16000hz": SpeechSDK.SpeechSynthesisOutputFormat.AmrWb16000Hz,
81
+ "g722-16khz-64kbps": SpeechSDK.SpeechSynthesisOutputFormat.G72216Khz64Kbps
82
+ };
83
+ function resolveOutputFormat(outputFormat) {
84
+ const resolvedFormat = OUTPUT_FORMATS[outputFormat];
85
+ if (resolvedFormat === void 0) {
86
+ throw new Error(`Unsupported Azure Speech output format: ${outputFormat}`);
87
+ }
88
+ return resolvedFormat;
89
+ }
90
+
91
+ // src/speechConfig.ts
92
+ function resolveEndpoint(config) {
93
+ const endpoint = config.endpoint?.trim() || "https://{region}.tts.speech.microsoft.com/cognitiveservices/v1";
94
+ return endpoint.replace(/\{region\}/g, encodeURIComponent(config.region));
95
+ }
96
+ function createSpeechConfig(config) {
97
+ const { outputFormat = DEFAULT_OUTPUT_FORMAT, subscriptionKey } = config;
98
+ const endpoint = new URL(resolveEndpoint(config));
99
+ const speechConfig = SpeechConfig.fromEndpoint(endpoint, subscriptionKey);
100
+ speechConfig.speechSynthesisOutputFormat = resolveOutputFormat(outputFormat);
101
+ return speechConfig;
102
+ }
103
+
104
+ // src/synthesis.ts
105
+ function closeSpeechResources(speechConfig, synthesizer) {
106
+ try {
107
+ synthesizer.close();
108
+ } catch {
109
+ }
110
+ try {
111
+ speechConfig.close();
112
+ } catch {
113
+ }
114
+ }
115
+ async function synthesizeSpeech(ssml, config) {
116
+ const speechConfig = createSpeechConfig(config);
117
+ const synthesizer = new SpeechSDK2.SpeechSynthesizer(speechConfig, null);
118
+ return await new Promise((resolve, reject) => {
119
+ let resourcesClosed = false;
120
+ const closeResources = () => {
121
+ if (resourcesClosed) return;
122
+ resourcesClosed = true;
123
+ closeSpeechResources(speechConfig, synthesizer);
124
+ };
125
+ const rejectWithError = (error) => {
126
+ closeResources();
127
+ reject(createSpeechSdkError(error));
128
+ };
129
+ const cb = (result) => {
130
+ const { reason, errorDetails } = result;
131
+ if (reason !== SpeechSDK2.ResultReason.SynthesizingAudioCompleted) {
132
+ const err = errorDetails || `Speech synthesis failed with reason ${reason}.`;
133
+ rejectWithError(err);
134
+ return;
135
+ }
136
+ closeResources();
137
+ resolve(result.audioData);
138
+ };
139
+ try {
140
+ synthesizer.speakSsmlAsync(ssml, cb, rejectWithError);
141
+ } catch (error) {
142
+ rejectWithError(error);
143
+ }
144
+ });
145
+ }
146
+
147
+ // src/client.ts
148
+ var ENDPOINT_TEMPLATE = "https://{region}.tts.speech.microsoft.com/cognitiveservices/v1";
149
+ var _options;
150
+ var AzureTtsClient = class {
151
+ constructor(options) {
152
+ __privateAdd(this, _options);
153
+ __privateSet(this, _options, options);
154
+ }
155
+ async synthesize(ssml) {
156
+ const { region, subscriptionKey, outputFormat } = __privateGet(this, _options);
157
+ const endpoint = __privateGet(this, _options).endpoint?.trim() || ENDPOINT_TEMPLATE.replace("{region}", region);
158
+ __privateGet(this, _options).logger?.debug?.("Using Azure TTS endpoint:", endpoint);
159
+ const config = { endpoint, region, subscriptionKey, outputFormat };
160
+ return synthesizeSpeech(ssml, config);
161
+ }
162
+ };
163
+ _options = new WeakMap();
164
+ export {
165
+ AzureTtsClient,
166
+ AzureTtsError,
167
+ AzureTtsSdkError,
168
+ synthesizeSpeech
169
+ };
170
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/errors.ts","../src/synthesis.ts","../src/speechConfig.ts","../src/outputFormats.ts","../src/client.ts"],"sourcesContent":["export class AzureTtsError extends Error {\n readonly status: number;\n readonly statusText: string;\n readonly responseBody: string;\n readonly requestId: string | null;\n\n constructor(status: number, statusText: string, responseBody: string, requestId: string | null) {\n super(`Azure TTS request failed: ${status} ${statusText}`);\n this.name = \"AzureTtsError\";\n this.status = status;\n this.statusText = statusText;\n this.responseBody = responseBody;\n this.requestId = requestId;\n }\n}\n\nexport class AzureTtsSdkError extends AzureTtsError {\n readonly errorDetails: string;\n\n constructor(errorDetails: string) {\n super(0, \"Speech SDK\", errorDetails, null);\n this.name = \"AzureTtsSdkError\";\n this.message = `Azure TTS synthesis failed: ${errorDetails}`;\n this.errorDetails = errorDetails;\n }\n}\n\nexport function createSpeechSdkError(error: unknown): AzureTtsSdkError {\n const message = error instanceof Error ? error.message : String(error);\n return new AzureTtsSdkError(message);\n}\n","import * as SpeechSDK from \"microsoft-cognitiveservices-speech-sdk\";\nimport { createSpeechSdkError } from \"./errors.ts\";\nimport { createSpeechConfig } from \"./speechConfig.ts\";\nimport type { TtsConfig } from \"./types.ts\";\n\nfunction closeSpeechResources(speechConfig: SpeechSDK.SpeechConfig, synthesizer: SpeechSDK.SpeechSynthesizer): void {\n try {\n synthesizer.close();\n } catch {}\n\n try {\n speechConfig.close();\n } catch {}\n}\n\nexport async function synthesizeSpeech(ssml: string, config: TtsConfig): Promise<ArrayBuffer> {\n const speechConfig = createSpeechConfig(config);\n const synthesizer = new SpeechSDK.SpeechSynthesizer(speechConfig, null);\n\n return await new Promise<ArrayBuffer>((resolve, reject) => {\n let resourcesClosed = false;\n const closeResources = () => {\n if (resourcesClosed) return;\n resourcesClosed = true;\n closeSpeechResources(speechConfig, synthesizer);\n };\n const rejectWithError = (error: unknown) => {\n closeResources();\n reject(createSpeechSdkError(error));\n };\n\n const cb = (result: SpeechSDK.SpeechSynthesisResult) => {\n const { reason, errorDetails } = result;\n if (reason !== SpeechSDK.ResultReason.SynthesizingAudioCompleted) {\n const err = errorDetails || `Speech synthesis failed with reason ${reason}.`;\n rejectWithError(err);\n return;\n }\n closeResources();\n resolve(result.audioData);\n };\n\n try {\n synthesizer.speakSsmlAsync(ssml, cb, rejectWithError);\n } catch (error) {\n rejectWithError(error);\n }\n });\n}\n","import { SpeechConfig } from \"microsoft-cognitiveservices-speech-sdk\";\nimport { DEFAULT_OUTPUT_FORMAT, resolveOutputFormat } from \"./outputFormats.ts\";\nimport type { TtsConfig } from \"./types.ts\";\n\nexport function resolveEndpoint(config: TtsConfig): string {\n const endpoint = config.endpoint?.trim() || \"https://{region}.tts.speech.microsoft.com/cognitiveservices/v1\";\n return endpoint.replace(/\\{region\\}/g, encodeURIComponent(config.region));\n}\n\nexport function createSpeechConfig(config: TtsConfig): SpeechConfig {\n const { outputFormat = DEFAULT_OUTPUT_FORMAT, subscriptionKey } = config;\n\n const endpoint = new URL(resolveEndpoint(config));\n const speechConfig = SpeechConfig.fromEndpoint(endpoint, subscriptionKey);\n speechConfig.speechSynthesisOutputFormat = resolveOutputFormat(outputFormat);\n return speechConfig;\n}\n","import * as SpeechSDK from \"microsoft-cognitiveservices-speech-sdk\";\n\nexport const DEFAULT_OUTPUT_FORMAT = \"audio-16khz-128kbitrate-mono-mp3\";\n\nconst OUTPUT_FORMATS: Record<string, SpeechSDK.SpeechSynthesisOutputFormat> = {\n \"raw-8khz-8bit-mono-mulaw\": SpeechSDK.SpeechSynthesisOutputFormat.Raw8Khz8BitMonoMULaw,\n \"riff-16khz-16kbps-mono-siren\": SpeechSDK.SpeechSynthesisOutputFormat.Riff16Khz16KbpsMonoSiren,\n \"audio-16khz-16kbps-mono-siren\": SpeechSDK.SpeechSynthesisOutputFormat.Audio16Khz16KbpsMonoSiren,\n \"audio-16khz-32kbitrate-mono-mp3\": SpeechSDK.SpeechSynthesisOutputFormat.Audio16Khz32KBitRateMonoMp3,\n \"audio-16khz-128kbitrate-mono-mp3\": SpeechSDK.SpeechSynthesisOutputFormat.Audio16Khz128KBitRateMonoMp3,\n \"audio-16khz-64kbitrate-mono-mp3\": SpeechSDK.SpeechSynthesisOutputFormat.Audio16Khz64KBitRateMonoMp3,\n \"audio-24khz-48kbitrate-mono-mp3\": SpeechSDK.SpeechSynthesisOutputFormat.Audio24Khz48KBitRateMonoMp3,\n \"audio-24khz-96kbitrate-mono-mp3\": SpeechSDK.SpeechSynthesisOutputFormat.Audio24Khz96KBitRateMonoMp3,\n \"audio-24khz-160kbitrate-mono-mp3\": SpeechSDK.SpeechSynthesisOutputFormat.Audio24Khz160KBitRateMonoMp3,\n \"raw-16khz-16bit-mono-truesilk\": SpeechSDK.SpeechSynthesisOutputFormat.Raw16Khz16BitMonoTrueSilk,\n \"riff-16khz-16bit-mono-pcm\": SpeechSDK.SpeechSynthesisOutputFormat.Riff16Khz16BitMonoPcm,\n \"riff-8khz-16bit-mono-pcm\": SpeechSDK.SpeechSynthesisOutputFormat.Riff8Khz16BitMonoPcm,\n \"riff-24khz-16bit-mono-pcm\": SpeechSDK.SpeechSynthesisOutputFormat.Riff24Khz16BitMonoPcm,\n \"riff-8khz-8bit-mono-mulaw\": SpeechSDK.SpeechSynthesisOutputFormat.Riff8Khz8BitMonoMULaw,\n \"raw-16khz-16bit-mono-pcm\": SpeechSDK.SpeechSynthesisOutputFormat.Raw16Khz16BitMonoPcm,\n \"raw-24khz-16bit-mono-pcm\": SpeechSDK.SpeechSynthesisOutputFormat.Raw24Khz16BitMonoPcm,\n \"raw-8khz-16bit-mono-pcm\": SpeechSDK.SpeechSynthesisOutputFormat.Raw8Khz16BitMonoPcm,\n \"ogg-16khz-16bit-mono-opus\": SpeechSDK.SpeechSynthesisOutputFormat.Ogg16Khz16BitMonoOpus,\n \"ogg-24khz-16bit-mono-opus\": SpeechSDK.SpeechSynthesisOutputFormat.Ogg24Khz16BitMonoOpus,\n \"raw-48khz-16bit-mono-pcm\": SpeechSDK.SpeechSynthesisOutputFormat.Raw48Khz16BitMonoPcm,\n \"riff-48khz-16bit-mono-pcm\": SpeechSDK.SpeechSynthesisOutputFormat.Riff48Khz16BitMonoPcm,\n \"audio-48khz-96kbitrate-mono-mp3\": SpeechSDK.SpeechSynthesisOutputFormat.Audio48Khz96KBitRateMonoMp3,\n \"audio-48khz-192kbitrate-mono-mp3\": SpeechSDK.SpeechSynthesisOutputFormat.Audio48Khz192KBitRateMonoMp3,\n \"ogg-48khz-16bit-mono-opus\": SpeechSDK.SpeechSynthesisOutputFormat.Ogg48Khz16BitMonoOpus,\n \"webm-16khz-16bit-mono-opus\": SpeechSDK.SpeechSynthesisOutputFormat.Webm16Khz16BitMonoOpus,\n \"webm-24khz-16bit-mono-opus\": SpeechSDK.SpeechSynthesisOutputFormat.Webm24Khz16BitMonoOpus,\n \"webm-24khz-16bit-24kbps-mono-opus\": SpeechSDK.SpeechSynthesisOutputFormat.Webm24Khz16Bit24KbpsMonoOpus,\n \"raw-24khz-16bit-mono-truesilk\": SpeechSDK.SpeechSynthesisOutputFormat.Raw24Khz16BitMonoTrueSilk,\n \"raw-8khz-8bit-mono-alaw\": SpeechSDK.SpeechSynthesisOutputFormat.Raw8Khz8BitMonoALaw,\n \"riff-8khz-8bit-mono-alaw\": SpeechSDK.SpeechSynthesisOutputFormat.Riff8Khz8BitMonoALaw,\n \"audio-16khz-16bit-32kbps-mono-opus\": SpeechSDK.SpeechSynthesisOutputFormat.Audio16Khz16Bit32KbpsMonoOpus,\n \"audio-24khz-16bit-48kbps-mono-opus\": SpeechSDK.SpeechSynthesisOutputFormat.Audio24Khz16Bit48KbpsMonoOpus,\n \"audio-24khz-16bit-24kbps-mono-opus\": SpeechSDK.SpeechSynthesisOutputFormat.Audio24Khz16Bit24KbpsMonoOpus,\n \"raw-22050hz-16bit-mono-pcm\": SpeechSDK.SpeechSynthesisOutputFormat.Raw22050Hz16BitMonoPcm,\n \"riff-22050hz-16bit-mono-pcm\": SpeechSDK.SpeechSynthesisOutputFormat.Riff22050Hz16BitMonoPcm,\n \"raw-44100hz-16bit-mono-pcm\": SpeechSDK.SpeechSynthesisOutputFormat.Raw44100Hz16BitMonoPcm,\n \"riff-44100hz-16bit-mono-pcm\": SpeechSDK.SpeechSynthesisOutputFormat.Riff44100Hz16BitMonoPcm,\n \"amr-wb-16000hz\": SpeechSDK.SpeechSynthesisOutputFormat.AmrWb16000Hz,\n \"g722-16khz-64kbps\": SpeechSDK.SpeechSynthesisOutputFormat.G72216Khz64Kbps,\n};\n\nexport function resolveOutputFormat(outputFormat: string): SpeechSDK.SpeechSynthesisOutputFormat {\n const resolvedFormat = OUTPUT_FORMATS[outputFormat];\n if (resolvedFormat === undefined) {\n throw new Error(`Unsupported Azure Speech output format: ${outputFormat}`);\n }\n\n return resolvedFormat;\n}\n","import { synthesizeSpeech } from \"./synthesis.ts\";\nimport type { AzureTtsClientOptions } from \"./types.ts\";\n\nconst ENDPOINT_TEMPLATE = \"https://{region}.tts.speech.microsoft.com/cognitiveservices/v1\";\n\nexport class AzureTtsClient {\n readonly #options: AzureTtsClientOptions;\n\n constructor(options: AzureTtsClientOptions) {\n this.#options = options;\n }\n\n async synthesize(ssml: string): Promise<ArrayBuffer> {\n const { region, subscriptionKey, outputFormat } = this.#options;\n const endpoint = this.#options.endpoint?.trim() || ENDPOINT_TEMPLATE.replace(\"{region}\", region);\n this.#options.logger?.debug?.(\"Using Azure TTS endpoint:\", endpoint);\n\n const config = { endpoint, region, subscriptionKey, outputFormat };\n return synthesizeSpeech(ssml, config);\n }\n}\n"],"mappings":"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","names":["SpeechSDK"]}
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@ssml-builder-js/azure-tts-client",
3
+ "version": "2.4.0",
4
+ "description": "Azure Text-to-Speech client using the Microsoft Speech SDK",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/nitta-a/SSML-Builder.git",
9
+ "directory": "packages/azure-tts-client"
10
+ },
11
+ "bugs": {
12
+ "url": "https://github.com/nitta-a/SSML-Builder/issues"
13
+ },
14
+ "homepage": "https://github.com/nitta-a/SSML-Builder#azure-tts-client",
15
+ "main": "dist/index.js",
16
+ "module": "dist/index.mjs",
17
+ "types": "dist/index.d.ts",
18
+ "exports": {
19
+ ".": {
20
+ "types": "./dist/index.d.ts",
21
+ "import": "./dist/index.mjs",
22
+ "require": "./dist/index.js"
23
+ }
24
+ },
25
+ "publishConfig": {
26
+ "access": "public",
27
+ "registry": "https://registry.npmjs.org/"
28
+ },
29
+ "scripts": {
30
+ "build": "tsup",
31
+ "typecheck": "tsc --noEmit",
32
+ "test": "node --experimental-strip-types --test test/*.test.ts"
33
+ },
34
+ "devDependencies": {
35
+ "typescript": "^6.0.3"
36
+ },
37
+ "dependencies": {
38
+ "microsoft-cognitiveservices-speech-sdk": "1.51.0"
39
+ }
40
+ }
package/src/client.ts ADDED
@@ -0,0 +1,21 @@
1
+ import { synthesizeSpeech } from "./synthesis.ts";
2
+ import type { AzureTtsClientOptions } from "./types.ts";
3
+
4
+ const ENDPOINT_TEMPLATE = "https://{region}.tts.speech.microsoft.com/cognitiveservices/v1";
5
+
6
+ export class AzureTtsClient {
7
+ readonly #options: AzureTtsClientOptions;
8
+
9
+ constructor(options: AzureTtsClientOptions) {
10
+ this.#options = options;
11
+ }
12
+
13
+ async synthesize(ssml: string): Promise<ArrayBuffer> {
14
+ const { region, subscriptionKey, outputFormat } = this.#options;
15
+ const endpoint = this.#options.endpoint?.trim() || ENDPOINT_TEMPLATE.replace("{region}", region);
16
+ this.#options.logger?.debug?.("Using Azure TTS endpoint:", endpoint);
17
+
18
+ const config = { endpoint, region, subscriptionKey, outputFormat };
19
+ return synthesizeSpeech(ssml, config);
20
+ }
21
+ }
package/src/errors.ts ADDED
@@ -0,0 +1,31 @@
1
+ export class AzureTtsError extends Error {
2
+ readonly status: number;
3
+ readonly statusText: string;
4
+ readonly responseBody: string;
5
+ readonly requestId: string | null;
6
+
7
+ constructor(status: number, statusText: string, responseBody: string, requestId: string | null) {
8
+ super(`Azure TTS request failed: ${status} ${statusText}`);
9
+ this.name = "AzureTtsError";
10
+ this.status = status;
11
+ this.statusText = statusText;
12
+ this.responseBody = responseBody;
13
+ this.requestId = requestId;
14
+ }
15
+ }
16
+
17
+ export class AzureTtsSdkError extends AzureTtsError {
18
+ readonly errorDetails: string;
19
+
20
+ constructor(errorDetails: string) {
21
+ super(0, "Speech SDK", errorDetails, null);
22
+ this.name = "AzureTtsSdkError";
23
+ this.message = `Azure TTS synthesis failed: ${errorDetails}`;
24
+ this.errorDetails = errorDetails;
25
+ }
26
+ }
27
+
28
+ export function createSpeechSdkError(error: unknown): AzureTtsSdkError {
29
+ const message = error instanceof Error ? error.message : String(error);
30
+ return new AzureTtsSdkError(message);
31
+ }
package/src/index.ts ADDED
@@ -0,0 +1,8 @@
1
+ /**
2
+ * azure-tts-client: Azure Text-to-Speech client for SSML playback.
3
+ */
4
+
5
+ export type { AzureTtsClientOptions, AzureTtsLogger, TtsConfig } from "./types.ts";
6
+ export { AzureTtsError, AzureTtsSdkError } from "./errors.ts";
7
+ export { AzureTtsClient } from "./client.ts";
8
+ export { synthesizeSpeech } from "./synthesis.ts";
@@ -0,0 +1,54 @@
1
+ import * as SpeechSDK from "microsoft-cognitiveservices-speech-sdk";
2
+
3
+ export const DEFAULT_OUTPUT_FORMAT = "audio-16khz-128kbitrate-mono-mp3";
4
+
5
+ const OUTPUT_FORMATS: Record<string, SpeechSDK.SpeechSynthesisOutputFormat> = {
6
+ "raw-8khz-8bit-mono-mulaw": SpeechSDK.SpeechSynthesisOutputFormat.Raw8Khz8BitMonoMULaw,
7
+ "riff-16khz-16kbps-mono-siren": SpeechSDK.SpeechSynthesisOutputFormat.Riff16Khz16KbpsMonoSiren,
8
+ "audio-16khz-16kbps-mono-siren": SpeechSDK.SpeechSynthesisOutputFormat.Audio16Khz16KbpsMonoSiren,
9
+ "audio-16khz-32kbitrate-mono-mp3": SpeechSDK.SpeechSynthesisOutputFormat.Audio16Khz32KBitRateMonoMp3,
10
+ "audio-16khz-128kbitrate-mono-mp3": SpeechSDK.SpeechSynthesisOutputFormat.Audio16Khz128KBitRateMonoMp3,
11
+ "audio-16khz-64kbitrate-mono-mp3": SpeechSDK.SpeechSynthesisOutputFormat.Audio16Khz64KBitRateMonoMp3,
12
+ "audio-24khz-48kbitrate-mono-mp3": SpeechSDK.SpeechSynthesisOutputFormat.Audio24Khz48KBitRateMonoMp3,
13
+ "audio-24khz-96kbitrate-mono-mp3": SpeechSDK.SpeechSynthesisOutputFormat.Audio24Khz96KBitRateMonoMp3,
14
+ "audio-24khz-160kbitrate-mono-mp3": SpeechSDK.SpeechSynthesisOutputFormat.Audio24Khz160KBitRateMonoMp3,
15
+ "raw-16khz-16bit-mono-truesilk": SpeechSDK.SpeechSynthesisOutputFormat.Raw16Khz16BitMonoTrueSilk,
16
+ "riff-16khz-16bit-mono-pcm": SpeechSDK.SpeechSynthesisOutputFormat.Riff16Khz16BitMonoPcm,
17
+ "riff-8khz-16bit-mono-pcm": SpeechSDK.SpeechSynthesisOutputFormat.Riff8Khz16BitMonoPcm,
18
+ "riff-24khz-16bit-mono-pcm": SpeechSDK.SpeechSynthesisOutputFormat.Riff24Khz16BitMonoPcm,
19
+ "riff-8khz-8bit-mono-mulaw": SpeechSDK.SpeechSynthesisOutputFormat.Riff8Khz8BitMonoMULaw,
20
+ "raw-16khz-16bit-mono-pcm": SpeechSDK.SpeechSynthesisOutputFormat.Raw16Khz16BitMonoPcm,
21
+ "raw-24khz-16bit-mono-pcm": SpeechSDK.SpeechSynthesisOutputFormat.Raw24Khz16BitMonoPcm,
22
+ "raw-8khz-16bit-mono-pcm": SpeechSDK.SpeechSynthesisOutputFormat.Raw8Khz16BitMonoPcm,
23
+ "ogg-16khz-16bit-mono-opus": SpeechSDK.SpeechSynthesisOutputFormat.Ogg16Khz16BitMonoOpus,
24
+ "ogg-24khz-16bit-mono-opus": SpeechSDK.SpeechSynthesisOutputFormat.Ogg24Khz16BitMonoOpus,
25
+ "raw-48khz-16bit-mono-pcm": SpeechSDK.SpeechSynthesisOutputFormat.Raw48Khz16BitMonoPcm,
26
+ "riff-48khz-16bit-mono-pcm": SpeechSDK.SpeechSynthesisOutputFormat.Riff48Khz16BitMonoPcm,
27
+ "audio-48khz-96kbitrate-mono-mp3": SpeechSDK.SpeechSynthesisOutputFormat.Audio48Khz96KBitRateMonoMp3,
28
+ "audio-48khz-192kbitrate-mono-mp3": SpeechSDK.SpeechSynthesisOutputFormat.Audio48Khz192KBitRateMonoMp3,
29
+ "ogg-48khz-16bit-mono-opus": SpeechSDK.SpeechSynthesisOutputFormat.Ogg48Khz16BitMonoOpus,
30
+ "webm-16khz-16bit-mono-opus": SpeechSDK.SpeechSynthesisOutputFormat.Webm16Khz16BitMonoOpus,
31
+ "webm-24khz-16bit-mono-opus": SpeechSDK.SpeechSynthesisOutputFormat.Webm24Khz16BitMonoOpus,
32
+ "webm-24khz-16bit-24kbps-mono-opus": SpeechSDK.SpeechSynthesisOutputFormat.Webm24Khz16Bit24KbpsMonoOpus,
33
+ "raw-24khz-16bit-mono-truesilk": SpeechSDK.SpeechSynthesisOutputFormat.Raw24Khz16BitMonoTrueSilk,
34
+ "raw-8khz-8bit-mono-alaw": SpeechSDK.SpeechSynthesisOutputFormat.Raw8Khz8BitMonoALaw,
35
+ "riff-8khz-8bit-mono-alaw": SpeechSDK.SpeechSynthesisOutputFormat.Riff8Khz8BitMonoALaw,
36
+ "audio-16khz-16bit-32kbps-mono-opus": SpeechSDK.SpeechSynthesisOutputFormat.Audio16Khz16Bit32KbpsMonoOpus,
37
+ "audio-24khz-16bit-48kbps-mono-opus": SpeechSDK.SpeechSynthesisOutputFormat.Audio24Khz16Bit48KbpsMonoOpus,
38
+ "audio-24khz-16bit-24kbps-mono-opus": SpeechSDK.SpeechSynthesisOutputFormat.Audio24Khz16Bit24KbpsMonoOpus,
39
+ "raw-22050hz-16bit-mono-pcm": SpeechSDK.SpeechSynthesisOutputFormat.Raw22050Hz16BitMonoPcm,
40
+ "riff-22050hz-16bit-mono-pcm": SpeechSDK.SpeechSynthesisOutputFormat.Riff22050Hz16BitMonoPcm,
41
+ "raw-44100hz-16bit-mono-pcm": SpeechSDK.SpeechSynthesisOutputFormat.Raw44100Hz16BitMonoPcm,
42
+ "riff-44100hz-16bit-mono-pcm": SpeechSDK.SpeechSynthesisOutputFormat.Riff44100Hz16BitMonoPcm,
43
+ "amr-wb-16000hz": SpeechSDK.SpeechSynthesisOutputFormat.AmrWb16000Hz,
44
+ "g722-16khz-64kbps": SpeechSDK.SpeechSynthesisOutputFormat.G72216Khz64Kbps,
45
+ };
46
+
47
+ export function resolveOutputFormat(outputFormat: string): SpeechSDK.SpeechSynthesisOutputFormat {
48
+ const resolvedFormat = OUTPUT_FORMATS[outputFormat];
49
+ if (resolvedFormat === undefined) {
50
+ throw new Error(`Unsupported Azure Speech output format: ${outputFormat}`);
51
+ }
52
+
53
+ return resolvedFormat;
54
+ }
@@ -0,0 +1,17 @@
1
+ import { SpeechConfig } from "microsoft-cognitiveservices-speech-sdk";
2
+ import { DEFAULT_OUTPUT_FORMAT, resolveOutputFormat } from "./outputFormats.ts";
3
+ import type { TtsConfig } from "./types.ts";
4
+
5
+ export function resolveEndpoint(config: TtsConfig): string {
6
+ const endpoint = config.endpoint?.trim() || "https://{region}.tts.speech.microsoft.com/cognitiveservices/v1";
7
+ return endpoint.replace(/\{region\}/g, encodeURIComponent(config.region));
8
+ }
9
+
10
+ export function createSpeechConfig(config: TtsConfig): SpeechConfig {
11
+ const { outputFormat = DEFAULT_OUTPUT_FORMAT, subscriptionKey } = config;
12
+
13
+ const endpoint = new URL(resolveEndpoint(config));
14
+ const speechConfig = SpeechConfig.fromEndpoint(endpoint, subscriptionKey);
15
+ speechConfig.speechSynthesisOutputFormat = resolveOutputFormat(outputFormat);
16
+ return speechConfig;
17
+ }
@@ -0,0 +1,49 @@
1
+ import * as SpeechSDK from "microsoft-cognitiveservices-speech-sdk";
2
+ import { createSpeechSdkError } from "./errors.ts";
3
+ import { createSpeechConfig } from "./speechConfig.ts";
4
+ import type { TtsConfig } from "./types.ts";
5
+
6
+ function closeSpeechResources(speechConfig: SpeechSDK.SpeechConfig, synthesizer: SpeechSDK.SpeechSynthesizer): void {
7
+ try {
8
+ synthesizer.close();
9
+ } catch {}
10
+
11
+ try {
12
+ speechConfig.close();
13
+ } catch {}
14
+ }
15
+
16
+ export async function synthesizeSpeech(ssml: string, config: TtsConfig): Promise<ArrayBuffer> {
17
+ const speechConfig = createSpeechConfig(config);
18
+ const synthesizer = new SpeechSDK.SpeechSynthesizer(speechConfig, null);
19
+
20
+ return await new Promise<ArrayBuffer>((resolve, reject) => {
21
+ let resourcesClosed = false;
22
+ const closeResources = () => {
23
+ if (resourcesClosed) return;
24
+ resourcesClosed = true;
25
+ closeSpeechResources(speechConfig, synthesizer);
26
+ };
27
+ const rejectWithError = (error: unknown) => {
28
+ closeResources();
29
+ reject(createSpeechSdkError(error));
30
+ };
31
+
32
+ const cb = (result: SpeechSDK.SpeechSynthesisResult) => {
33
+ const { reason, errorDetails } = result;
34
+ if (reason !== SpeechSDK.ResultReason.SynthesizingAudioCompleted) {
35
+ const err = errorDetails || `Speech synthesis failed with reason ${reason}.`;
36
+ rejectWithError(err);
37
+ return;
38
+ }
39
+ closeResources();
40
+ resolve(result.audioData);
41
+ };
42
+
43
+ try {
44
+ synthesizer.speakSsmlAsync(ssml, cb, rejectWithError);
45
+ } catch (error) {
46
+ rejectWithError(error);
47
+ }
48
+ });
49
+ }
package/src/types.ts ADDED
@@ -0,0 +1,21 @@
1
+ export interface TtsConfig {
2
+ endpoint?: string;
3
+ subscriptionKey: string;
4
+ region: string;
5
+ outputFormat?: string;
6
+ }
7
+
8
+ export interface AzureTtsLogger {
9
+ debug?: (...args: unknown[]) => void;
10
+ info?: (...args: unknown[]) => void;
11
+ warn?: (...args: unknown[]) => void;
12
+ error?: (...args: unknown[]) => void;
13
+ }
14
+
15
+ export interface AzureTtsClientOptions {
16
+ subscriptionKey: string;
17
+ region: string;
18
+ endpoint?: string;
19
+ outputFormat?: string;
20
+ logger?: AzureTtsLogger;
21
+ }
@@ -0,0 +1,78 @@
1
+ import assert from "node:assert/strict";
2
+ import test, { type TestContext } from "node:test";
3
+ import * as SpeechSDK from "microsoft-cognitiveservices-speech-sdk";
4
+ import { AzureTtsClient, synthesizeSpeech } from "../src/index.ts";
5
+
6
+ function installSuccessfulSpeechSdkMock(testContext: TestContext, audio: ArrayBuffer): { endpoint?: URL } {
7
+ const captured: { endpoint?: URL } = {};
8
+ const originalFromEndpoint = SpeechSDK.SpeechConfig.fromEndpoint;
9
+
10
+ testContext.mock.method(SpeechSDK.SpeechConfig, "fromEndpoint", (endpoint, subscriptionKey) => {
11
+ captured.endpoint = endpoint;
12
+ return originalFromEndpoint(endpoint, String(subscriptionKey));
13
+ });
14
+ testContext.mock.method(SpeechSDK.SpeechSynthesizer.prototype, "speakSsmlAsync", (_ssml, callback) => {
15
+ callback?.({
16
+ audioData: audio,
17
+ errorDetails: "",
18
+ reason: SpeechSDK.ResultReason.SynthesizingAudioCompleted,
19
+ } as SpeechSDK.SpeechSynthesisResult);
20
+ });
21
+ testContext.mock.method(SpeechSDK.SpeechSynthesizer.prototype, "close", () => {});
22
+
23
+ return captured;
24
+ }
25
+
26
+ test("synthesizeSpeech replaces every endpoint region placeholder", async (t) => {
27
+ const audio = new ArrayBuffer(1);
28
+ const speechSdkMock = installSuccessfulSpeechSdkMock(t, audio);
29
+
30
+ const result = await synthesizeSpeech("<speak>Hello</speak>", {
31
+ endpoint: "https://{region}.example.test/{region}",
32
+ subscriptionKey: "subscription-key",
33
+ region: "japan-east",
34
+ });
35
+
36
+ assert.equal(speechSdkMock.endpoint?.href, "https://japan-east.example.test/japan-east");
37
+ assert.strictEqual(result, audio);
38
+ });
39
+
40
+ test("synthesizeSpeech URL-encodes special regions in endpoint paths", async (t) => {
41
+ const audio = new ArrayBuffer(1);
42
+ const speechSdkMock = installSuccessfulSpeechSdkMock(t, audio);
43
+
44
+ await synthesizeSpeech("<speak>Hello</speak>", {
45
+ endpoint: "https://speech.example.test/{region}/{region}",
46
+ subscriptionKey: "subscription-key",
47
+ region: "japan east",
48
+ });
49
+
50
+ assert.equal(speechSdkMock.endpoint?.href, "https://speech.example.test/japan%20east/japan%20east");
51
+ });
52
+
53
+ test("AzureTtsClient reports Speech SDK callback failures", async (t) => {
54
+ const errorDetails = "network unavailable";
55
+ const originalFromEndpoint = SpeechSDK.SpeechConfig.fromEndpoint;
56
+
57
+ t.mock.method(SpeechSDK.SpeechConfig, "fromEndpoint", (endpoint, subscriptionKey) =>
58
+ originalFromEndpoint(endpoint, String(subscriptionKey)),
59
+ );
60
+ t.mock.method(SpeechSDK.SpeechSynthesizer.prototype, "speakSsmlAsync", (_ssml, _callback, errorCallback) => {
61
+ errorCallback?.(errorDetails);
62
+ });
63
+ t.mock.method(SpeechSDK.SpeechSynthesizer.prototype, "close", () => {});
64
+
65
+ await assert.rejects(
66
+ new AzureTtsClient({
67
+ endpoint: "https://speech.example.test/cognitiveservices/v1",
68
+ subscriptionKey: "subscription-key",
69
+ region: "japaneast",
70
+ }).synthesize("<speak>Hello</speak>"),
71
+ (error: unknown) => {
72
+ assert.equal(error instanceof Error ? error.message : error, "Azure TTS synthesis failed: network unavailable");
73
+ assert.ok(error instanceof Error);
74
+ assert.equal(error.name, "AzureTtsSdkError");
75
+ return true;
76
+ },
77
+ );
78
+ });
@@ -0,0 +1,36 @@
1
+ import assert from "node:assert/strict";
2
+ import test from "node:test";
3
+ import { AzureTtsError, AzureTtsSdkError, createSpeechSdkError } from "../src/errors.ts";
4
+
5
+ test("AzureTtsError exposes HTTP response metadata", () => {
6
+ const error = new AzureTtsError(401, "Unauthorized", '{"error":"invalid key"}', "request-id");
7
+
8
+ assert.ok(error instanceof Error);
9
+ assert.equal(error.name, "AzureTtsError");
10
+ assert.equal(error.message, "Azure TTS request failed: 401 Unauthorized");
11
+ assert.equal(error.status, 401);
12
+ assert.equal(error.statusText, "Unauthorized");
13
+ assert.equal(error.responseBody, '{"error":"invalid key"}');
14
+ assert.equal(error.requestId, "request-id");
15
+ });
16
+
17
+ test("AzureTtsSdkError preserves SDK error details", () => {
18
+ const error = new AzureTtsSdkError("The SSML is invalid.");
19
+
20
+ assert.ok(error instanceof AzureTtsError);
21
+ assert.equal(error.name, "AzureTtsSdkError");
22
+ assert.equal(error.message, "Azure TTS synthesis failed: The SSML is invalid.");
23
+ assert.equal(error.status, 0);
24
+ assert.equal(error.statusText, "Speech SDK");
25
+ assert.equal(error.responseBody, "The SSML is invalid.");
26
+ assert.equal(error.requestId, null);
27
+ assert.equal(error.errorDetails, "The SSML is invalid.");
28
+ });
29
+
30
+ test("createSpeechSdkError normalizes Error and unknown values", () => {
31
+ assert.equal(
32
+ createSpeechSdkError(new Error("network unavailable")).message,
33
+ "Azure TTS synthesis failed: network unavailable",
34
+ );
35
+ assert.equal(createSpeechSdkError("request failed").errorDetails, "request failed");
36
+ });
@@ -0,0 +1,139 @@
1
+ import assert from "node:assert/strict";
2
+ import test, { type TestContext } from "node:test";
3
+ import * as SpeechSDK from "microsoft-cognitiveservices-speech-sdk";
4
+ import { AzureTtsClient, AzureTtsError, AzureTtsSdkError, synthesizeSpeech } from "../src/index.ts";
5
+
6
+ type SpeechSdkMock = {
7
+ endpoint?: URL;
8
+ subscriptionKey?: string;
9
+ speechConfig?: SpeechSDK.SpeechConfig;
10
+ ssml?: string;
11
+ closeCount: number;
12
+ };
13
+
14
+ function installSpeechSdkMock(testContext: TestContext, audio: ArrayBuffer): SpeechSdkMock {
15
+ const captured: SpeechSdkMock = { closeCount: 0 };
16
+ const originalFromEndpoint = SpeechSDK.SpeechConfig.fromEndpoint;
17
+
18
+ testContext.mock.method(SpeechSDK.SpeechConfig, "fromEndpoint", (endpoint, subscriptionKey) => {
19
+ captured.endpoint = endpoint;
20
+ captured.subscriptionKey = String(subscriptionKey);
21
+ const speechConfig = originalFromEndpoint(endpoint, String(subscriptionKey));
22
+ captured.speechConfig = speechConfig;
23
+ return speechConfig;
24
+ });
25
+ testContext.mock.method(SpeechSDK.SpeechSynthesizer.prototype, "speakSsmlAsync", (ssml, callback) => {
26
+ captured.ssml = ssml;
27
+ callback?.({
28
+ audioData: audio,
29
+ errorDetails: "",
30
+ reason: SpeechSDK.ResultReason.SynthesizingAudioCompleted,
31
+ } as SpeechSDK.SpeechSynthesisResult);
32
+ });
33
+ testContext.mock.method(SpeechSDK.SpeechSynthesizer.prototype, "close", () => {
34
+ captured.closeCount += 1;
35
+ });
36
+
37
+ return captured;
38
+ }
39
+
40
+ function installSpeechSdkErrorMock(testContext: TestContext, errorDetails: string): SpeechSdkMock {
41
+ const captured = installSpeechSdkMock(testContext, new ArrayBuffer(0));
42
+ testContext.mock.method(SpeechSDK.SpeechSynthesizer.prototype, "speakSsmlAsync", (ssml, _callback, errorCallback) => {
43
+ captured.ssml = ssml;
44
+ errorCallback?.(errorDetails);
45
+ });
46
+ return captured;
47
+ }
48
+
49
+ test("synthesizeSpeech sends SSML using the Speech SDK", async (t) => {
50
+ const mockAudio = new ArrayBuffer(3);
51
+ new Uint8Array(mockAudio).set([4, 5, 6]);
52
+ const speechSdkMock = installSpeechSdkMock(t, mockAudio);
53
+ const ssml = "<speak>Hello</speak>";
54
+
55
+ const audio = await synthesizeSpeech(ssml, {
56
+ endpoint: "https://speech.example.test/cognitiveservices/v1",
57
+ subscriptionKey: "subscription-key",
58
+ region: "japaneast",
59
+ });
60
+
61
+ assert.equal(speechSdkMock.endpoint?.href, "https://speech.example.test/cognitiveservices/v1");
62
+ assert.equal(speechSdkMock.subscriptionKey, "subscription-key");
63
+ assert.equal(speechSdkMock.ssml, ssml);
64
+ assert.equal(
65
+ speechSdkMock.speechConfig?.speechSynthesisOutputFormat,
66
+ SpeechSDK.SpeechSynthesisOutputFormat.Audio16Khz128KBitRateMonoMp3,
67
+ );
68
+ assert.strictEqual(audio, mockAudio);
69
+ assert.equal(speechSdkMock.closeCount, 1);
70
+ });
71
+
72
+ test("synthesize uses the configured output format", async (t) => {
73
+ const mockAudio = new ArrayBuffer(3);
74
+ const speechSdkMock = installSpeechSdkMock(t, mockAudio);
75
+ const ssml = "<speak>Hello</speak>";
76
+
77
+ const audio = await new AzureTtsClient({
78
+ subscriptionKey: "subscription-key",
79
+ region: "japaneast",
80
+ outputFormat: "audio-24khz-160kbitrate-mono-mp3",
81
+ }).synthesize(ssml);
82
+
83
+ assert.equal(
84
+ speechSdkMock.speechConfig?.speechSynthesisOutputFormat,
85
+ SpeechSDK.SpeechSynthesisOutputFormat.Audio24Khz160KBitRateMonoMp3,
86
+ );
87
+ assert.strictEqual(audio, mockAudio);
88
+ });
89
+
90
+ test("synthesize sends SSML to the regional Azure endpoint", async (t) => {
91
+ const mockAudio = new ArrayBuffer(3);
92
+ const speechSdkMock = installSpeechSdkMock(t, mockAudio);
93
+ const ssml = "<speak>Hello</speak>";
94
+
95
+ const audio = await new AzureTtsClient({
96
+ subscriptionKey: "subscription-key",
97
+ region: "japaneast",
98
+ }).synthesize(ssml);
99
+
100
+ assert.equal(speechSdkMock.endpoint?.href, "https://japaneast.tts.speech.microsoft.com/cognitiveservices/v1");
101
+ assert.equal(speechSdkMock.ssml, ssml);
102
+ assert.strictEqual(audio, mockAudio);
103
+ });
104
+
105
+ test("synthesize falls back when endpoint is an empty string", async (t) => {
106
+ const mockAudio = new ArrayBuffer(1);
107
+ const speechSdkMock = installSpeechSdkMock(t, mockAudio);
108
+
109
+ await new AzureTtsClient({
110
+ endpoint: " ",
111
+ subscriptionKey: "subscription-key",
112
+ region: "japaneast",
113
+ }).synthesize("<speak>Hello</speak>");
114
+
115
+ assert.equal(speechSdkMock.endpoint?.href, "https://japaneast.tts.speech.microsoft.com/cognitiveservices/v1");
116
+ });
117
+
118
+ test("synthesize reports Speech SDK synthesis errors", async (t) => {
119
+ const errorDetails = "The SSML is invalid.";
120
+ installSpeechSdkErrorMock(t, errorDetails);
121
+
122
+ await assert.rejects(
123
+ new AzureTtsClient({
124
+ subscriptionKey: "subscription-key",
125
+ region: "japaneast",
126
+ }).synthesize("<speak>Hello</speak>"),
127
+ (error: unknown) => {
128
+ assert.ok(error instanceof AzureTtsError);
129
+ assert.ok(error instanceof AzureTtsSdkError);
130
+ assert.equal(error.message, "Azure TTS synthesis failed: The SSML is invalid.");
131
+ assert.equal(error.status, 0);
132
+ assert.equal(error.statusText, "Speech SDK");
133
+ assert.equal(error.responseBody, errorDetails);
134
+ assert.equal(error.requestId, null);
135
+ assert.equal(error.errorDetails, errorDetails);
136
+ return true;
137
+ },
138
+ );
139
+ });
@@ -0,0 +1,30 @@
1
+ import assert from "node:assert/strict";
2
+ import test from "node:test";
3
+ import * as SpeechSDK from "microsoft-cognitiveservices-speech-sdk";
4
+ import { DEFAULT_OUTPUT_FORMAT, resolveOutputFormat } from "../src/outputFormats.ts";
5
+
6
+ test("defines the default Azure Speech output format", () => {
7
+ assert.equal(DEFAULT_OUTPUT_FORMAT, "audio-16khz-128kbitrate-mono-mp3");
8
+ assert.equal(
9
+ resolveOutputFormat(DEFAULT_OUTPUT_FORMAT),
10
+ SpeechSDK.SpeechSynthesisOutputFormat.Audio16Khz128KBitRateMonoMp3,
11
+ );
12
+ });
13
+
14
+ test("resolves supported output formats", () => {
15
+ assert.equal(
16
+ resolveOutputFormat("audio-24khz-160kbitrate-mono-mp3"),
17
+ SpeechSDK.SpeechSynthesisOutputFormat.Audio24Khz160KBitRateMonoMp3,
18
+ );
19
+ assert.equal(
20
+ resolveOutputFormat("ogg-48khz-16bit-mono-opus"),
21
+ SpeechSDK.SpeechSynthesisOutputFormat.Ogg48Khz16BitMonoOpus,
22
+ );
23
+ });
24
+
25
+ test("rejects unsupported output formats", () => {
26
+ assert.throws(
27
+ () => resolveOutputFormat("unsupported-format"),
28
+ new Error("Unsupported Azure Speech output format: unsupported-format"),
29
+ );
30
+ });
@@ -0,0 +1,61 @@
1
+ import assert from "node:assert/strict";
2
+ import test from "node:test";
3
+ import * as SpeechSDK from "microsoft-cognitiveservices-speech-sdk";
4
+ import { createSpeechConfig, resolveEndpoint } from "../src/speechConfig.ts";
5
+
6
+ test("replaces and URL-encodes every endpoint region placeholder", () => {
7
+ assert.equal(
8
+ resolveEndpoint({
9
+ endpoint: "https://{region}.example.test/{region}",
10
+ subscriptionKey: "subscription-key",
11
+ region: "japan east",
12
+ }),
13
+ "https://japan%20east.example.test/japan%20east",
14
+ );
15
+ });
16
+
17
+ test("falls back to the regional endpoint for empty endpoint values", () => {
18
+ assert.equal(
19
+ resolveEndpoint({
20
+ endpoint: " ",
21
+ subscriptionKey: "subscription-key",
22
+ region: "japaneast",
23
+ }),
24
+ "https://japaneast.tts.speech.microsoft.com/cognitiveservices/v1",
25
+ );
26
+ });
27
+
28
+ test("creates Speech SDK configuration with the default format", () => {
29
+ const speechConfig = createSpeechConfig({
30
+ endpoint: "https://speech.example.test/cognitiveservices/v1",
31
+ subscriptionKey: "subscription-key",
32
+ region: "japaneast",
33
+ });
34
+
35
+ try {
36
+ assert.equal(
37
+ speechConfig.speechSynthesisOutputFormat,
38
+ SpeechSDK.SpeechSynthesisOutputFormat.Audio16Khz128KBitRateMonoMp3,
39
+ );
40
+ } finally {
41
+ speechConfig.close();
42
+ }
43
+ });
44
+
45
+ test("creates Speech SDK configuration with a custom format", () => {
46
+ const speechConfig = createSpeechConfig({
47
+ endpoint: "https://speech.example.test/cognitiveservices/v1",
48
+ subscriptionKey: "subscription-key",
49
+ region: "japaneast",
50
+ outputFormat: "raw-22050hz-16bit-mono-pcm",
51
+ });
52
+
53
+ try {
54
+ assert.equal(
55
+ speechConfig.speechSynthesisOutputFormat,
56
+ SpeechSDK.SpeechSynthesisOutputFormat.Raw22050Hz16BitMonoPcm,
57
+ );
58
+ } finally {
59
+ speechConfig.close();
60
+ }
61
+ });
package/tsconfig.json ADDED
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "dist",
5
+ "rootDir": "src",
6
+ "rewriteRelativeImportExtensions": true
7
+ },
8
+ "include": ["src"]
9
+ }
package/tsup.config.ts ADDED
@@ -0,0 +1,14 @@
1
+ import { defineConfig } from "tsup";
2
+
3
+ export default defineConfig({
4
+ entry: ["src/index.ts"],
5
+ format: ["esm", "cjs"],
6
+ dts: {
7
+ compilerOptions: {
8
+ composite: false,
9
+ ignoreDeprecations: "6.0",
10
+ },
11
+ },
12
+ sourcemap: true,
13
+ clean: true,
14
+ });