@speech-sdk/core 0.6.1 → 0.7.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.
Files changed (130) hide show
  1. package/LICENSE +202 -21
  2. package/README.md +215 -269
  3. package/dist/__tests__/e2e/_save-audio.d.ts +51 -2
  4. package/dist/__tests__/e2e/_save-audio.d.ts.map +1 -1
  5. package/dist/__tests__/e2e/_save-audio.js +139 -11
  6. package/dist/__tests__/e2e/_save-audio.js.map +1 -1
  7. package/dist/audio-utils.d.ts +2 -0
  8. package/dist/audio-utils.d.ts.map +1 -1
  9. package/dist/audio-utils.js +9 -0
  10. package/dist/audio-utils.js.map +1 -1
  11. package/dist/captions.d.ts +137 -0
  12. package/dist/captions.d.ts.map +1 -0
  13. package/dist/captions.js +283 -0
  14. package/dist/captions.js.map +1 -0
  15. package/dist/conversation/stitch.d.ts +5 -0
  16. package/dist/conversation/stitch.d.ts.map +1 -1
  17. package/dist/conversation/stitch.js +37 -0
  18. package/dist/conversation/stitch.js.map +1 -1
  19. package/dist/conversation/types.d.ts +16 -0
  20. package/dist/conversation/types.d.ts.map +1 -1
  21. package/dist/conversation/validate.d.ts.map +1 -1
  22. package/dist/conversation/validate.js +0 -6
  23. package/dist/conversation/validate.js.map +1 -1
  24. package/dist/derive-timestamps.d.ts +14 -0
  25. package/dist/derive-timestamps.d.ts.map +1 -0
  26. package/dist/derive-timestamps.js +38 -0
  27. package/dist/derive-timestamps.js.map +1 -0
  28. package/dist/errors.d.ts +25 -0
  29. package/dist/errors.d.ts.map +1 -1
  30. package/dist/errors.js +28 -0
  31. package/dist/errors.js.map +1 -1
  32. package/dist/generate-conversation.d.ts +2 -1
  33. package/dist/generate-conversation.d.ts.map +1 -1
  34. package/dist/generate-conversation.js +72 -0
  35. package/dist/generate-conversation.js.map +1 -1
  36. package/dist/generate-speech.d.ts +18 -1
  37. package/dist/generate-speech.d.ts.map +1 -1
  38. package/dist/generate-speech.js +73 -16
  39. package/dist/generate-speech.js.map +1 -1
  40. package/dist/index.d.ts +6 -2
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +2 -1
  43. package/dist/index.js.map +1 -1
  44. package/dist/logger.d.ts +2 -0
  45. package/dist/logger.d.ts.map +1 -0
  46. package/dist/logger.js +40 -0
  47. package/dist/logger.js.map +1 -0
  48. package/dist/provider-utils.d.ts +8 -0
  49. package/dist/provider-utils.d.ts.map +1 -1
  50. package/dist/provider-utils.js +16 -2
  51. package/dist/provider-utils.js.map +1 -1
  52. package/dist/providers/cartesia/alignment.d.ts +24 -0
  53. package/dist/providers/cartesia/alignment.d.ts.map +1 -0
  54. package/dist/providers/cartesia/alignment.js +23 -0
  55. package/dist/providers/cartesia/alignment.js.map +1 -0
  56. package/dist/providers/cartesia/index.d.ts +12 -2
  57. package/dist/providers/cartesia/index.d.ts.map +1 -1
  58. package/dist/providers/cartesia/index.js +137 -2
  59. package/dist/providers/cartesia/index.js.map +1 -1
  60. package/dist/providers/elevenlabs/alignment.d.ts +24 -0
  61. package/dist/providers/elevenlabs/alignment.d.ts.map +1 -0
  62. package/dist/providers/elevenlabs/alignment.js +48 -0
  63. package/dist/providers/elevenlabs/alignment.js.map +1 -0
  64. package/dist/providers/elevenlabs/index.d.ts +19 -4
  65. package/dist/providers/elevenlabs/index.d.ts.map +1 -1
  66. package/dist/providers/elevenlabs/index.js +83 -13
  67. package/dist/providers/elevenlabs/index.js.map +1 -1
  68. package/dist/providers/fal/index.d.ts +0 -25
  69. package/dist/providers/fal/index.d.ts.map +1 -1
  70. package/dist/providers/fal/index.js +3 -58
  71. package/dist/providers/fal/index.js.map +1 -1
  72. package/dist/providers/hume/alignment.d.ts +38 -0
  73. package/dist/providers/hume/alignment.d.ts.map +1 -0
  74. package/dist/providers/hume/alignment.js +31 -0
  75. package/dist/providers/hume/alignment.js.map +1 -0
  76. package/dist/providers/hume/index.d.ts +8 -1
  77. package/dist/providers/hume/index.d.ts.map +1 -1
  78. package/dist/providers/hume/index.js +75 -1
  79. package/dist/providers/hume/index.js.map +1 -1
  80. package/dist/providers/inworld/alignment.d.ts +25 -0
  81. package/dist/providers/inworld/alignment.d.ts.map +1 -0
  82. package/dist/providers/inworld/alignment.js +23 -0
  83. package/dist/providers/inworld/alignment.js.map +1 -0
  84. package/dist/providers/inworld/index.d.ts +11 -2
  85. package/dist/providers/inworld/index.d.ts.map +1 -1
  86. package/dist/providers/inworld/index.js +11 -2
  87. package/dist/providers/inworld/index.js.map +1 -1
  88. package/dist/providers/murf/alignment.d.ts +22 -0
  89. package/dist/providers/murf/alignment.d.ts.map +1 -0
  90. package/dist/providers/murf/alignment.js +17 -0
  91. package/dist/providers/murf/alignment.js.map +1 -0
  92. package/dist/providers/murf/index.d.ts +8 -1
  93. package/dist/providers/murf/index.d.ts.map +1 -1
  94. package/dist/providers/murf/index.js +10 -1
  95. package/dist/providers/murf/index.js.map +1 -1
  96. package/dist/providers/openai/index.d.ts +12 -3
  97. package/dist/providers/openai/index.d.ts.map +1 -1
  98. package/dist/providers/openai/index.js +7 -3
  99. package/dist/providers/openai/index.js.map +1 -1
  100. package/dist/providers/resemble/alignment.d.ts +32 -0
  101. package/dist/providers/resemble/alignment.d.ts.map +1 -0
  102. package/dist/providers/resemble/alignment.js +57 -0
  103. package/dist/providers/resemble/alignment.js.map +1 -0
  104. package/dist/providers/resemble/index.d.ts +7 -1
  105. package/dist/providers/resemble/index.d.ts.map +1 -1
  106. package/dist/providers/resemble/index.js +13 -1
  107. package/dist/providers/resemble/index.js.map +1 -1
  108. package/dist/resolve-provider.d.ts.map +1 -1
  109. package/dist/resolve-provider.js +3 -12
  110. package/dist/resolve-provider.js.map +1 -1
  111. package/dist/speech-provider.d.ts +48 -4
  112. package/dist/speech-provider.d.ts.map +1 -1
  113. package/dist/speech-provider.js +16 -0
  114. package/dist/speech-provider.js.map +1 -1
  115. package/dist/speech-result.d.ts +10 -0
  116. package/dist/speech-result.d.ts.map +1 -1
  117. package/dist/speech-result.js.map +1 -1
  118. package/dist/speech-to-text-provider.d.ts +40 -0
  119. package/dist/speech-to-text-provider.d.ts.map +1 -0
  120. package/dist/speech-to-text-provider.js +2 -0
  121. package/dist/speech-to-text-provider.js.map +1 -0
  122. package/dist/stt-providers/openai/index.d.ts +42 -0
  123. package/dist/stt-providers/openai/index.d.ts.map +1 -0
  124. package/dist/stt-providers/openai/index.js +184 -0
  125. package/dist/stt-providers/openai/index.js.map +1 -0
  126. package/dist/timestamps.d.ts +23 -0
  127. package/dist/timestamps.d.ts.map +1 -0
  128. package/dist/timestamps.js +2 -0
  129. package/dist/timestamps.js.map +1 -0
  130. package/package.json +6 -2
