@speech-sdk/core 0.7.0 → 0.8.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 (245) hide show
  1. package/README.md +227 -108
  2. package/dist/__tests__/e2e/_save-audio.d.ts +0 -42
  3. package/dist/__tests__/e2e/_save-audio.d.ts.map +1 -1
  4. package/dist/__tests__/e2e/_save-audio.js +0 -59
  5. package/dist/__tests__/e2e/_save-audio.js.map +1 -1
  6. package/dist/audio-decode.d.ts +7 -0
  7. package/dist/audio-decode.d.ts.map +1 -0
  8. package/dist/audio-decode.js +109 -0
  9. package/dist/audio-decode.js.map +1 -0
  10. package/dist/audio-duration.d.ts +0 -5
  11. package/dist/audio-duration.d.ts.map +1 -1
  12. package/dist/audio-duration.js +5 -21
  13. package/dist/audio-duration.js.map +1 -1
  14. package/dist/audio-output.d.ts +39 -0
  15. package/dist/audio-output.d.ts.map +1 -0
  16. package/dist/audio-output.js +111 -0
  17. package/dist/audio-output.js.map +1 -0
  18. package/dist/audio-utils.d.ts +2 -10
  19. package/dist/audio-utils.d.ts.map +1 -1
  20. package/dist/audio-utils.js +57 -15
  21. package/dist/audio-utils.js.map +1 -1
  22. package/dist/captions.d.ts +0 -108
  23. package/dist/captions.d.ts.map +1 -1
  24. package/dist/captions.js +8 -98
  25. package/dist/captions.js.map +1 -1
  26. package/dist/conversation/attribute-timestamps.d.ts +26 -0
  27. package/dist/conversation/attribute-timestamps.d.ts.map +1 -0
  28. package/dist/conversation/attribute-timestamps.js +276 -0
  29. package/dist/conversation/attribute-timestamps.js.map +1 -0
  30. package/dist/conversation/dispatch.d.ts +5 -5
  31. package/dist/conversation/dispatch.d.ts.map +1 -1
  32. package/dist/conversation/dispatch.js +18 -8
  33. package/dist/conversation/dispatch.js.map +1 -1
  34. package/dist/conversation/errors.d.ts +3 -0
  35. package/dist/conversation/errors.d.ts.map +1 -1
  36. package/dist/conversation/errors.js +6 -0
  37. package/dist/conversation/errors.js.map +1 -1
  38. package/dist/conversation/pcm-concat.d.ts +0 -24
  39. package/dist/conversation/pcm-concat.d.ts.map +1 -1
  40. package/dist/conversation/pcm-concat.js +8 -183
  41. package/dist/conversation/pcm-concat.js.map +1 -1
  42. package/dist/conversation/proportional-fill.d.ts +10 -0
  43. package/dist/conversation/proportional-fill.d.ts.map +1 -0
  44. package/dist/conversation/proportional-fill.js +64 -0
  45. package/dist/conversation/proportional-fill.js.map +1 -0
  46. package/dist/conversation/silence-detection.d.ts +14 -0
  47. package/dist/conversation/silence-detection.d.ts.map +1 -0
  48. package/dist/conversation/silence-detection.js +52 -0
  49. package/dist/conversation/silence-detection.js.map +1 -0
  50. package/dist/conversation/stitch.d.ts +9 -6
  51. package/dist/conversation/stitch.d.ts.map +1 -1
  52. package/dist/conversation/stitch.js +72 -51
  53. package/dist/conversation/stitch.js.map +1 -1
  54. package/dist/conversation/types.d.ts +7 -37
  55. package/dist/conversation/types.d.ts.map +1 -1
  56. package/dist/conversation/validate.d.ts +1 -16
  57. package/dist/conversation/validate.d.ts.map +1 -1
  58. package/dist/conversation/validate.js +29 -29
  59. package/dist/conversation/validate.js.map +1 -1
  60. package/dist/default-stt-fallback.d.ts +3 -0
  61. package/dist/default-stt-fallback.d.ts.map +1 -0
  62. package/dist/default-stt-fallback.js +11 -0
  63. package/dist/default-stt-fallback.js.map +1 -0
  64. package/dist/derive-timestamps.d.ts +1 -5
  65. package/dist/derive-timestamps.d.ts.map +1 -1
  66. package/dist/derive-timestamps.js +1 -15
  67. package/dist/derive-timestamps.js.map +1 -1
  68. package/dist/encoders/mp3.d.ts +6 -0
  69. package/dist/encoders/mp3.d.ts.map +1 -0
  70. package/dist/encoders/mp3.js +54 -0
  71. package/dist/encoders/mp3.js.map +1 -0
  72. package/dist/errors.d.ts +20 -13
  73. package/dist/errors.d.ts.map +1 -1
  74. package/dist/errors.js +49 -15
  75. package/dist/errors.js.map +1 -1
  76. package/dist/generate-conversation.d.ts +5 -4
  77. package/dist/generate-conversation.d.ts.map +1 -1
  78. package/dist/generate-conversation.js +250 -93
  79. package/dist/generate-conversation.js.map +1 -1
  80. package/dist/generate-speech.d.ts +7 -28
  81. package/dist/generate-speech.d.ts.map +1 -1
  82. package/dist/generate-speech.js +185 -94
  83. package/dist/generate-speech.js.map +1 -1
  84. package/dist/index.d.ts +7 -11
  85. package/dist/index.d.ts.map +1 -1
  86. package/dist/index.js +6 -4
  87. package/dist/index.js.map +1 -1
  88. package/dist/logger.d.ts.map +1 -1
  89. package/dist/logger.js +2 -13
  90. package/dist/logger.js.map +1 -1
  91. package/dist/metadata.d.ts +0 -22
  92. package/dist/metadata.d.ts.map +1 -1
  93. package/dist/pronunciations/errors.d.ts +5 -0
  94. package/dist/pronunciations/errors.d.ts.map +1 -0
  95. package/dist/pronunciations/errors.js +8 -0
  96. package/dist/pronunciations/errors.js.map +1 -0
  97. package/dist/pronunciations/inverse-align.d.ts +4 -0
  98. package/dist/pronunciations/inverse-align.d.ts.map +1 -0
  99. package/dist/pronunciations/inverse-align.js +54 -0
  100. package/dist/pronunciations/inverse-align.js.map +1 -0
  101. package/dist/pronunciations/merge.d.ts +4 -0
  102. package/dist/pronunciations/merge.d.ts.map +1 -0
  103. package/dist/pronunciations/merge.js +13 -0
  104. package/dist/pronunciations/merge.js.map +1 -0
  105. package/dist/pronunciations/substitute.d.ts +6 -0
  106. package/dist/pronunciations/substitute.d.ts.map +1 -0
  107. package/dist/pronunciations/substitute.js +67 -0
  108. package/dist/pronunciations/substitute.js.map +1 -0
  109. package/dist/pronunciations/types.d.ts +18 -0
  110. package/dist/pronunciations/types.d.ts.map +1 -0
  111. package/dist/pronunciations/types.js +2 -0
  112. package/dist/pronunciations/types.js.map +1 -0
  113. package/dist/pronunciations/validate.d.ts +3 -0
  114. package/dist/pronunciations/validate.d.ts.map +1 -0
  115. package/dist/pronunciations/validate.js +26 -0
  116. package/dist/pronunciations/validate.js.map +1 -0
  117. package/dist/provider-utils.d.ts +4 -9
  118. package/dist/provider-utils.d.ts.map +1 -1
  119. package/dist/provider-utils.js +60 -51
  120. package/dist/provider-utils.js.map +1 -1
  121. package/dist/providers/cartesia/alignment.d.ts +0 -16
  122. package/dist/providers/cartesia/alignment.d.ts.map +1 -1
  123. package/dist/providers/cartesia/alignment.js +1 -6
  124. package/dist/providers/cartesia/alignment.js.map +1 -1
  125. package/dist/providers/cartesia/index.d.ts +29 -19
  126. package/dist/providers/cartesia/index.d.ts.map +1 -1
  127. package/dist/providers/cartesia/index.js +116 -80
  128. package/dist/providers/cartesia/index.js.map +1 -1
  129. package/dist/providers/deepgram/index.d.ts +23 -8
  130. package/dist/providers/deepgram/index.d.ts.map +1 -1
  131. package/dist/providers/deepgram/index.js +51 -18
  132. package/dist/providers/deepgram/index.js.map +1 -1
  133. package/dist/providers/elevenlabs/alignment.d.ts +7 -21
  134. package/dist/providers/elevenlabs/alignment.d.ts.map +1 -1
  135. package/dist/providers/elevenlabs/alignment.js +8 -9
  136. package/dist/providers/elevenlabs/alignment.js.map +1 -1
  137. package/dist/providers/elevenlabs/index.d.ts +14 -38
  138. package/dist/providers/elevenlabs/index.d.ts.map +1 -1
  139. package/dist/providers/elevenlabs/index.js +186 -169
  140. package/dist/providers/elevenlabs/index.js.map +1 -1
  141. package/dist/providers/fal/index.d.ts +11 -20
  142. package/dist/providers/fal/index.d.ts.map +1 -1
  143. package/dist/providers/fal/index.js +49 -37
  144. package/dist/providers/fal/index.js.map +1 -1
  145. package/dist/providers/fish-audio/index.d.ts +14 -8
  146. package/dist/providers/fish-audio/index.d.ts.map +1 -1
  147. package/dist/providers/fish-audio/index.js +47 -19
  148. package/dist/providers/fish-audio/index.js.map +1 -1
  149. package/dist/providers/gateway/index.d.ts +76 -0
  150. package/dist/providers/gateway/index.d.ts.map +1 -0
  151. package/dist/providers/gateway/index.js +251 -0
  152. package/dist/providers/gateway/index.js.map +1 -0
  153. package/dist/providers/google/index.d.ts +12 -20
  154. package/dist/providers/google/index.d.ts.map +1 -1
  155. package/dist/providers/google/index.js +180 -162
  156. package/dist/providers/google/index.js.map +1 -1
  157. package/dist/providers/hume/alignment.d.ts +30 -35
  158. package/dist/providers/hume/alignment.d.ts.map +1 -1
  159. package/dist/providers/hume/alignment.js +14 -8
  160. package/dist/providers/hume/alignment.js.map +1 -1
  161. package/dist/providers/hume/index.d.ts +16 -16
  162. package/dist/providers/hume/index.d.ts.map +1 -1
  163. package/dist/providers/hume/index.js +79 -65
  164. package/dist/providers/hume/index.js.map +1 -1
  165. package/dist/providers/inworld/alignment.d.ts +8 -22
  166. package/dist/providers/inworld/alignment.d.ts.map +1 -1
  167. package/dist/providers/inworld/alignment.js +9 -8
  168. package/dist/providers/inworld/alignment.js.map +1 -1
  169. package/dist/providers/inworld/index.d.ts +17 -20
  170. package/dist/providers/inworld/index.d.ts.map +1 -1
  171. package/dist/providers/inworld/index.js +79 -47
  172. package/dist/providers/inworld/index.js.map +1 -1
  173. package/dist/providers/mistral/index.d.ts +14 -8
  174. package/dist/providers/mistral/index.d.ts.map +1 -1
  175. package/dist/providers/mistral/index.js +63 -48
  176. package/dist/providers/mistral/index.js.map +1 -1
  177. package/dist/providers/murf/alignment.d.ts +10 -19
  178. package/dist/providers/murf/alignment.d.ts.map +1 -1
  179. package/dist/providers/murf/alignment.js +10 -5
  180. package/dist/providers/murf/alignment.js.map +1 -1
  181. package/dist/providers/murf/index.d.ts +15 -16
  182. package/dist/providers/murf/index.d.ts.map +1 -1
  183. package/dist/providers/murf/index.js +105 -58
  184. package/dist/providers/murf/index.js.map +1 -1
  185. package/dist/providers/openai/index.d.ts +43 -29
  186. package/dist/providers/openai/index.d.ts.map +1 -1
  187. package/dist/providers/openai/index.js +294 -106
  188. package/dist/providers/openai/index.js.map +1 -1
  189. package/dist/providers/resemble/alignment.d.ts +8 -29
  190. package/dist/providers/resemble/alignment.d.ts.map +1 -1
  191. package/dist/providers/resemble/alignment.js +9 -12
  192. package/dist/providers/resemble/alignment.js.map +1 -1
  193. package/dist/providers/resemble/index.d.ts +21 -11
  194. package/dist/providers/resemble/index.d.ts.map +1 -1
  195. package/dist/providers/resemble/index.js +89 -49
  196. package/dist/providers/resemble/index.js.map +1 -1
  197. package/dist/providers/smallest-ai/index.d.ts +47 -0
  198. package/dist/providers/smallest-ai/index.d.ts.map +1 -0
  199. package/dist/providers/smallest-ai/index.js +107 -0
  200. package/dist/providers/smallest-ai/index.js.map +1 -0
  201. package/dist/providers/xai/index.d.ts +25 -9
  202. package/dist/providers/xai/index.d.ts.map +1 -1
  203. package/dist/providers/xai/index.js +63 -40
  204. package/dist/providers/xai/index.js.map +1 -1
  205. package/dist/providers.d.ts +31 -0
  206. package/dist/providers.d.ts.map +1 -0
  207. package/dist/providers.js +16 -0
  208. package/dist/providers.js.map +1 -0
  209. package/dist/resolve-provider.d.ts.map +1 -1
  210. package/dist/resolve-provider.js +8 -51
  211. package/dist/resolve-provider.js.map +1 -1
  212. package/dist/retry-options.d.ts +6 -0
  213. package/dist/retry-options.d.ts.map +1 -0
  214. package/dist/retry-options.js +48 -0
  215. package/dist/retry-options.js.map +1 -0
  216. package/dist/speech-provider.d.ts +28 -53
  217. package/dist/speech-provider.d.ts.map +1 -1
  218. package/dist/speech-provider.js +5 -26
  219. package/dist/speech-provider.js.map +1 -1
  220. package/dist/speech-result.d.ts +8 -9
  221. package/dist/speech-result.d.ts.map +1 -1
  222. package/dist/speech-result.js.map +1 -1
  223. package/dist/speech-to-text-provider.d.ts +0 -12
  224. package/dist/speech-to-text-provider.d.ts.map +1 -1
  225. package/dist/stream-speech.d.ts +4 -2
  226. package/dist/stream-speech.d.ts.map +1 -1
  227. package/dist/stream-speech.js +36 -22
  228. package/dist/stream-speech.js.map +1 -1
  229. package/dist/timestamps.d.ts +3 -17
  230. package/dist/timestamps.d.ts.map +1 -1
  231. package/dist/turns.d.ts +9 -0
  232. package/dist/turns.d.ts.map +1 -0
  233. package/dist/turns.js +21 -0
  234. package/dist/turns.js.map +1 -0
  235. package/dist/types.d.ts +31 -0
  236. package/dist/types.d.ts.map +1 -1
  237. package/dist/volume-adjust.d.ts +0 -6
  238. package/dist/volume-adjust.d.ts.map +1 -1
  239. package/dist/volume-adjust.js +4 -16
  240. package/dist/volume-adjust.js.map +1 -1
  241. package/package.json +13 -66
  242. package/dist/stt-providers/openai/index.d.ts +0 -42
  243. package/dist/stt-providers/openai/index.d.ts.map +0 -1
  244. package/dist/stt-providers/openai/index.js +0 -184
  245. package/dist/stt-providers/openai/index.js.map +0 -1
