@speech-sdk/core 0.6.2 → 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.
- package/LICENSE +202 -21
- package/README.md +215 -269
- package/dist/__tests__/e2e/_save-audio.d.ts +25 -2
- package/dist/__tests__/e2e/_save-audio.d.ts.map +1 -1
- package/dist/__tests__/e2e/_save-audio.js +46 -10
- package/dist/__tests__/e2e/_save-audio.js.map +1 -1
- package/dist/audio-utils.d.ts +2 -0
- package/dist/audio-utils.d.ts.map +1 -1
- package/dist/audio-utils.js +9 -0
- package/dist/audio-utils.js.map +1 -1
- package/dist/captions.d.ts +137 -0
- package/dist/captions.d.ts.map +1 -0
- package/dist/captions.js +283 -0
- package/dist/captions.js.map +1 -0
- package/dist/conversation/stitch.d.ts +5 -0
- package/dist/conversation/stitch.d.ts.map +1 -1
- package/dist/conversation/stitch.js +37 -0
- package/dist/conversation/stitch.js.map +1 -1
- package/dist/conversation/types.d.ts +16 -0
- package/dist/conversation/types.d.ts.map +1 -1
- package/dist/derive-timestamps.d.ts +14 -0
- package/dist/derive-timestamps.d.ts.map +1 -0
- package/dist/derive-timestamps.js +38 -0
- package/dist/derive-timestamps.js.map +1 -0
- package/dist/errors.d.ts +25 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +28 -0
- package/dist/errors.js.map +1 -1
- package/dist/generate-conversation.d.ts +1 -1
- package/dist/generate-conversation.d.ts.map +1 -1
- package/dist/generate-conversation.js +59 -0
- package/dist/generate-conversation.js.map +1 -1
- package/dist/generate-speech.d.ts +18 -1
- package/dist/generate-speech.d.ts.map +1 -1
- package/dist/generate-speech.js +73 -16
- package/dist/generate-speech.js.map +1 -1
- package/dist/index.d.ts +6 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/logger.d.ts +2 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +40 -0
- package/dist/logger.js.map +1 -0
- package/dist/provider-utils.d.ts +8 -0
- package/dist/provider-utils.d.ts.map +1 -1
- package/dist/provider-utils.js +16 -2
- package/dist/provider-utils.js.map +1 -1
- package/dist/providers/cartesia/alignment.d.ts +24 -0
- package/dist/providers/cartesia/alignment.d.ts.map +1 -0
- package/dist/providers/cartesia/alignment.js +23 -0
- package/dist/providers/cartesia/alignment.js.map +1 -0
- package/dist/providers/cartesia/index.d.ts +12 -2
- package/dist/providers/cartesia/index.d.ts.map +1 -1
- package/dist/providers/cartesia/index.js +137 -2
- package/dist/providers/cartesia/index.js.map +1 -1
- package/dist/providers/elevenlabs/alignment.d.ts +24 -0
- package/dist/providers/elevenlabs/alignment.d.ts.map +1 -0
- package/dist/providers/elevenlabs/alignment.js +48 -0
- package/dist/providers/elevenlabs/alignment.js.map +1 -0
- package/dist/providers/elevenlabs/index.d.ts +19 -4
- package/dist/providers/elevenlabs/index.d.ts.map +1 -1
- package/dist/providers/elevenlabs/index.js +83 -13
- package/dist/providers/elevenlabs/index.js.map +1 -1
- package/dist/providers/fal/index.d.ts +0 -25
- package/dist/providers/fal/index.d.ts.map +1 -1
- package/dist/providers/fal/index.js +3 -58
- package/dist/providers/fal/index.js.map +1 -1
- package/dist/providers/hume/alignment.d.ts +38 -0
- package/dist/providers/hume/alignment.d.ts.map +1 -0
- package/dist/providers/hume/alignment.js +31 -0
- package/dist/providers/hume/alignment.js.map +1 -0
- package/dist/providers/hume/index.d.ts +8 -1
- package/dist/providers/hume/index.d.ts.map +1 -1
- package/dist/providers/hume/index.js +75 -1
- package/dist/providers/hume/index.js.map +1 -1
- package/dist/providers/inworld/alignment.d.ts +25 -0
- package/dist/providers/inworld/alignment.d.ts.map +1 -0
- package/dist/providers/inworld/alignment.js +23 -0
- package/dist/providers/inworld/alignment.js.map +1 -0
- package/dist/providers/inworld/index.d.ts +11 -2
- package/dist/providers/inworld/index.d.ts.map +1 -1
- package/dist/providers/inworld/index.js +11 -2
- package/dist/providers/inworld/index.js.map +1 -1
- package/dist/providers/murf/alignment.d.ts +22 -0
- package/dist/providers/murf/alignment.d.ts.map +1 -0
- package/dist/providers/murf/alignment.js +17 -0
- package/dist/providers/murf/alignment.js.map +1 -0
- package/dist/providers/murf/index.d.ts +8 -1
- package/dist/providers/murf/index.d.ts.map +1 -1
- package/dist/providers/murf/index.js +10 -1
- package/dist/providers/murf/index.js.map +1 -1
- package/dist/providers/openai/index.d.ts +12 -3
- package/dist/providers/openai/index.d.ts.map +1 -1
- package/dist/providers/openai/index.js +7 -3
- package/dist/providers/openai/index.js.map +1 -1
- package/dist/providers/resemble/alignment.d.ts +32 -0
- package/dist/providers/resemble/alignment.d.ts.map +1 -0
- package/dist/providers/resemble/alignment.js +57 -0
- package/dist/providers/resemble/alignment.js.map +1 -0
- package/dist/providers/resemble/index.d.ts +7 -1
- package/dist/providers/resemble/index.d.ts.map +1 -1
- package/dist/providers/resemble/index.js +13 -1
- package/dist/providers/resemble/index.js.map +1 -1
- package/dist/resolve-provider.d.ts.map +1 -1
- package/dist/resolve-provider.js +3 -12
- package/dist/resolve-provider.js.map +1 -1
- package/dist/speech-provider.d.ts +48 -4
- package/dist/speech-provider.d.ts.map +1 -1
- package/dist/speech-provider.js +16 -0
- package/dist/speech-provider.js.map +1 -1
- package/dist/speech-result.d.ts +10 -0
- package/dist/speech-result.d.ts.map +1 -1
- package/dist/speech-result.js.map +1 -1
- package/dist/speech-to-text-provider.d.ts +40 -0
- package/dist/speech-to-text-provider.d.ts.map +1 -0
- package/dist/speech-to-text-provider.js +2 -0
- package/dist/speech-to-text-provider.js.map +1 -0
- package/dist/stt-providers/openai/index.d.ts +42 -0
- package/dist/stt-providers/openai/index.d.ts.map +1 -0
- package/dist/stt-providers/openai/index.js +184 -0
- package/dist/stt-providers/openai/index.js.map +1 -0
- package/dist/timestamps.d.ts +23 -0
- package/dist/timestamps.d.ts.map +1 -0
- package/dist/timestamps.js +2 -0
- package/dist/timestamps.js.map +1 -0
- package/package.json +6 -2
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { generateConversation as _generateConversation } from "../../generate-conversation.js";
|
|
2
2
|
import { generateSpeech as _generateSpeech } from "../../generate-speech.js";
|
|
3
|
+
import type { WordTimestamp } from "../../timestamps.js";
|
|
3
4
|
/**
|
|
4
5
|
* Write a test-generated audio file to `SPEECH_SDK_E2E_OUTPUT_DIR` if the env
|
|
5
6
|
* var is set. No-op otherwise, so normal CI runs don't produce artifacts.
|
|
@@ -15,14 +16,36 @@ export declare function maybeSaveAudio(name: string, audio: {
|
|
|
15
16
|
uint8Array: Uint8Array;
|
|
16
17
|
mediaType: string;
|
|
17
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>;
|
|
18
37
|
/**
|
|
19
38
|
* Drop-in replacement for `generateSpeech` that autosaves to
|
|
20
|
-
* `SPEECH_SDK_E2E_OUTPUT_DIR` using the current vitest test name.
|
|
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.
|
|
21
42
|
*/
|
|
22
43
|
export declare const generateSpeech: typeof _generateSpeech;
|
|
23
44
|
/**
|
|
24
45
|
* Drop-in replacement for `generateConversation` that autosaves to
|
|
25
|
-
* `SPEECH_SDK_E2E_OUTPUT_DIR` using the current vitest test name.
|
|
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.
|
|
26
49
|
*/
|
|
27
50
|
export declare const generateConversation: typeof _generateConversation;
|
|
28
51
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_save-audio.d.ts","sourceRoot":"","sources":["../../../src/__tests__/e2e/_save-audio.ts"],"names":[],"mappings":"
|
|
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,6 +1,7 @@
|
|
|
1
1
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
2
|
import { basename, join } from "node:path";
|
|
3
3
|
import { expect } from "vitest";
|
|
4
|
+
import { timestampsToCaptions } from "../../captions.js";
|
|
4
5
|
import { generateConversation as _generateConversation } from "../../generate-conversation.js";
|
|
5
6
|
import { generateSpeech as _generateSpeech } from "../../generate-speech.js";
|
|
6
7
|
import { collectStream } from "./_collect-stream.js";
|
|
@@ -66,11 +67,22 @@ function providerBucket(testPath) {
|
|
|
66
67
|
// per file, so this resets per test file — collisions are only meaningful
|
|
67
68
|
// within the same `it`.
|
|
68
69
|
const callCounts = new Map();
|
|
69
|
-
|
|
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) {
|
|
70
78
|
const key = `${bucket}/${slug}`;
|
|
71
79
|
const n = (callCounts.get(key) ?? 0) + 1;
|
|
72
80
|
callCounts.set(key, n);
|
|
73
|
-
return n === 1 ?
|
|
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}`);
|
|
74
86
|
}
|
|
75
87
|
/**
|
|
76
88
|
* Write a test-generated audio file to `SPEECH_SDK_E2E_OUTPUT_DIR` if the env
|
|
@@ -84,6 +96,23 @@ function nextFilename(bucket, slug, ext) {
|
|
|
84
96
|
* `-3`, etc.
|
|
85
97
|
*/
|
|
86
98
|
export async function maybeSaveAudio(name, audio) {
|
|
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) {
|
|
87
116
|
const dir = resolveOutputDir();
|
|
88
117
|
if (!dir) {
|
|
89
118
|
return;
|
|
@@ -92,10 +121,13 @@ export async function maybeSaveAudio(name, audio) {
|
|
|
92
121
|
const bucket = providerBucket(testPath);
|
|
93
122
|
const bucketDir = join(dir, bucket);
|
|
94
123
|
await mkdir(bucketDir, { recursive: true });
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
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
|
+
}
|
|
99
131
|
}
|
|
100
132
|
function currentTestSlug() {
|
|
101
133
|
const { currentTestName } = currentTestContext();
|
|
@@ -103,20 +135,24 @@ function currentTestSlug() {
|
|
|
103
135
|
}
|
|
104
136
|
/**
|
|
105
137
|
* Drop-in replacement for `generateSpeech` that autosaves to
|
|
106
|
-
* `SPEECH_SDK_E2E_OUTPUT_DIR` using the current vitest test name.
|
|
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.
|
|
107
141
|
*/
|
|
108
142
|
export const generateSpeech = (async (options) => {
|
|
109
143
|
const result = await _generateSpeech(options);
|
|
110
|
-
await
|
|
144
|
+
await maybeSaveResult(currentTestSlug(), result.audio, result.timestamps);
|
|
111
145
|
return result;
|
|
112
146
|
});
|
|
113
147
|
/**
|
|
114
148
|
* Drop-in replacement for `generateConversation` that autosaves to
|
|
115
|
-
* `SPEECH_SDK_E2E_OUTPUT_DIR` using the current vitest test name.
|
|
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.
|
|
116
152
|
*/
|
|
117
153
|
export const generateConversation = (async (options) => {
|
|
118
154
|
const result = await _generateConversation(options);
|
|
119
|
-
await
|
|
155
|
+
await maybeSaveResult(currentTestSlug(), result.audio, result.timestamps);
|
|
120
156
|
return result;
|
|
121
157
|
});
|
|
122
158
|
/**
|
|
@@ -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,QAAQ,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,oBAAoB,IAAI,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAC/F,OAAO,EAAE,cAAc,IAAI,eAAe,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"_save-audio.js","sourceRoot":"","sources":["../../../src/__tests__/e2e/_save-audio.ts"],"names":[],"mappings":"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"}
|
package/dist/audio-utils.d.ts
CHANGED
|
@@ -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"}
|
package/dist/audio-utils.js
CHANGED
|
@@ -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
|
package/dist/audio-utils.js.map
CHANGED
|
@@ -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"}
|
package/dist/captions.js
ADDED
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
const SECONDS_PER_HOUR = 3600;
|
|
2
|
+
const SECONDS_PER_MINUTE = 60;
|
|
3
|
+
const MS_PER_SECOND = 1000;
|
|
4
|
+
const TYPOGRAPHY_MAP = [
|
|
5
|
+
[/\u2019/g, "'"],
|
|
6
|
+
[/\u2018/g, "'"],
|
|
7
|
+
[/\u201C/g, '"'],
|
|
8
|
+
[/\u201D/g, '"'],
|
|
9
|
+
[/\u2013/g, "-"],
|
|
10
|
+
[/\u2014/g, "-"],
|
|
11
|
+
[/\u2026/g, "..."],
|
|
12
|
+
];
|
|
13
|
+
// C0 control chars (minus \t \n \r \v \f, which `\s` collapses downstream)
|
|
14
|
+
// and DEL. Providers should never emit these in text, but a stray NUL or ESC
|
|
15
|
+
// would silently corrupt SRT/VTT output — some parsers truncate on NUL.
|
|
16
|
+
// biome-ignore lint/suspicious/noControlCharactersInRegex: intentional — this regex exists to strip control characters
|
|
17
|
+
const CONTROL_CHARS = /[\u0000-\u0008\u000E-\u001F\u007F]/g;
|
|
18
|
+
const WHITESPACE_RUN = /\s+/g;
|
|
19
|
+
/**
|
|
20
|
+
* Sanitizes caption-body text: strips C0 control characters (U+0000–U+001F
|
|
21
|
+
* minus whitespace, plus U+007F DEL), folds non-ASCII typography (curly
|
|
22
|
+
* quotes, en/em dashes, ellipsis) to ASCII equivalents, and collapses
|
|
23
|
+
* whitespace runs to a single space. Exported for testing.
|
|
24
|
+
*/
|
|
25
|
+
export function normalizeTypography(text) {
|
|
26
|
+
let out = text.replace(CONTROL_CHARS, "");
|
|
27
|
+
for (const [pattern, replacement] of TYPOGRAPHY_MAP) {
|
|
28
|
+
out = out.replace(pattern, replacement);
|
|
29
|
+
}
|
|
30
|
+
return out.replace(WHITESPACE_RUN, " ");
|
|
31
|
+
}
|
|
32
|
+
const VTT_ESCAPE_MAP = [
|
|
33
|
+
[/&/g, "&"],
|
|
34
|
+
[/</g, "<"],
|
|
35
|
+
[/>/g, ">"],
|
|
36
|
+
];
|
|
37
|
+
/**
|
|
38
|
+
* Escapes characters that would otherwise be interpreted as inline WebVTT
|
|
39
|
+
* markup. Applied only to the VTT render path; SRT passes raw text through.
|
|
40
|
+
* Exported for testing; not part of the public API.
|
|
41
|
+
*/
|
|
42
|
+
export function escapeVttText(text) {
|
|
43
|
+
let out = text;
|
|
44
|
+
for (const [pattern, replacement] of VTT_ESCAPE_MAP) {
|
|
45
|
+
out = out.replace(pattern, replacement);
|
|
46
|
+
}
|
|
47
|
+
return out;
|
|
48
|
+
}
|
|
49
|
+
function formatTimestamp(seconds, separator) {
|
|
50
|
+
const clamped = Math.max(0, seconds);
|
|
51
|
+
const totalMs = Math.round(clamped * MS_PER_SECOND);
|
|
52
|
+
const ms = totalMs % MS_PER_SECOND;
|
|
53
|
+
const totalSeconds = Math.floor(totalMs / MS_PER_SECOND);
|
|
54
|
+
const hours = Math.floor(totalSeconds / SECONDS_PER_HOUR);
|
|
55
|
+
const minutes = Math.floor((totalSeconds % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE);
|
|
56
|
+
const secs = totalSeconds % SECONDS_PER_MINUTE;
|
|
57
|
+
return `${String(hours).padStart(2, "0")}:${String(minutes).padStart(2, "0")}:${String(secs).padStart(2, "0")}${separator}${String(ms).padStart(3, "0")}`;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Formats a number of seconds as an SRT timestamp: `HH:MM:SS,mmm`.
|
|
61
|
+
* Negative inputs are clamped to zero. Milliseconds are rounded.
|
|
62
|
+
* Exported for testing; not part of the public API.
|
|
63
|
+
*/
|
|
64
|
+
export function formatSrtTime(seconds) {
|
|
65
|
+
return formatTimestamp(seconds, ",");
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Formats a number of seconds as a WebVTT timestamp: `HH:MM:SS.mmm`.
|
|
69
|
+
* Negative inputs are clamped to zero. Milliseconds are rounded.
|
|
70
|
+
* Exported for testing; not part of the public API.
|
|
71
|
+
*/
|
|
72
|
+
export function formatVttTime(seconds) {
|
|
73
|
+
return formatTimestamp(seconds, ".");
|
|
74
|
+
}
|
|
75
|
+
// Sentence-ending punctuation across major writing systems:
|
|
76
|
+
// ASCII: . ! ?
|
|
77
|
+
// CJK: 。 ! ? (U+3002, U+FF01, U+FF1F)
|
|
78
|
+
// Devanagari: । ॥ (U+0964 danda, U+0965 double danda)
|
|
79
|
+
// Arabic: ؟ ۔ (U+061F question, U+06D4 full stop)
|
|
80
|
+
// Optionally followed by a closing quote: ASCII, curly, or CJK corner bracket.
|
|
81
|
+
const SENTENCE_TERMINATOR = /[.!?\u3002\uFF01\uFF1F\u0964\u0965\u061F\u06D4]["'\u2018\u2019\u201C\u201D\u300D\u300F]?$/;
|
|
82
|
+
/**
|
|
83
|
+
* Groups a flat list of word timestamps into sentences using terminator
|
|
84
|
+
* punctuation attached to the trailing word. Supported terminators:
|
|
85
|
+
*
|
|
86
|
+
* - ASCII: `.`, `!`, `?`
|
|
87
|
+
* - CJK: `。`, `!`, `?`
|
|
88
|
+
* - Devanagari (Hindi, Sanskrit, Marathi): `।`, `॥`
|
|
89
|
+
* - Arabic: `؟`, `۔`
|
|
90
|
+
*
|
|
91
|
+
* A trailing closing quote (`"`, `'`, curly variants, or CJK corner
|
|
92
|
+
* bracket `」` / `』`) attached to the terminator is tolerated.
|
|
93
|
+
*
|
|
94
|
+
* Known limitations:
|
|
95
|
+
* - Abbreviations like "Dr." or "e.g." are treated as sentence ends.
|
|
96
|
+
* - Thai and other scripts without word-level whitespace or inline
|
|
97
|
+
* terminators fall through to char/duration-based hard breaks.
|
|
98
|
+
*
|
|
99
|
+
* Exported for testing; not part of the public API.
|
|
100
|
+
*/
|
|
101
|
+
export function groupIntoSentences(words) {
|
|
102
|
+
const sentences = [];
|
|
103
|
+
let current = [];
|
|
104
|
+
for (const word of words) {
|
|
105
|
+
current.push(word);
|
|
106
|
+
if (SENTENCE_TERMINATOR.test(word.text.trim())) {
|
|
107
|
+
sentences.push(current);
|
|
108
|
+
current = [];
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
if (current.length > 0) {
|
|
112
|
+
sentences.push(current);
|
|
113
|
+
}
|
|
114
|
+
return sentences;
|
|
115
|
+
}
|
|
116
|
+
// Comma-equivalent soft-break punctuation: ASCII, CJK ideographic (`、`) and
|
|
117
|
+
// fullwidth (`,`), and Arabic (`،`).
|
|
118
|
+
const COMMA_TERMINATOR = /[,\u3001\uFF0C\u060C]["'\u2018\u2019\u201C\u201D\u300D\u300F]?$/;
|
|
119
|
+
function cueCharLength(cue) {
|
|
120
|
+
// Sum word lengths + (n-1) spaces between words.
|
|
121
|
+
let chars = 0;
|
|
122
|
+
for (const word of cue) {
|
|
123
|
+
chars += word.text.length;
|
|
124
|
+
}
|
|
125
|
+
if (cue.length > 1) {
|
|
126
|
+
chars += cue.length - 1;
|
|
127
|
+
}
|
|
128
|
+
return chars;
|
|
129
|
+
}
|
|
130
|
+
function cueDurationMs(cue) {
|
|
131
|
+
if (cue.length === 0) {
|
|
132
|
+
return 0;
|
|
133
|
+
}
|
|
134
|
+
const first = cue[0];
|
|
135
|
+
const last = cue.at(-1);
|
|
136
|
+
if (!last) {
|
|
137
|
+
return 0;
|
|
138
|
+
}
|
|
139
|
+
return (last.end - first.start) * 1000;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Subdivides a sentence (an ordered list of words) into one or more cues.
|
|
143
|
+
* Breaks are chosen in this priority order:
|
|
144
|
+
* 1. Hard: character budget exceeded → break before the offending word.
|
|
145
|
+
* 2. Hard: duration exceeded → break before the offending word.
|
|
146
|
+
* 3. Soft: comma in a word that leaves the current cue above
|
|
147
|
+
* `longPhraseCommaBreakChars` → break after that word.
|
|
148
|
+
*
|
|
149
|
+
* Exported for testing; not part of the public API.
|
|
150
|
+
*/
|
|
151
|
+
export function splitSentenceIntoCues(sentence, options) {
|
|
152
|
+
const cues = [];
|
|
153
|
+
let current = [];
|
|
154
|
+
for (const word of sentence) {
|
|
155
|
+
const tentative = [...current, word];
|
|
156
|
+
const exceedsChars = cueCharLength(tentative) > options.maxCharsPerCue;
|
|
157
|
+
const exceedsDuration = cueDurationMs(tentative) > options.maxCueDurationMs;
|
|
158
|
+
if ((exceedsChars || exceedsDuration) && current.length > 0) {
|
|
159
|
+
cues.push(current);
|
|
160
|
+
current = [word];
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
current.push(word);
|
|
164
|
+
const endsWithComma = COMMA_TERMINATOR.test(word.text.trim());
|
|
165
|
+
if (endsWithComma &&
|
|
166
|
+
cueCharLength(current) + 1 >= options.longPhraseCommaBreakChars) {
|
|
167
|
+
cues.push(current);
|
|
168
|
+
current = [];
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
if (current.length > 0) {
|
|
172
|
+
cues.push(current);
|
|
173
|
+
}
|
|
174
|
+
return cues;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Wraps a sequence of words into up to `maxLines` lines, trying to keep
|
|
178
|
+
* each line at or below `maxLineLength` characters. A word longer than
|
|
179
|
+
* `maxLineLength` is placed on its own line rather than split. If words
|
|
180
|
+
* remain after the final line is full, they are appended to that final
|
|
181
|
+
* line (accept overflow; cue splitter is expected to have prevented this
|
|
182
|
+
* in normal flow).
|
|
183
|
+
*
|
|
184
|
+
* Exported for testing; not part of the public API.
|
|
185
|
+
*/
|
|
186
|
+
export function wrapCueText(words, options) {
|
|
187
|
+
if (words.length === 0) {
|
|
188
|
+
return "";
|
|
189
|
+
}
|
|
190
|
+
const lines = [""];
|
|
191
|
+
for (const word of words) {
|
|
192
|
+
const last = lines.at(-1) ?? "";
|
|
193
|
+
const candidate = last.length === 0 ? word : `${last} ${word}`;
|
|
194
|
+
if (candidate.length <= options.maxLineLength ||
|
|
195
|
+
last.length === 0 ||
|
|
196
|
+
lines.length >= options.maxLines) {
|
|
197
|
+
lines[lines.length - 1] = candidate;
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
lines.push(word);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return lines.join("\n");
|
|
204
|
+
}
|
|
205
|
+
const DEFAULT_MAX_LINE_LENGTH = 42;
|
|
206
|
+
const DEFAULT_MAX_LINES_PER_CUE = 2;
|
|
207
|
+
const DEFAULT_MAX_CUE_DURATION_MS = 7000;
|
|
208
|
+
const DEFAULT_LONG_PHRASE_COMMA_BREAK_CHARS = 60;
|
|
209
|
+
function identity(text) {
|
|
210
|
+
return text;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Converts word-level timestamps into a caption string in SRT or WebVTT
|
|
214
|
+
* format.
|
|
215
|
+
*
|
|
216
|
+
* Sentence boundaries (`.`, `!`, `?` in word text, optionally followed
|
|
217
|
+
* by a closing quote) create cue breaks; long sentences are subdivided
|
|
218
|
+
* by character count, duration, and soft comma breaks. Each cue is
|
|
219
|
+
* greedily wrapped into up to `maxLinesPerCue` lines of `maxLineLength`
|
|
220
|
+
* characters.
|
|
221
|
+
*
|
|
222
|
+
* Returns the empty string for empty input.
|
|
223
|
+
*
|
|
224
|
+
* @example
|
|
225
|
+
* ```ts
|
|
226
|
+
* const { timestamps } = await generateSpeech({ ... });
|
|
227
|
+
*
|
|
228
|
+
* const srt = timestampsToCaptions(timestamps ?? []);
|
|
229
|
+
* const vtt = timestampsToCaptions(timestamps ?? [], { format: "vtt" });
|
|
230
|
+
* ```
|
|
231
|
+
*/
|
|
232
|
+
export function timestampsToCaptions(timestamps, options = {}) {
|
|
233
|
+
const format = options.format ?? "srt";
|
|
234
|
+
if (timestamps.length === 0) {
|
|
235
|
+
// SRT has no required signature — `""` is a valid empty track. WebVTT
|
|
236
|
+
// requires the `WEBVTT` header per W3C §3.1; emit the minimal valid
|
|
237
|
+
// zero-cue file so callers can still write the output as `.vtt`.
|
|
238
|
+
return format === "vtt" ? "WEBVTT\n\n" : "";
|
|
239
|
+
}
|
|
240
|
+
const maxLineLength = options.maxLineLength ?? DEFAULT_MAX_LINE_LENGTH;
|
|
241
|
+
const maxLinesPerCue = options.maxLinesPerCue ?? DEFAULT_MAX_LINES_PER_CUE;
|
|
242
|
+
const maxCharsPerCue = options.maxCharsPerCue ?? maxLineLength * maxLinesPerCue;
|
|
243
|
+
const maxCueDurationMs = options.maxCueDurationMs ?? DEFAULT_MAX_CUE_DURATION_MS;
|
|
244
|
+
const longPhraseCommaBreakChars = options.longPhraseCommaBreakChars ?? DEFAULT_LONG_PHRASE_COMMA_BREAK_CHARS;
|
|
245
|
+
const sentences = groupIntoSentences(timestamps);
|
|
246
|
+
const cues = [];
|
|
247
|
+
for (const sentence of sentences) {
|
|
248
|
+
cues.push(...splitSentenceIntoCues(sentence, {
|
|
249
|
+
maxCharsPerCue,
|
|
250
|
+
maxCueDurationMs,
|
|
251
|
+
longPhraseCommaBreakChars,
|
|
252
|
+
}));
|
|
253
|
+
}
|
|
254
|
+
const formatTime = format === "vtt" ? formatVttTime : formatSrtTime;
|
|
255
|
+
const escapeText = format === "vtt" ? escapeVttText : identity;
|
|
256
|
+
const blocks = [];
|
|
257
|
+
if (format === "vtt") {
|
|
258
|
+
blocks.push("WEBVTT\n");
|
|
259
|
+
}
|
|
260
|
+
let index = 1;
|
|
261
|
+
for (const cue of cues) {
|
|
262
|
+
if (cue.length === 0) {
|
|
263
|
+
continue;
|
|
264
|
+
}
|
|
265
|
+
const normalizedWords = cue.map((wt) => escapeText(normalizeTypography(wt.text)));
|
|
266
|
+
const body = wrapCueText(normalizedWords, {
|
|
267
|
+
maxLineLength,
|
|
268
|
+
maxLines: maxLinesPerCue,
|
|
269
|
+
});
|
|
270
|
+
const first = cue[0];
|
|
271
|
+
const last = cue.at(-1);
|
|
272
|
+
if (!last) {
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
blocks.push(`${index}\n${formatTime(first.start)} --> ${formatTime(last.end)}\n${body}\n`);
|
|
276
|
+
index++;
|
|
277
|
+
}
|
|
278
|
+
// Append a trailing newline so the file ends with a blank line after the
|
|
279
|
+
// last cue — required by WebVTT's empty-line-separator rule and the SRT
|
|
280
|
+
// convention that strict parsers (e.g. ffmpeg, browser <track>) expect.
|
|
281
|
+
return `${blocks.join("\n")}\n`;
|
|
282
|
+
}
|
|
283
|
+
//# sourceMappingURL=captions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"captions.js","sourceRoot":"","sources":["../src/captions.ts"],"names":[],"mappings":"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"}
|