@@ -1,11 +1,60 @@
1
+ import { generateConversation as _generateConversation } from "../../generate-conversation.js";
2
+ import { generateSpeech as _generateSpeech } from "../../generate-speech.js";
3
+ import type { WordTimestamp } from "../../timestamps.js";
1
4
  /**
2
5
  * Write a test-generated audio file to `SPEECH_SDK_E2E_OUTPUT_DIR` if the env
3
6
  * var is set. No-op otherwise, so normal CI runs don't produce artifacts.
4
- * Intended to let conversation e2e tests double as a way to sample provider
5
- * output (e.g. `SPEECH_SDK_E2E_OUTPUT_DIR=~/Downloads/convos pnpm test:e2e`).
7
+ * Usually you don't need to call this directly use the `generateSpeech`,
8
+ * `generateConversation`, and `collectStreamAndSave` helpers exported from
9
+ * this module, which autosave using the current test name.
10
+ *
11
+ * Output layout: `$SPEECH_SDK_E2E_OUTPUT_DIR/<provider-file>/<test-slug>.<ext>`.
12
+ * If the same test saves multiple times, subsequent files are suffixed `-2`,
13
+ * `-3`, etc.
6
14
  */
7
15
  export declare function maybeSaveAudio(name: string, audio: {
8
16
  uint8Array: Uint8Array;
9
17
  mediaType: string;
10
18
  }): Promise<void>;