@@ -1,137 +1,29 @@
1
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
2
  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
3
  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
4
  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
5
  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
6
  export declare function groupIntoSentences(words: readonly WordTimestamp[]): WordTimestamp[][];
47
7
  interface CueSplitOptions {
48
8
  readonly longPhraseCommaBreakChars: number;
49
9
  readonly maxCharsPerCue: number;
50
10
  readonly maxCueDurationMs: number;
51
11
  }
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
12
  export declare function splitSentenceIntoCues(sentence: readonly WordTimestamp[], options: CueSplitOptions): WordTimestamp[][];
63
13
  interface WrapOptions {
64
14
  readonly maxLineLength: number;
65
15
  readonly maxLines: number;
66
16
  }
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
17
  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
18
  export type CaptionFormat = "srt" | "vtt";
87
- /**
88
- * Options for {@link timestampsToCaptions}.
89
- */
90
19
  export interface CaptionsOptions {
91
- /** Output format. Default `"srt"`. */
92
20
  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
21
  readonly longPhraseCommaBreakChars?: number;
98
- /** Max total chars per cue. Default `maxLineLength * maxLinesPerCue`. */
99
22
  readonly maxCharsPerCue?: number;
100
- /** Max cue duration in milliseconds. Default `7000`. */
101
23
  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
24
  readonly maxLineLength?: number;
112
- /** Max lines per cue. Default `2`. */
113
25
  readonly maxLinesPerCue?: number;
114
26
  }
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
27
  export declare function timestampsToCaptions(timestamps: readonly WordTimestamp[], options?: CaptionsOptions): string;