19
+ /**
20
+ * Like {@link maybeSaveAudio}, plus — when `timestamps` is non-empty — also
21
+ * writes the raw alignment JSON and rendered SRT/VTT caption files alongside
22
+ * the audio. All four files share the same stem so they stay paired across
23
+ * multi-call tests. Still a no-op when `SPEECH_SDK_E2E_OUTPUT_DIR` is unset.
24
+ *
25
+ * Output layout (when timestamps present):
26
+ * ```
27
+ * <dir>/<bucket>/<slug>.<audio-ext>
28
+ * <dir>/<bucket>/<slug>.timestamps.json
29
+ * <dir>/<bucket>/<slug>.srt
30
+ * <dir>/<bucket>/<slug>.vtt
31
+ * ```
32
+ */
33
+ export declare function maybeSaveResult(name: string, audio: {
34
+ uint8Array: Uint8Array;
35
+ mediaType: string;
36
+ }, timestamps?: readonly WordTimestamp[]): Promise<void>;
37
+ /**
38
+ * Drop-in replacement for `generateSpeech` that autosaves to
39
+ * `SPEECH_SDK_E2E_OUTPUT_DIR` using the current vitest test name. When the
40
+ * result includes word timestamps, also writes paired `.timestamps.json`,
41
+ * `.srt`, and `.vtt` files.
42
+ */
43
+ export declare const generateSpeech: typeof _generateSpeech;
44
+ /**
45
+ * Drop-in replacement for `generateConversation` that autosaves to
46
+ * `SPEECH_SDK_E2E_OUTPUT_DIR` using the current vitest test name. When the
47
+ * result includes word timestamps, also writes paired `.timestamps.json`,
48
+ * `.srt`, and `.vtt` files.
49
+ */
50
+ export declare const generateConversation: typeof _generateConversation;
51
+ /**
52
+ * Collects a streamed `streamSpeech` result into bytes AND autosaves them to
53
+ * `SPEECH_SDK_E2E_OUTPUT_DIR` using the current vitest test name. Use in place
54
+ * of `collectStream(result.audio)` in e2e tests.
55
+ */
56
+ export declare function collectStreamAndSave(result: {
57
+ audio: ReadableStream<Uint8Array>;
58
+ mediaType: string;
59
+ }): Promise<Uint8Array>;
11
60
  //# sourceMappingURL=_save-audio.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"_save-audio.d.ts","sourceRoot":"","sources":["../../../src/__tests__/e2e/_save-audio.ts"],"names":[],"mappings":"AAyBA;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE;IAAE,UAAU,EAAE,UAAU,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACnD,OAAO,CAAC,IAAI,CAAC,CAYf"}