136
28
  export {};
137
29
  //# sourceMappingURL=captions.d.ts.map
@@ -1 +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"}
1
+ {"version":3,"file":"captions.d.ts","sourceRoot":"","sources":["../src/captions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAsBrD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMxD;AAQD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMlD;AAeD,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAErD;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAErD;AAOD,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,SAAS,aAAa,EAAE,GAC9B,aAAa,EAAE,EAAE,CAcnB;AAMD,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,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;AAGD,wBAAgB,WAAW,CACzB,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,OAAO,EAAE,WAAW,GACnB,MAAM,CAmBR;AAED,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,KAAK,CAAC;AAE1C,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC;IAChC,QAAQ,CAAC,yBAAyB,CAAC,EAAE,MAAM,CAAC;IAC5C,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAEnC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;CAClC;AAWD,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,SAAS,aAAa,EAAE,EACpC,OAAO,GAAE,eAAoB,GAC5B,MAAM,CA8DR"}
package/dist/captions.js CHANGED
@@ -10,18 +10,10 @@ const TYPOGRAPHY_MAP = [
10
10
  [/\u2014/g, "-"],
11
11
  [/\u2026/g, "..."],
12
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.
13
+ // Strip C0 controls (excluding whitespace) + DEL some parsers truncate on NUL.
16
14
  // biome-ignore lint/suspicious/noControlCharactersInRegex: intentional — this regex exists to strip control characters
17
15
  const CONTROL_CHARS = /[\u0000-\u0008\u000E-\u001F\u007F]/g;
18
16
  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
17
  export function normalizeTypography(text) {
26
18
  let out = text.replace(CONTROL_CHARS, "");
27
19
  for (const [pattern, replacement] of TYPOGRAPHY_MAP) {
@@ -34,11 +26,6 @@ const VTT_ESCAPE_MAP = [
34
26
  [/</g, "&lt;"],
35
27
  [/>/g, "&gt;"],
36
28
  ];
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
29
  export function escapeVttText(text) {
43
30
  let out = text;
44
31
  for (const [pattern, replacement] of VTT_ESCAPE_MAP) {
@@ -56,48 +43,15 @@ function formatTimestamp(seconds, separator) {
56
43
  const secs = totalSeconds % SECONDS_PER_MINUTE;
57
44
  return `${String(hours).padStart(2, "0")}:${String(minutes).padStart(2, "0")}:${String(secs).padStart(2, "0")}${separator}${String(ms).padStart(3, "0")}`;
58
45
  }
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
46
  export function formatSrtTime(seconds) {
65
47
  return formatTimestamp(seconds, ",");
66
48
  }
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
49
  export function formatVttTime(seconds) {
73
50
  return formatTimestamp(seconds, ".");
74
51
  }
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.
52
+ // Sentence terminators: ASCII + CJK + Devanagari + Arabic, optional trailing quote.
81
53
  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
- */
54
+ // Limitations: "Dr."/"e.g." are treated as sentence ends; Thai etc. fall through to char/duration breaks.
101
55
  export function groupIntoSentences(words) {
102
56
  const sentences = [];
103
57
  let current = [];
@@ -113,11 +67,9 @@ export function groupIntoSentences(words) {
113
67
  }
114
68
  return sentences;
115
69
  }
116
- // Comma-equivalent soft-break punctuation: ASCII, CJK ideographic (`、`) and
117
- // fullwidth (`,`), and Arabic (`،`).
70
+ // Comma-equivalent soft breaks: ASCII + CJK + Arabic.
118
71
  const COMMA_TERMINATOR = /[,\u3001\uFF0C\u060C]["'\u2018\u2019\u201C\u201D\u300D\u300F]?$/;
119
72
  function cueCharLength(cue) {
120
- // Sum word lengths + (n-1) spaces between words.
121
73
  let chars = 0;
122
74
  for (const word of cue) {
123
75
  chars += word.text.length;
@@ -138,16 +90,7 @@ function cueDurationMs(cue) {
138
90
  }
139
91
  return (last.end - first.start) * 1000;
140
92
  }
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
- */
93
+ // Break priority: char budget → duration → comma above longPhraseCommaBreakChars.
151
94
  export function splitSentenceIntoCues(sentence, options) {
152
95
  const cues = [];
153
96
  let current = [];
@@ -173,16 +116,7 @@ export function splitSentenceIntoCues(sentence, options) {
173
116
  }
174
117
  return cues;
175
118
  }
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
- */
119
+ // Words longer than maxLineLength go on their own line; overflow appends to the last line.
186
120
  export function wrapCueText(words, options) {
187
121
  if (words.length === 0) {
188
122
  return "";
@@ -209,32 +143,10 @@ const DEFAULT_LONG_PHRASE_COMMA_BREAK_CHARS = 60;
209
143
  function identity(text) {
210
144
  return text;
211
145
  }
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
146
  export function timestampsToCaptions(timestamps, options = {}) {
233
147
  const format = options.format ?? "srt";
234
148
  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`.
149
+ // WebVTT requires the WEBVTT header per W3C §3.1, even with zero cues.
238
150
  return format === "vtt" ? "WEBVTT\n\n" : "";
239
151
  }
240
152
  const maxLineLength = options.maxLineLength ?? DEFAULT_MAX_LINE_LENGTH;
@@ -275,9 +187,7 @@ export function timestampsToCaptions(timestamps, options = {}) {
275
187
  blocks.push(`${index}\n${formatTime(first.start)} --> ${formatTime(last.end)}\n${body}\n`);
276
188
  index++;
277
189
  }
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.
190
+ // Trailing blank line required by WebVTT and expected by strict SRT parsers.
281
191
  return `${blocks.join("\n")}\n`;
282
192
  }
283
193
  //# sourceMappingURL=captions.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"captions.js","sourceRoot":"","sources":["../src/captions.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"captions.js","sourceRoot":"","sources":["../src/captions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import type { ConversationWordTimestamp, WordTimestamp } from "../timestamps.js";
2
+ import type { SilenceGap } from "./silence-detection.js";
3
+ export interface Tier2Result {
4
+ readonly budgetExceeded: boolean;
5
+ readonly mismatches: number;
6
+ readonly timestamps: readonly ConversationWordTimestamp[];
7
+ }
8
+ export declare function tier2TextMatch(args: {
9
+ timestamps: readonly WordTimestamp[];
10
+ turnTexts: readonly string[];
11
+ }): Tier2Result;
12
+ export declare function tier1SilenceAnchored(args: {
13
+ timestamps: readonly WordTimestamp[];
14
+ gaps: readonly SilenceGap[];
15
+ turnTexts: readonly string[];
16
+ }): readonly ConversationWordTimestamp[] | undefined;
17
+ export interface AttributeTimestampsResult {
18
+ readonly timestamps?: readonly ConversationWordTimestamp[];
19
+ readonly warnings: readonly string[];
20
+ }
21
+ export declare function attributeTimestamps(args: {
22
+ timestamps: readonly WordTimestamp[];
23
+ turnTexts: readonly string[];
24
+ silenceGaps: readonly SilenceGap[];
25
+ }): AttributeTimestampsResult;
26
+ //# sourceMappingURL=attribute-timestamps.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attribute-timestamps.d.ts","sourceRoot":"","sources":["../../src/conversation/attribute-timestamps.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,yBAAyB,EACzB,aAAa,EACd,MAAM,kBAAkB,CAAC;AAE1B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AA6DzD,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,SAAS,yBAAyB,EAAE,CAAC;CAC3D;AAGD,wBAAgB,cAAc,CAAC,IAAI,EAAE;IACnC,UAAU,EAAE,SAAS,aAAa,EAAE,CAAC;IACrC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;CAC9B,GAAG,WAAW,CA4Id;AAYD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IACzC,UAAU,EAAE,SAAS,aAAa,EAAE,CAAC;IACrC,IAAI,EAAE,SAAS,UAAU,EAAE,CAAC;IAC5B,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;CAC9B,GAAG,SAAS,yBAAyB,EAAE,GAAG,SAAS,CAqEnD;AAED,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,yBAAyB,EAAE,CAAC;IAC3D,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE;IACxC,UAAU,EAAE,SAAS,aAAa,EAAE,CAAC;IACrC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7B,WAAW,EAAE,SAAS,UAAU,EAAE,CAAC;CACpC,GAAG,yBAAyB,CAwC5B"}
@@ -0,0 +1,276 @@
1
+ import { distributeWordsAcrossTurns } from "./proportional-fill.js";
2
+ const NORMALIZE_LEAD_RE = /^[^\p{L}\p{N}'-]+/u;
3
+ const NORMALIZE_TRAIL_RE = /[^\p{L}\p{N}'-]+$/u;
4
+ const WHITESPACE_SPLIT_RE = /\s+/;
5
+ function normalizeWord(s) {
6
+ return s
7
+ .toLowerCase()
8
+ .replace(NORMALIZE_LEAD_RE, "")
9
+ .replace(NORMALIZE_TRAIL_RE, "");
10
+ }
11
+ function tokenizeTurn(text) {
12
+ return text
13
+ .split(WHITESPACE_SPLIT_RE)
14
+ .map(normalizeWord)
15
+ .filter((t) => t.length > 0);
16
+ }
17
+ function levenshteinAtMost1(a, b) {
18
+ if (a === b) {
19
+ return true;
20
+ }
21
+ const la = a.length;
22
+ const lb = b.length;
23
+ if (Math.abs(la - lb) > 1) {
24
+ return false;
25
+ }
26
+ // One substitution.
27
+ if (la === lb) {
28
+ let diffs = 0;
29
+ for (let i = 0; i < la; i++) {
30
+ if (a[i] !== b[i]) {
31
+ diffs++;
32
+ if (diffs > 1) {
33
+ return false;
34
+ }
35
+ }
36
+ }
37
+ return true;
38
+ }
39
+ // One insertion or deletion.
40
+ const [shorter, longer] = la < lb ? [a, b] : [b, a];
41
+ let i = 0;
42
+ let j = 0;
43
+ let skipped = false;
44
+ while (i < shorter.length && j < longer.length) {
45
+ if (shorter[i] === longer[j]) {
46
+ i++;
47
+ j++;
48
+ }
49
+ else if (skipped) {
50
+ return false;
51
+ }
52
+ else {
53
+ skipped = true;
54
+ j++;
55
+ }
56
+ }
57
+ return true;
58
+ }
59
+ // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: tiered text-match is a single state machine — splitting hurts readability more than the score helps
60
+ export function tier2TextMatch(args) {
61
+ const { timestamps, turnTexts } = args;
62
+ if (turnTexts.length === 0) {
63
+ return {
64
+ timestamps: [],
65
+ mismatches: 0,
66
+ budgetExceeded: timestamps.some((t) => normalizeWord(t.text).length > 0),
67
+ };
68
+ }
69
+ const turnTokens = turnTexts.map((t) => tokenizeTurn(t));
70
+ const totalExpected = turnTokens.reduce((n, t) => n + t.length, 0);
71
+ // Per-turn budget: max(2, floor(0.2 * tokens_in_turn)).
72
+ const perTurnBudget = turnTokens.map((t) => Math.max(2, Math.floor(0.2 * t.length)));
73
+ const perTurnUsed = turnTokens.map(() => 0);
74
+ const out = [];
75
+ let turnIndex = 0;
76
+ let tokenIndex = 0;
77
+ let totalMismatches = 0;
78
+ let budgetExceeded = false;
79
+ const recordDrift = () => {
80
+ totalMismatches++;
81
+ perTurnUsed[turnIndex] = (perTurnUsed[turnIndex] ?? 0) + 1;
82
+ if ((perTurnUsed[turnIndex] ?? 0) > (perTurnBudget[turnIndex] ?? 0)) {
83
+ budgetExceeded = true;
84
+ }
85
+ };
86
+ for (let i = 0; i < timestamps.length; i++) {
87
+ const ts = timestamps[i];
88
+ const observed = normalizeWord(ts.text);
89
+ if (observed.length === 0) {
90
+ // Skip pure-punctuation tokens entirely.
91
+ continue;
92
+ }
93
+ // Advance turn boundary if current turn is exhausted.
94
+ while (turnIndex < turnTokens.length &&
95
+ tokenIndex >= (turnTokens[turnIndex]?.length ?? 0)) {
96
+ turnIndex++;
97
+ tokenIndex = 0;
98
+ }
99
+ if (turnIndex >= turnTokens.length) {
100
+ // Over-emit: provider returned more words than expected.
101
+ budgetExceeded = true;
102
+ out.push({
103
+ text: ts.text,
104
+ start: ts.start,
105
+ end: ts.end,
106
+ turnIndex: turnTokens.length - 1,
107
+ });
108
+ continue;
109
+ }
110
+ const expected = turnTokens[turnIndex]?.[tokenIndex] ?? "";
111
+ if (observed === expected || levenshteinAtMost1(observed, expected)) {
112
+ out.push({
113
+ text: ts.text,
114
+ start: ts.start,
115
+ end: ts.end,
116
+ turnIndex,
117
+ });
118
+ tokenIndex++;
119
+ continue;
120
+ }
121
+ // Look-ahead 1: is observed actually the NEXT expected? (provider dropped a word)
122
+ const expectedNext = turnTokens[turnIndex]?.[tokenIndex + 1];
123
+ if (expectedNext &&
124
+ (observed === expectedNext || levenshteinAtMost1(observed, expectedNext))) {
125
+ // Skip the dropped expected word. This is recovered drift, but still drift.
126
+ recordDrift();
127
+ tokenIndex++;
128
+ out.push({
129
+ text: ts.text,
130
+ start: ts.start,
131
+ end: ts.end,
132
+ turnIndex,
133
+ });
134
+ tokenIndex++;
135
+ continue;
136
+ }
137
+ // Look-behind 1 on observed: is the NEXT observed actually the current expected? (provider inserted)
138
+ const observedNext = timestamps[i + 1]
139
+ ? normalizeWord(timestamps[i + 1].text)
140
+ : undefined;
141
+ if (observedNext &&
142
+ (observedNext === expected || levenshteinAtMost1(observedNext, expected))) {
143
+ // Treat observed as inserted: emit at current turn, don't advance tokenIndex.
144
+ recordDrift();
145
+ out.push({
146
+ text: ts.text,
147
+ start: ts.start,
148
+ end: ts.end,
149
+ turnIndex,
150
+ });
151
+ continue;
152
+ }
153
+ // Genuine mismatch: count against per-turn budget.
154
+ recordDrift();
155
+ out.push({
156
+ text: ts.text,
157
+ start: ts.start,
158
+ end: ts.end,
159
+ turnIndex,
160
+ });
161
+ tokenIndex++;
162
+ }
163
+ // End-of-stream consumption check at 95%.
164
+ const consumedExpected = turnTokens.slice(0, turnIndex).reduce((n, t) => n + t.length, 0) +
165
+ tokenIndex;
166
+ if (totalExpected > 0 &&
167
+ consumedExpected < Math.floor(totalExpected * 0.95)) {
168
+ budgetExceeded = true;
169
+ }
170
+ return {
171
+ timestamps: out,
172
+ mismatches: totalMismatches,
173
+ budgetExceeded,
174
+ };
175
+ }
176
+ const FALLBACK_TEXT_MATCH_WARNING = "speech-sdk: timestamp attribution fell back to text-matching (silence boundaries unclear)";
177
+ const FALLBACK_PROPORTIONAL_WARNING = "speech-sdk: timestamp attribution fell back to proportional distribution; treat per-word turnIndex as approximate.";
178
+ const TIMESTAMPS_UNAVAILABLE_WARNING = "speech-sdk: timestamp attribution unavailable; provider/STT returned no word timestamps.";
179
+ const MIN_TIER1_TOKEN_RATIO = 0.35;
180
+ const MAX_TIER1_TOKEN_RATIO = 2.5;
181
+ // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: silence-anchored partition is a single algorithm — splitting hurts readability more than the score helps
182
+ export function tier1SilenceAnchored(args) {
183
+ const { timestamps, gaps, turnTexts } = args;
184
+ const turnCount = turnTexts.length;
185
+ if (turnCount <= 1) {
186
+ return timestamps.map((w) => ({ ...w, turnIndex: 0 }));
187
+ }
188
+ if (timestamps.length === 0) {
189
+ return;
190
+ }
191
+ const firstWordStartSec = timestamps[0]?.start ?? 0;
192
+ const lastWordEndSec = timestamps.at(-1)?.end ?? 0;
193
+ const candidateGaps = gaps.filter((g) => {
194
+ const midpointSec = (g.startMs + g.endMs) / 2 / 1000;
195
+ return midpointSec > firstWordStartSec && midpointSec < lastWordEndSec;
196
+ });
197
+ if (candidateGaps.length < turnCount - 1) {
198
+ return;
199
+ }
200
+ const selectedGaps = [...candidateGaps]
201
+ .sort((a, b) => b.durationMs - a.durationMs)
202
+ .slice(0, turnCount - 1)
203
+ .sort((a, b) => a.startMs - b.startMs);
204
+ // Boundary times in seconds (midpoint of each gap).
205
+ const boundariesSec = selectedGaps.map((g) => (g.startMs + g.endMs) / 2 / 1000);
206
+ // Partition words by which segment each word's midpoint falls into.
207
+ const partitions = Array.from({ length: turnCount }, () => []);
208
+ for (const w of timestamps) {
209
+ const midpoint = (w.start + w.end) / 2;
210
+ let turnIndex = 0;
211
+ while (turnIndex < boundariesSec.length &&
212
+ midpoint >= (boundariesSec[turnIndex] ?? Number.POSITIVE_INFINITY)) {
213
+ turnIndex++;
214
+ }
215
+ partitions[turnIndex]?.push(w);
216
+ }
217
+ // Validate: no partition empty.
218
+ if (partitions.some((p) => p.length === 0)) {
219
+ return;
220
+ }
221
+ const expectedCounts = turnTexts.map((t) => tokenizeTurn(t).length);
222
+ for (let i = 0; i < partitions.length; i++) {
223
+ const expected = expectedCounts[i] ?? 0;
224
+ if (expected === 0) {
225
+ return;
226
+ }
227
+ const ratio = (partitions[i]?.length ?? 0) / expected;
228
+ if (ratio < MIN_TIER1_TOKEN_RATIO || ratio > MAX_TIER1_TOKEN_RATIO) {
229
+ return;
230
+ }
231
+ }
232
+ const out = [];
233
+ for (let i = 0; i < partitions.length; i++) {
234
+ for (const w of partitions[i] ?? []) {
235
+ out.push({ ...w, turnIndex: i });
236
+ }
237
+ }
238
+ return out;
239
+ }
240
+ export function attributeTimestamps(args) {
241
+ const { timestamps, turnTexts, silenceGaps } = args;
242
+ const observed = timestamps.filter((w) => normalizeWord(w.text).length > 0);
243
+ if (observed.length === 0 || turnTexts.length === 0) {
244
+ return {
245
+ timestamps: undefined,
246
+ warnings: [TIMESTAMPS_UNAVAILABLE_WARNING],
247
+ };
248
+ }
249
+ // Tier 1: silence-anchored partitioning.
250
+ const tier1 = tier1SilenceAnchored({
251
+ timestamps: observed,
252
+ gaps: silenceGaps,
253
+ turnTexts,
254
+ });
255
+ if (tier1) {
256
+ return { timestamps: tier1, warnings: [] };
257
+ }
258
+ // Tier 2: improved text-match.
259
+ const tier2 = tier2TextMatch({ timestamps: observed, turnTexts });
260
+ if (!tier2.budgetExceeded) {
261
+ return {
262
+ timestamps: tier2.timestamps,
263
+ warnings: [
264
+ `${FALLBACK_TEXT_MATCH_WARNING}; ${tier2.mismatches} word(s) tolerated as mismatches.`,
265
+ ],
266
+ };
267
+ }
268
+ // Tier 3: proportional distribution.
269
+ const expectedTokensPerTurn = turnTexts.map((t) => t.split(WHITESPACE_SPLIT_RE).filter((s) => s.length > 0).length);
270
+ const tier3 = distributeWordsAcrossTurns(observed, expectedTokensPerTurn);
271
+ return {
272
+ timestamps: tier3,
273
+ warnings: [FALLBACK_PROPORTIONAL_WARNING],
274
+ };
275
+ }
276
+ //# sourceMappingURL=attribute-timestamps.js.map