1
+ {"version":3,"file":"_save-audio.d.ts","sourceRoot":"","sources":["../../../src/__tests__/e2e/_save-audio.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,oBAAoB,IAAI,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAC/F,OAAO,EAAE,cAAc,IAAI,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC7E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AA8FzD;;;;;;;;;;GAUG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE;IAAE,UAAU,EAAE,UAAU,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACnD,OAAO,CAAC,IAAI,CAAC,CAEf;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE;IAAE,UAAU,EAAE,UAAU,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,EACpD,UAAU,CAAC,EAAE,SAAS,aAAa,EAAE,GACpC,OAAO,CAAC,IAAI,CAAC,CA8Bf;AAOD;;;;;GAKG;AACH,eAAO,MAAM,cAAc,EAAE,OAAO,eAMR,CAAC;AAE7B;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,EAAE,OAAO,qBAMR,CAAC;AAEnC;;;;GAIG;AACH,wBAAsB,oBAAoB,CAAC,MAAM,EAAE;IACjD,KAAK,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;IAClC,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC,UAAU,CAAC,CAOtB"}
@@ -1,5 +1,10 @@
1
1
  import { mkdir, writeFile } from "node:fs/promises";
2
- import { join } from "node:path";
2
+ import { basename, join } from "node:path";
3
+ import { expect } from "vitest";
4
+ import { timestampsToCaptions } from "../../captions.js";
5
+ import { generateConversation as _generateConversation } from "../../generate-conversation.js";
6
+ import { generateSpeech as _generateSpeech } from "../../generate-speech.js";
7
+ import { collectStream } from "./_collect-stream.js";
3
8
  function extFor(mediaType) {
4
9
  if (mediaType.includes("wav")) {
5
10
  return "wav";
@@ -21,23 +26,146 @@ function extFor(mediaType) {
21
26
  }
22
27
  return "bin";
23
28
  }
29
+ const NON_SLUG_CHARS = /[^a-zA-Z0-9._-]+/g;
30
+ const LEADING_OR_TRAILING_UNDERSCORES = /^_+|_+$/g;
31
+ const E2E_TEST_SUFFIX = /\.e2e\.test\.(ts|tsx|js|mjs)$/;
32
+ function slugify(name) {
33
+ return name
34
+ .replace(NON_SLUG_CHARS, "_")
35
+ .replace(LEADING_OR_TRAILING_UNDERSCORES, "");
36
+ }
37
+ function resolveOutputDir() {
38
+ const dir = process.env.SPEECH_SDK_E2E_OUTPUT_DIR;
39
+ if (!dir) {
40
+ return null;
41
+ }
42
+ return dir.startsWith("~") ? join(process.env.HOME ?? "", dir.slice(1)) : dir;
43
+ }
44
+ function currentTestContext() {
45
+ // biome-ignore lint/suspicious/noMisplacedAssertion: reading vitest state, not asserting
46
+ const state = expect.getState();
47
+ return {
48
+ currentTestName: state.currentTestName,
49
+ testPath: state.testPath,
50
+ };
51
+ }
52
+ /**
53
+ * Derives the subdirectory for a given test file. e2e tests are named like
54
+ * `openai.e2e.test.ts` / `conversation-google.e2e.test.ts`; we strip the
55
+ * `.e2e.test.ts` suffix and use that as the per-provider bucket so a full run
56
+ * doesn't dump 100+ files into a single flat directory.
57
+ */
58
+ function providerBucket(testPath) {
59
+ if (!testPath) {
60
+ return "unknown";
61
+ }
62
+ const base = basename(testPath).replace(E2E_TEST_SUFFIX, "");
63
+ return slugify(base) || "unknown";
64
+ }
65
+ // Counter keyed by `${bucket}/${slug}` so multiple generate/stream calls
66
+ // within a single test don't overwrite each other. Vitest isolates modules
67
+ // per file, so this resets per test file — collisions are only meaningful
68
+ // within the same `it`.
69
+ const callCounts = new Map();
70
+ /**
71
+ * Reserves a filename stem (without extension) for the next save call.
72
+ * First call returns `slug`; subsequent calls return `slug-2`, `slug-3`, etc.
73
+ * A single stem is shared across all sibling outputs from one logical save
74
+ * (audio + timestamps + captions), so they remain paired even across
75
+ * multiple saves within the same test.
76
+ */
77
+ function nextStem(bucket, slug) {
78
+ const key = `${bucket}/${slug}`;
79
+ const n = (callCounts.get(key) ?? 0) + 1;
80
+ callCounts.set(key, n);
81
+ return n === 1 ? slug : `${slug}-${n}`;
82
+ }
83
+ async function writeAndLog(file, data) {
84
+ await writeFile(file, data);
85
+ console.log(`[e2e-save] wrote ${file}`);
86
+ }
24
87
  /**
25
88
  * Write a test-generated audio file to `SPEECH_SDK_E2E_OUTPUT_DIR` if the env
26
89
  * var is set. No-op otherwise, so normal CI runs don't produce artifacts.
27
- * Intended to let conversation e2e tests double as a way to sample provider
28
- * output (e.g. `SPEECH_SDK_E2E_OUTPUT_DIR=~/Downloads/convos pnpm test:e2e`).
90
+ * Usually you don't need to call this directly use the `generateSpeech`,
91
+ * `generateConversation`, and `collectStreamAndSave` helpers exported from
92
+ * this module, which autosave using the current test name.
93
+ *
94
+ * Output layout: `$SPEECH_SDK_E2E_OUTPUT_DIR/<provider-file>/<test-slug>.<ext>`.
95
+ * If the same test saves multiple times, subsequent files are suffixed `-2`,
96
+ * `-3`, etc.
29
97
  */
30
98
  export async function maybeSaveAudio(name, audio) {
31
- const dir = process.env.SPEECH_SDK_E2E_OUTPUT_DIR;
99
+ await maybeSaveResult(name, audio);
100
+ }
101
+ /**
102
+ * Like {@link maybeSaveAudio}, plus — when `timestamps` is non-empty — also
103
+ * writes the raw alignment JSON and rendered SRT/VTT caption files alongside
104
+ * the audio. All four files share the same stem so they stay paired across
105
+ * multi-call tests. Still a no-op when `SPEECH_SDK_E2E_OUTPUT_DIR` is unset.
106
+ *
107
+ * Output layout (when timestamps present):
108
+ * ```
109
+ * <dir>/<bucket>/<slug>.<audio-ext>
110
+ * <dir>/<bucket>/<slug>.timestamps.json
111
+ * <dir>/<bucket>/<slug>.srt
112
+ * <dir>/<bucket>/<slug>.vtt
113
+ * ```
114
+ */
115
+ export async function maybeSaveResult(name, audio, timestamps) {
116
+ const dir = resolveOutputDir();
32
117
  if (!dir) {
33
118
  return;
34
119
  }
35
- const expanded = dir.startsWith("~")
36
- ? join(process.env.HOME ?? "", dir.slice(1))
37
- : dir;
38
- await mkdir(expanded, { recursive: true });
39
- const file = join(expanded, `${name}.${extFor(audio.mediaType)}`);
40
- await writeFile(file, audio.uint8Array);
41
- console.log(`[maybeSaveAudio] wrote ${file}`);
120
+ const { testPath } = currentTestContext();
121
+ const bucket = providerBucket(testPath);
122
+ const bucketDir = join(dir, bucket);
123
+ await mkdir(bucketDir, { recursive: true });
124
+ const stem = nextStem(bucket, slugify(name));
125
+ await writeAndLog(join(bucketDir, `${stem}.${extFor(audio.mediaType)}`), audio.uint8Array);
126
+ if (timestamps && timestamps.length > 0) {
127
+ await writeAndLog(join(bucketDir, `${stem}.timestamps.json`), `${JSON.stringify(timestamps, null, 2)}\n`);
128
+ await writeAndLog(join(bucketDir, `${stem}.srt`), timestampsToCaptions(timestamps));
129
+ await writeAndLog(join(bucketDir, `${stem}.vtt`), timestampsToCaptions(timestamps, { format: "vtt" }));
130
+ }
131
+ }
132
+ function currentTestSlug() {
133
+ const { currentTestName } = currentTestContext();
134
+ return slugify(currentTestName ?? "unnamed") || "unnamed";
135
+ }
136
+ /**
137
+ * Drop-in replacement for `generateSpeech` that autosaves to
138
+ * `SPEECH_SDK_E2E_OUTPUT_DIR` using the current vitest test name. When the
139
+ * result includes word timestamps, also writes paired `.timestamps.json`,
140
+ * `.srt`, and `.vtt` files.
141
+ */
142
+ export const generateSpeech = (async (options) => {
143
+ const result = await _generateSpeech(options);
144
+ await maybeSaveResult(currentTestSlug(), result.audio, result.timestamps);
145
+ return result;
146
+ });
147
+ /**
148
+ * Drop-in replacement for `generateConversation` that autosaves to
149
+ * `SPEECH_SDK_E2E_OUTPUT_DIR` using the current vitest test name. When the
150
+ * result includes word timestamps, also writes paired `.timestamps.json`,
151
+ * `.srt`, and `.vtt` files.
152
+ */
153
+ export const generateConversation = (async (options) => {
154
+ const result = await _generateConversation(options);
155
+ await maybeSaveResult(currentTestSlug(), result.audio, result.timestamps);
156
+ return result;
157
+ });
158
+ /**
159
+ * Collects a streamed `streamSpeech` result into bytes AND autosaves them to
160
+ * `SPEECH_SDK_E2E_OUTPUT_DIR` using the current vitest test name. Use in place
161
+ * of `collectStream(result.audio)` in e2e tests.
162
+ */
163
+ export async function collectStreamAndSave(result) {
164
+ const bytes = await collectStream(result.audio);
165
+ await maybeSaveAudio(currentTestSlug(), {
166
+ uint8Array: bytes,
167
+ mediaType: result.mediaType,
168
+ });
169
+ return bytes;
42
170
  }
43
171
  //# sourceMappingURL=_save-audio.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"_save-audio.js","sourceRoot":"","sources":["../../../src/__tests__/e2e/_save-audio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,SAAS,MAAM,CAAC,SAAiB;IAC/B,IAAI,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5D,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QAC/B,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,IAAI,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QAC/B,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,IAAI,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,IAAY,EACZ,KAAoD;IAEpD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC;IAClD,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,OAAO;IACT,CAAC;IACD,MAAM,QAAQ,GAAG,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC;QAClC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC5C,CAAC,CAAC,GAAG,CAAC;IACR,MAAM,KAAK,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3C,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IAClE,MAAM,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;IACxC,OAAO,CAAC,GAAG,CAAC,0BAA0B,IAAI,EAAE,CAAC,CAAC;AAChD,CAAC"}
1
+ {"version":3,"file":"_save-audio.js","sourceRoot":"","sources":["../../../src/__tests__/e2e/_save-audio.ts"],"names":[],"mappings":"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"}
@@ -9,4 +9,6 @@ export declare function parseMediaTypeParam(mediaType: string, name: string): nu
9
9
  * does not require the WebCodecs encoder.
10
10
  */
11
11
  export declare function wrapPcm16Mono(pcm: Uint8Array, sampleRate: number): Promise<Uint8Array>;
12
+ /** Decode a base64 string into raw bytes. */
13
+ export declare function base64ToUint8Array(b64: string): Uint8Array;
12
14
  //# sourceMappingURL=audio-utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"audio-utils.d.ts","sourceRoot":"","sources":["../src/audio-utils.ts"],"names":[],"mappings":"AAUA;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,GACX,MAAM,GAAG,SAAS,CAcpB;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,UAAU,EACf,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,UAAU,CAAC,CA2BrB"}
1
+ {"version":3,"file":"audio-utils.d.ts","sourceRoot":"","sources":["../src/audio-utils.ts"],"names":[],"mappings":"AAUA;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,GACX,MAAM,GAAG,SAAS,CAcpB;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,UAAU,EACf,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,UAAU,CAAC,CA2BrB;AAED,6CAA6C;AAC7C,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAO1D"}
@@ -50,4 +50,13 @@ export async function wrapPcm16Mono(pcm, sampleRate) {
50
50
  }
51
51
  return new Uint8Array(buffer);
52
52
  }
53
+ /** Decode a base64 string into raw bytes. */
54
+ export function base64ToUint8Array(b64) {
55
+ const binary = atob(b64);
56
+ const bytes = new Uint8Array(binary.length);
57
+ for (let i = 0; i < binary.length; i++) {
58
+ bytes[i] = binary.charCodeAt(i);
59
+ }
60
+ return bytes;
61
+ }
53
62
  //# sourceMappingURL=audio-utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"audio-utils.js","sourceRoot":"","sources":["../src/audio-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,wBAAwB,EACxB,aAAa,EACb,MAAM,EACN,eAAe,GAChB,MAAM,YAAY,CAAC;AAEpB,MAAM,iBAAiB,GAAG,IAAI,GAAG,EAAkB,CAAC;AAEpD;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CACjC,SAAiB,EACjB,IAAY;IAEZ,IAAI,EAAE,GAAG,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACrC,IAAI,CAAC,EAAE,EAAE,CAAC;QACR,sEAAsE;QACtE,oDAAoD;QACpD,EAAE,GAAG,IAAI,MAAM,CAAC,cAAc,IAAI,oBAAoB,EAAE,GAAG,CAAC,CAAC;QAC7D,iBAAiB,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAClC,CAAC;IACD,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAClC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/B,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACjE,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,GAAe,EACf,UAAkB;IAElB,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC;QACxB,MAAM,EAAE,IAAI,eAAe,EAAE;QAC7B,MAAM,EAAE,IAAI,YAAY,EAAE;KAC3B,CAAC,CAAC;IACH,MAAM,MAAM,GAAG,IAAI,wBAAwB,CAAC,SAAS,CAAC,CAAC;IACvD,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;IAC7B,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IAErB,4BAA4B;IAC5B,MAAM,UAAU,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC;IAClC,MAAM,eAAe,GAAG,UAAU,GAAG,UAAU,CAAC;IAChD,MAAM,MAAM,GAAG,IAAI,aAAa,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,eAAe,EAAE,CAAC,CAAC,CAAC;IACpE,MAAM,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE;QACvB,aAAa,EAAE;YACb,KAAK,EAAE,SAAS;YAChB,gBAAgB,EAAE,CAAC;YACnB,UAAU;SACX;KACF,CAAC,CAAC;IAEH,MAAM,MAAM,CAAC,QAAQ,EAAE,CAAC;IACxB,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;IACpC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IACrE,CAAC;IACD,OAAO,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;AAChC,CAAC"}
1
+ {"version":3,"file":"audio-utils.js","sourceRoot":"","sources":["../src/audio-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,wBAAwB,EACxB,aAAa,EACb,MAAM,EACN,eAAe,GAChB,MAAM,YAAY,CAAC;AAEpB,MAAM,iBAAiB,GAAG,IAAI,GAAG,EAAkB,CAAC;AAEpD;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CACjC,SAAiB,EACjB,IAAY;IAEZ,IAAI,EAAE,GAAG,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACrC,IAAI,CAAC,EAAE,EAAE,CAAC;QACR,sEAAsE;QACtE,oDAAoD;QACpD,EAAE,GAAG,IAAI,MAAM,CAAC,cAAc,IAAI,oBAAoB,EAAE,GAAG,CAAC,CAAC;QAC7D,iBAAiB,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAClC,CAAC;IACD,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAClC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/B,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACjE,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,GAAe,EACf,UAAkB;IAElB,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC;QACxB,MAAM,EAAE,IAAI,eAAe,EAAE;QAC7B,MAAM,EAAE,IAAI,YAAY,EAAE;KAC3B,CAAC,CAAC;IACH,MAAM,MAAM,GAAG,IAAI,wBAAwB,CAAC,SAAS,CAAC,CAAC;IACvD,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;IAC7B,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IAErB,4BAA4B;IAC5B,MAAM,UAAU,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC;IAClC,MAAM,eAAe,GAAG,UAAU,GAAG,UAAU,CAAC;IAChD,MAAM,MAAM,GAAG,IAAI,aAAa,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,eAAe,EAAE,CAAC,CAAC,CAAC;IACpE,MAAM,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE;QACvB,aAAa,EAAE;YACb,KAAK,EAAE,SAAS;YAChB,gBAAgB,EAAE,CAAC;YACnB,UAAU;SACX;KACF,CAAC,CAAC;IAEH,MAAM,MAAM,CAAC,QAAQ,EAAE,CAAC;IACxB,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;IACpC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IACrE,CAAC;IACD,OAAO,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;AAChC,CAAC;AAED,6CAA6C;AAC7C,MAAM,UAAU,kBAAkB,CAAC,GAAW;IAC5C,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;IACzB,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC5C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACvC,KAAK,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,137 @@
1
+ import type { WordTimestamp } from "./timestamps.js";
2
+ /**
3
+ * Sanitizes caption-body text: strips C0 control characters (U+0000–U+001F
4
+ * minus whitespace, plus U+007F DEL), folds non-ASCII typography (curly
5
+ * quotes, en/em dashes, ellipsis) to ASCII equivalents, and collapses
6
+ * whitespace runs to a single space. Exported for testing.
7
+ */
8
+ export declare function normalizeTypography(text: string): string;
9
+ /**
10
+ * Escapes characters that would otherwise be interpreted as inline WebVTT
11
+ * markup. Applied only to the VTT render path; SRT passes raw text through.
12
+ * Exported for testing; not part of the public API.
13
+ */
14
+ export declare function escapeVttText(text: string): string;
15
+ /**
16
+ * Formats a number of seconds as an SRT timestamp: `HH:MM:SS,mmm`.
17
+ * Negative inputs are clamped to zero. Milliseconds are rounded.
18
+ * Exported for testing; not part of the public API.
19
+ */
20
+ export declare function formatSrtTime(seconds: number): string;
21
+ /**
22
+ * Formats a number of seconds as a WebVTT timestamp: `HH:MM:SS.mmm`.
23
+ * Negative inputs are clamped to zero. Milliseconds are rounded.
24
+ * Exported for testing; not part of the public API.
25
+ */
26
+ export declare function formatVttTime(seconds: number): string;
27
+ /**
28
+ * Groups a flat list of word timestamps into sentences using terminator
29
+ * punctuation attached to the trailing word. Supported terminators:
30
+ *
31
+ * - ASCII: `.`, `!`, `?`
32
+ * - CJK: `。`, `!`, `?`
33
+ * - Devanagari (Hindi, Sanskrit, Marathi): `।`, `॥`
34
+ * - Arabic: `؟`, `۔`
35
+ *
36
+ * A trailing closing quote (`"`, `'`, curly variants, or CJK corner
37
+ * bracket `」` / `』`) attached to the terminator is tolerated.
38
+ *
39
+ * Known limitations:
40
+ * - Abbreviations like "Dr." or "e.g." are treated as sentence ends.
41
+ * - Thai and other scripts without word-level whitespace or inline
42
+ * terminators fall through to char/duration-based hard breaks.
43
+ *
44
+ * Exported for testing; not part of the public API.
45
+ */
46
+ export declare function groupIntoSentences(words: readonly WordTimestamp[]): WordTimestamp[][];
47
+ interface CueSplitOptions {
48
+ readonly longPhraseCommaBreakChars: number;
49
+ readonly maxCharsPerCue: number;
50
+ readonly maxCueDurationMs: number;
51
+ }
52
+ /**
53
+ * Subdivides a sentence (an ordered list of words) into one or more cues.
54
+ * Breaks are chosen in this priority order:
55
+ * 1. Hard: character budget exceeded → break before the offending word.
56
+ * 2. Hard: duration exceeded → break before the offending word.
57
+ * 3. Soft: comma in a word that leaves the current cue above
58
+ * `longPhraseCommaBreakChars` → break after that word.
59
+ *
60
+ * Exported for testing; not part of the public API.
61
+ */
62
+ export declare function splitSentenceIntoCues(sentence: readonly WordTimestamp[], options: CueSplitOptions): WordTimestamp[][];
63
+ interface WrapOptions {
64
+ readonly maxLineLength: number;
65
+ readonly maxLines: number;
66
+ }
67
+ /**
68
+ * Wraps a sequence of words into up to `maxLines` lines, trying to keep
69
+ * each line at or below `maxLineLength` characters. A word longer than
70
+ * `maxLineLength` is placed on its own line rather than split. If words
71
+ * remain after the final line is full, they are appended to that final
72
+ * line (accept overflow; cue splitter is expected to have prevented this
73
+ * in normal flow).
74
+ *
75
+ * Exported for testing; not part of the public API.
76
+ */
77
+ export declare function wrapCueText(words: readonly string[], options: WrapOptions): string;
78
+ /**
79
+ * Supported caption output formats.
80
+ *
81
+ * - `"srt"` — SubRip (`.srt`). Comma-decimal timestamps, numeric cue IDs,
82
+ * plain text bodies. Widely supported by media players and upload tools.
83
+ * - `"vtt"` — WebVTT (`.vtt`). Period-decimal timestamps, `WEBVTT` header,
84
+ * HTML-escaped bodies (`&`, `<`, `>`). Required for HTML `<track>`.
85
+ */
86
+ export type CaptionFormat = "srt" | "vtt";
87
+ /**
88
+ * Options for {@link timestampsToCaptions}.
89
+ */
90
+ export interface CaptionsOptions {
91
+ /** Output format. Default `"srt"`. */
92
+ readonly format?: CaptionFormat;
93
+ /**
94
+ * Minimum cue-char-count at which a trailing comma triggers a soft cue
95
+ * break. Prevents tiny fragments after every comma. Default `60`.
96
+ */
97
+ readonly longPhraseCommaBreakChars?: number;
98
+ /** Max total chars per cue. Default `maxLineLength * maxLinesPerCue`. */
99
+ readonly maxCharsPerCue?: number;
100
+ /** Max cue duration in milliseconds. Default `7000`. */
101
+ readonly maxCueDurationMs?: number;
102
+ /**
103
+ * Max chars per line (word-boundary wrap). Default `42` — the common
104
+ * broadcast convention for Latin-alphabet subtitles.
105
+ *
106
+ * Character counts use JavaScript `string.length` (UTF-16 code units).
107
+ * For CJK (Japanese, Chinese, Korean) content, each character is roughly
108
+ * twice the visual width of an ASCII character in monospaced players;
109
+ * pass a smaller value (e.g. `16`) to match Japanese broadcast norms.
110
+ */
111
+ readonly maxLineLength?: number;
112
+ /** Max lines per cue. Default `2`. */
113
+ readonly maxLinesPerCue?: number;
114
+ }
115
+ /**
116
+ * Converts word-level timestamps into a caption string in SRT or WebVTT
117
+ * format.
118
+ *
119
+ * Sentence boundaries (`.`, `!`, `?` in word text, optionally followed
120
+ * by a closing quote) create cue breaks; long sentences are subdivided
121
+ * by character count, duration, and soft comma breaks. Each cue is
122
+ * greedily wrapped into up to `maxLinesPerCue` lines of `maxLineLength`
123
+ * characters.
124
+ *
125
+ * Returns the empty string for empty input.
126
+ *
127
+ * @example
128
+ * ```ts
129
+ * const { timestamps } = await generateSpeech({ ... });
130
+ *
131
+ * const srt = timestampsToCaptions(timestamps ?? []);
132
+ * const vtt = timestampsToCaptions(timestamps ?? [], { format: "vtt" });
133
+ * ```
134
+ */
135
+ export declare function timestampsToCaptions(timestamps: readonly WordTimestamp[], options?: CaptionsOptions): string;
136
+ export {};
137
+ //# sourceMappingURL=captions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"captions.d.ts","sourceRoot":"","sources":["../src/captions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAwBrD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMxD;AAQD;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMlD;AAeD;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAErD;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAErD;AAWD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,SAAS,aAAa,EAAE,GAC9B,aAAa,EAAE,EAAE,CAcnB;AAOD,UAAU,eAAe;IACvB,QAAQ,CAAC,yBAAyB,EAAE,MAAM,CAAC;IAC3C,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;CACnC;AA0BD;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,SAAS,aAAa,EAAE,EAClC,OAAO,EAAE,eAAe,GACvB,aAAa,EAAE,EAAE,CAgCnB;AAED,UAAU,WAAW;IACnB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,OAAO,EAAE,WAAW,GACnB,MAAM,CAmBR;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,KAAK,CAAC;AAE1C;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,sCAAsC;IACtC,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC;IAChC;;;OAGG;IACH,QAAQ,CAAC,yBAAyB,CAAC,EAAE,MAAM,CAAC;IAC5C,yEAAyE;IACzE,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,wDAAwD;IACxD,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC;;;;;;;;OAQG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,sCAAsC;IACtC,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;CAClC;AAWD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,SAAS,aAAa,EAAE,EACpC,OAAO,GAAE,eAAoB,GAC5B,MAAM,CAkER"}