@pico-brief/speech-services 1.0.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 (242) hide show
  1. package/README.md +177 -0
  2. package/dist/audio-sampler.d.ts +9 -0
  3. package/dist/audio-sampler.d.ts.map +1 -0
  4. package/dist/audio-sampler.js +135 -0
  5. package/dist/audio-sampler.js.map +1 -0
  6. package/dist/client.d.ts +3 -0
  7. package/dist/client.d.ts.map +1 -0
  8. package/dist/client.js +23 -0
  9. package/dist/client.js.map +1 -0
  10. package/dist/detect-locale.d.ts +3 -0
  11. package/dist/detect-locale.d.ts.map +1 -0
  12. package/dist/detect-locale.js +73 -0
  13. package/dist/detect-locale.js.map +1 -0
  14. package/dist/errors.d.ts +7 -0
  15. package/dist/errors.d.ts.map +1 -0
  16. package/dist/errors.js +13 -0
  17. package/dist/errors.js.map +1 -0
  18. package/dist/fetch-voices.d.ts +3 -0
  19. package/dist/fetch-voices.d.ts.map +1 -0
  20. package/dist/fetch-voices.js +50 -0
  21. package/dist/fetch-voices.js.map +1 -0
  22. package/dist/index.d.ts +10 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +12 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/providers/assemblyai/index.d.ts +2 -0
  27. package/dist/providers/assemblyai/index.d.ts.map +1 -0
  28. package/dist/providers/assemblyai/index.js +2 -0
  29. package/dist/providers/assemblyai/index.js.map +1 -0
  30. package/dist/providers/assemblyai/transcribe.d.ts +3 -0
  31. package/dist/providers/assemblyai/transcribe.d.ts.map +1 -0
  32. package/dist/providers/assemblyai/transcribe.js +92 -0
  33. package/dist/providers/assemblyai/transcribe.js.map +1 -0
  34. package/dist/providers/assemblyai/types.d.ts +18 -0
  35. package/dist/providers/assemblyai/types.d.ts.map +1 -0
  36. package/dist/providers/assemblyai/types.js +2 -0
  37. package/dist/providers/assemblyai/types.js.map +1 -0
  38. package/dist/providers/azure/batch-transcribe.d.ts +3 -0
  39. package/dist/providers/azure/batch-transcribe.d.ts.map +1 -0
  40. package/dist/providers/azure/batch-transcribe.js +118 -0
  41. package/dist/providers/azure/batch-transcribe.js.map +1 -0
  42. package/dist/providers/azure/detect-languages.d.ts +3 -0
  43. package/dist/providers/azure/detect-languages.d.ts.map +1 -0
  44. package/dist/providers/azure/detect-languages.js +15 -0
  45. package/dist/providers/azure/detect-languages.js.map +1 -0
  46. package/dist/providers/azure/fetch-voices.d.ts +3 -0
  47. package/dist/providers/azure/fetch-voices.d.ts.map +1 -0
  48. package/dist/providers/azure/fetch-voices.js +22 -0
  49. package/dist/providers/azure/fetch-voices.js.map +1 -0
  50. package/dist/providers/azure/helpers.d.ts +2 -0
  51. package/dist/providers/azure/helpers.d.ts.map +1 -0
  52. package/dist/providers/azure/helpers.js +9 -0
  53. package/dist/providers/azure/helpers.js.map +1 -0
  54. package/dist/providers/azure/index.d.ts +5 -0
  55. package/dist/providers/azure/index.d.ts.map +1 -0
  56. package/dist/providers/azure/index.js +5 -0
  57. package/dist/providers/azure/index.js.map +1 -0
  58. package/dist/providers/azure/synthesize.d.ts +3 -0
  59. package/dist/providers/azure/synthesize.d.ts.map +1 -0
  60. package/dist/providers/azure/synthesize.js +57 -0
  61. package/dist/providers/azure/synthesize.js.map +1 -0
  62. package/dist/providers/azure/transcribe.d.ts +5 -0
  63. package/dist/providers/azure/transcribe.d.ts.map +1 -0
  64. package/dist/providers/azure/transcribe.js +75 -0
  65. package/dist/providers/azure/transcribe.js.map +1 -0
  66. package/dist/providers/azure/types.d.ts +48 -0
  67. package/dist/providers/azure/types.d.ts.map +1 -0
  68. package/dist/providers/azure/types.js +2 -0
  69. package/dist/providers/azure/types.js.map +1 -0
  70. package/dist/providers/cartesia/fetch-voices.d.ts +3 -0
  71. package/dist/providers/cartesia/fetch-voices.d.ts.map +1 -0
  72. package/dist/providers/cartesia/fetch-voices.js +37 -0
  73. package/dist/providers/cartesia/fetch-voices.js.map +1 -0
  74. package/dist/providers/cartesia/index.d.ts +3 -0
  75. package/dist/providers/cartesia/index.d.ts.map +1 -0
  76. package/dist/providers/cartesia/index.js +3 -0
  77. package/dist/providers/cartesia/index.js.map +1 -0
  78. package/dist/providers/cartesia/synthesize.d.ts +3 -0
  79. package/dist/providers/cartesia/synthesize.d.ts.map +1 -0
  80. package/dist/providers/cartesia/synthesize.js +54 -0
  81. package/dist/providers/cartesia/synthesize.js.map +1 -0
  82. package/dist/providers/cartesia/types.d.ts +14 -0
  83. package/dist/providers/cartesia/types.d.ts.map +1 -0
  84. package/dist/providers/cartesia/types.js +3 -0
  85. package/dist/providers/cartesia/types.js.map +1 -0
  86. package/dist/providers/deepgram/fetch-voices.d.ts +3 -0
  87. package/dist/providers/deepgram/fetch-voices.d.ts.map +1 -0
  88. package/dist/providers/deepgram/fetch-voices.js +27 -0
  89. package/dist/providers/deepgram/fetch-voices.js.map +1 -0
  90. package/dist/providers/deepgram/index.d.ts +4 -0
  91. package/dist/providers/deepgram/index.d.ts.map +1 -0
  92. package/dist/providers/deepgram/index.js +4 -0
  93. package/dist/providers/deepgram/index.js.map +1 -0
  94. package/dist/providers/deepgram/synthesize.d.ts +3 -0
  95. package/dist/providers/deepgram/synthesize.d.ts.map +1 -0
  96. package/dist/providers/deepgram/synthesize.js +31 -0
  97. package/dist/providers/deepgram/synthesize.js.map +1 -0
  98. package/dist/providers/deepgram/transcribe.d.ts +3 -0
  99. package/dist/providers/deepgram/transcribe.d.ts.map +1 -0
  100. package/dist/providers/deepgram/transcribe.js +53 -0
  101. package/dist/providers/deepgram/transcribe.js.map +1 -0
  102. package/dist/providers/deepgram/types.d.ts +39 -0
  103. package/dist/providers/deepgram/types.d.ts.map +1 -0
  104. package/dist/providers/deepgram/types.js +2 -0
  105. package/dist/providers/deepgram/types.js.map +1 -0
  106. package/dist/providers/elevenlabs/fetch-voices.d.ts +3 -0
  107. package/dist/providers/elevenlabs/fetch-voices.d.ts.map +1 -0
  108. package/dist/providers/elevenlabs/fetch-voices.js +27 -0
  109. package/dist/providers/elevenlabs/fetch-voices.js.map +1 -0
  110. package/dist/providers/elevenlabs/index.d.ts +4 -0
  111. package/dist/providers/elevenlabs/index.d.ts.map +1 -0
  112. package/dist/providers/elevenlabs/index.js +4 -0
  113. package/dist/providers/elevenlabs/index.js.map +1 -0
  114. package/dist/providers/elevenlabs/synthesize.d.ts +3 -0
  115. package/dist/providers/elevenlabs/synthesize.d.ts.map +1 -0
  116. package/dist/providers/elevenlabs/synthesize.js +43 -0
  117. package/dist/providers/elevenlabs/synthesize.js.map +1 -0
  118. package/dist/providers/elevenlabs/transcribe.d.ts +3 -0
  119. package/dist/providers/elevenlabs/transcribe.d.ts.map +1 -0
  120. package/dist/providers/elevenlabs/transcribe.js +50 -0
  121. package/dist/providers/elevenlabs/transcribe.js.map +1 -0
  122. package/dist/providers/elevenlabs/types.d.ts +24 -0
  123. package/dist/providers/elevenlabs/types.d.ts.map +1 -0
  124. package/dist/providers/elevenlabs/types.js +2 -0
  125. package/dist/providers/elevenlabs/types.js.map +1 -0
  126. package/dist/providers/google/fetch-voices.d.ts +3 -0
  127. package/dist/providers/google/fetch-voices.d.ts.map +1 -0
  128. package/dist/providers/google/fetch-voices.js +28 -0
  129. package/dist/providers/google/fetch-voices.js.map +1 -0
  130. package/dist/providers/google/helpers.d.ts +10 -0
  131. package/dist/providers/google/helpers.d.ts.map +1 -0
  132. package/dist/providers/google/helpers.js +15 -0
  133. package/dist/providers/google/helpers.js.map +1 -0
  134. package/dist/providers/google/index.d.ts +4 -0
  135. package/dist/providers/google/index.d.ts.map +1 -0
  136. package/dist/providers/google/index.js +4 -0
  137. package/dist/providers/google/index.js.map +1 -0
  138. package/dist/providers/google/synthesize.d.ts +3 -0
  139. package/dist/providers/google/synthesize.d.ts.map +1 -0
  140. package/dist/providers/google/synthesize.js +35 -0
  141. package/dist/providers/google/synthesize.js.map +1 -0
  142. package/dist/providers/google/transcribe.d.ts +3 -0
  143. package/dist/providers/google/transcribe.d.ts.map +1 -0
  144. package/dist/providers/google/transcribe.js +117 -0
  145. package/dist/providers/google/transcribe.js.map +1 -0
  146. package/dist/providers/google/types.d.ts +43 -0
  147. package/dist/providers/google/types.d.ts.map +1 -0
  148. package/dist/providers/google/types.js +3 -0
  149. package/dist/providers/google/types.js.map +1 -0
  150. package/dist/providers/openai/fetch-voices.d.ts +3 -0
  151. package/dist/providers/openai/fetch-voices.d.ts.map +1 -0
  152. package/dist/providers/openai/fetch-voices.js +14 -0
  153. package/dist/providers/openai/fetch-voices.js.map +1 -0
  154. package/dist/providers/openai/index.d.ts +4 -0
  155. package/dist/providers/openai/index.d.ts.map +1 -0
  156. package/dist/providers/openai/index.js +4 -0
  157. package/dist/providers/openai/index.js.map +1 -0
  158. package/dist/providers/openai/synthesize.d.ts +3 -0
  159. package/dist/providers/openai/synthesize.d.ts.map +1 -0
  160. package/dist/providers/openai/synthesize.js +37 -0
  161. package/dist/providers/openai/synthesize.js.map +1 -0
  162. package/dist/providers/openai/transcribe.d.ts +3 -0
  163. package/dist/providers/openai/transcribe.d.ts.map +1 -0
  164. package/dist/providers/openai/transcribe.js +58 -0
  165. package/dist/providers/openai/transcribe.js.map +1 -0
  166. package/dist/providers/openai/types.d.ts +18 -0
  167. package/dist/providers/openai/types.d.ts.map +1 -0
  168. package/dist/providers/openai/types.js +2 -0
  169. package/dist/providers/openai/types.js.map +1 -0
  170. package/dist/providers/playht/fetch-voices.d.ts +3 -0
  171. package/dist/providers/playht/fetch-voices.d.ts.map +1 -0
  172. package/dist/providers/playht/fetch-voices.js +25 -0
  173. package/dist/providers/playht/fetch-voices.js.map +1 -0
  174. package/dist/providers/playht/index.d.ts +3 -0
  175. package/dist/providers/playht/index.d.ts.map +1 -0
  176. package/dist/providers/playht/index.js +3 -0
  177. package/dist/providers/playht/index.js.map +1 -0
  178. package/dist/providers/playht/synthesize.d.ts +3 -0
  179. package/dist/providers/playht/synthesize.d.ts.map +1 -0
  180. package/dist/providers/playht/synthesize.js +41 -0
  181. package/dist/providers/playht/synthesize.js.map +1 -0
  182. package/dist/providers/playht/types.d.ts +11 -0
  183. package/dist/providers/playht/types.d.ts.map +1 -0
  184. package/dist/providers/playht/types.js +2 -0
  185. package/dist/providers/playht/types.js.map +1 -0
  186. package/dist/providers/revai/index.d.ts +2 -0
  187. package/dist/providers/revai/index.d.ts.map +1 -0
  188. package/dist/providers/revai/index.js +2 -0
  189. package/dist/providers/revai/index.js.map +1 -0
  190. package/dist/providers/revai/transcribe.d.ts +3 -0
  191. package/dist/providers/revai/transcribe.d.ts.map +1 -0
  192. package/dist/providers/revai/transcribe.js +97 -0
  193. package/dist/providers/revai/transcribe.js.map +1 -0
  194. package/dist/providers/revai/types.d.ts +23 -0
  195. package/dist/providers/revai/types.d.ts.map +1 -0
  196. package/dist/providers/revai/types.js +2 -0
  197. package/dist/providers/revai/types.js.map +1 -0
  198. package/dist/providers/speechmatics/detect-languages.d.ts +3 -0
  199. package/dist/providers/speechmatics/detect-languages.d.ts.map +1 -0
  200. package/dist/providers/speechmatics/detect-languages.js +24 -0
  201. package/dist/providers/speechmatics/detect-languages.js.map +1 -0
  202. package/dist/providers/speechmatics/helpers.d.ts +4 -0
  203. package/dist/providers/speechmatics/helpers.d.ts.map +1 -0
  204. package/dist/providers/speechmatics/helpers.js +57 -0
  205. package/dist/providers/speechmatics/helpers.js.map +1 -0
  206. package/dist/providers/speechmatics/index.d.ts +3 -0
  207. package/dist/providers/speechmatics/index.d.ts.map +1 -0
  208. package/dist/providers/speechmatics/index.js +3 -0
  209. package/dist/providers/speechmatics/index.js.map +1 -0
  210. package/dist/providers/speechmatics/transcribe.d.ts +3 -0
  211. package/dist/providers/speechmatics/transcribe.d.ts.map +1 -0
  212. package/dist/providers/speechmatics/transcribe.js +61 -0
  213. package/dist/providers/speechmatics/transcribe.js.map +1 -0
  214. package/dist/providers/speechmatics/types.d.ts +27 -0
  215. package/dist/providers/speechmatics/types.d.ts.map +1 -0
  216. package/dist/providers/speechmatics/types.js +2 -0
  217. package/dist/providers/speechmatics/types.js.map +1 -0
  218. package/dist/synthesize.d.ts +4 -0
  219. package/dist/synthesize.d.ts.map +1 -0
  220. package/dist/synthesize.js +73 -0
  221. package/dist/synthesize.js.map +1 -0
  222. package/dist/transcribe.d.ts +3 -0
  223. package/dist/transcribe.d.ts.map +1 -0
  224. package/dist/transcribe.js +55 -0
  225. package/dist/transcribe.js.map +1 -0
  226. package/dist/types.d.ts +361 -0
  227. package/dist/types.d.ts.map +1 -0
  228. package/dist/types.js +3 -0
  229. package/dist/types.js.map +1 -0
  230. package/dist/utils.d.ts +19 -0
  231. package/dist/utils.d.ts.map +1 -0
  232. package/dist/utils.js +101 -0
  233. package/dist/utils.js.map +1 -0
  234. package/dist/voice-cache.d.ts +9 -0
  235. package/dist/voice-cache.d.ts.map +1 -0
  236. package/dist/voice-cache.js +21 -0
  237. package/dist/voice-cache.js.map +1 -0
  238. package/dist/voice-resolver.d.ts +7 -0
  239. package/dist/voice-resolver.d.ts.map +1 -0
  240. package/dist/voice-resolver.js +82 -0
  241. package/dist/voice-resolver.js.map +1 -0
  242. package/package.json +100 -0
package/README.md ADDED
@@ -0,0 +1,177 @@
1
+ # @pico-brief/speech-services
2
+
3
+ Unified speech-to-text and text-to-speech library wrapping 10 provider APIs behind consistent interfaces. Zero external dependencies — Node.js 18+ built-ins only.
4
+
5
+ ## Providers
6
+
7
+ | Provider | STT | TTS | Language Detection |
8
+ |----------|-----|-----|--------------------|
9
+ | AssemblyAI | Yes | - | Yes |
10
+ | Azure | Yes (fast + batch) | Yes | Yes |
11
+ | Cartesia | - | Yes | - |
12
+ | Deepgram | Yes | Yes | Yes |
13
+ | ElevenLabs | Yes | Yes | Yes |
14
+ | Google | Yes | Yes | - |
15
+ | OpenAI | Yes | Yes | Yes |
16
+ | PlayHT | - | Yes | - |
17
+ | Rev.ai | Yes | - | - |
18
+ | Speechmatics | Yes | - | Yes |
19
+
20
+ ## Installation
21
+
22
+ ```bash
23
+ npm install @pico-brief/speech-services
24
+ ```
25
+
26
+ ## Quick Start
27
+
28
+ ### Client API (recommended)
29
+
30
+ ```typescript
31
+ import { createSpeechClient } from "@pico-brief/speech-services";
32
+
33
+ const client = createSpeechClient({
34
+ openai: { apiKey: "sk-..." },
35
+ azure: { subscriptionKey: "...", region: "eastus" },
36
+ });
37
+
38
+ // Transcribe
39
+ const transcript = await client.transcribe({
40
+ provider: "openai",
41
+ audio: audioBuffer,
42
+ languages: ["en"],
43
+ });
44
+ console.log(transcript.text);
45
+ console.log(transcript.words); // word-level timestamps
46
+
47
+ // Synthesize (voice auto-selected by language + gender)
48
+ const speech = await client.synthesize({
49
+ provider: "azure",
50
+ text: "Hello, world!",
51
+ languages: ["en-US"],
52
+ gender: "female",
53
+ });
54
+ // speech.audio is a Buffer, speech.voice is the resolved voice ID
55
+
56
+ // Detect languages
57
+ const languages = await client.detectLocales({
58
+ provider: "openai",
59
+ audio: audioBuffer,
60
+ });
61
+ // Map { "en" => 1 }
62
+ ```
63
+
64
+ ### Standalone Functions (tree-shakeable)
65
+
66
+ ```typescript
67
+ import { transcribe, synthesize } from "@pico-brief/speech-services";
68
+
69
+ const result = await transcribe(
70
+ { openai: { apiKey: "sk-..." } },
71
+ { provider: "openai", audio: audioBuffer },
72
+ );
73
+ ```
74
+
75
+ ### Direct Provider Import
76
+
77
+ ```typescript
78
+ import { transcribe } from "@pico-brief/speech-services/providers/deepgram";
79
+
80
+ const result = await transcribe(
81
+ { apiKey: "your-deepgram-key" },
82
+ audioBuffer,
83
+ ["en"],
84
+ { model: "nova-2", smartFormat: true },
85
+ );
86
+ ```
87
+
88
+ ## Audio Input
89
+
90
+ All transcription functions accept `Buffer | string` for audio:
91
+
92
+ - **Buffer**: Raw audio bytes (MP3, WAV, etc.)
93
+ - **String (URL)**: `https://...` or `gs://...` — each provider handles URLs natively where possible
94
+
95
+ ## Voice Resolution
96
+
97
+ When synthesizing, the `voice` parameter is optional. If omitted, a voice is auto-selected based on `languages` and `gender`:
98
+
99
+ ```typescript
100
+ // Explicit voice
101
+ await client.synthesize({ provider: "azure", text: "Hi", voice: "en-US-JennyNeural" });
102
+
103
+ // Auto-select: female English voice
104
+ await client.synthesize({ provider: "azure", text: "Hi", languages: ["en-US"], gender: "female" });
105
+
106
+ // Voice by name (fuzzy matched)
107
+ await client.synthesize({ provider: "azure", text: "Hi", voice: "Jenny" });
108
+ ```
109
+
110
+ Resolution tiers: exact ID → exact name → locale extraction → base language fallback. Gender is a preference, not a hard filter.
111
+
112
+ ## Provider Options
113
+
114
+ Each provider has specific options accessible via `providerOptions`:
115
+
116
+ ```typescript
117
+ await client.transcribe({
118
+ provider: "assemblyai",
119
+ audio: audioBuffer,
120
+ providerOptions: {
121
+ speechModel: "universal",
122
+ pollInterval: 3000,
123
+ timeout: 300000,
124
+ },
125
+ });
126
+
127
+ await client.synthesize({
128
+ provider: "elevenlabs",
129
+ text: "Hello",
130
+ voice: "Rachel",
131
+ providerOptions: {
132
+ modelId: "eleven_multilingual_v2",
133
+ stability: 0.5,
134
+ similarityBoost: 0.75,
135
+ },
136
+ });
137
+ ```
138
+
139
+ ## Language Detection
140
+
141
+ ```typescript
142
+ // With ffmpeg (recommended for long audio — samples clips from different positions)
143
+ const languages = await client.detectLocales({
144
+ provider: "azure",
145
+ audio: audioBuffer,
146
+ ffmpegPath: "/usr/local/bin/ffmpeg",
147
+ });
148
+
149
+ // Without ffmpeg (truncates to first ~30s)
150
+ const languages = await client.detectLocales({
151
+ provider: "azure",
152
+ audio: audioBuffer,
153
+ maxBytes: 500_000,
154
+ });
155
+ ```
156
+
157
+ ## Error Handling
158
+
159
+ All errors are thrown as `SpeechServiceError` with structured fields:
160
+
161
+ ```typescript
162
+ import { SpeechServiceError } from "@pico-brief/speech-services";
163
+
164
+ try {
165
+ await client.transcribe({ provider: "openai", audio: buffer });
166
+ } catch (err) {
167
+ if (err instanceof SpeechServiceError) {
168
+ console.log(err.code); // "API_ERROR", "TIMEOUT", "NOT_CONFIGURED", etc.
169
+ console.log(err.provider); // "openai"
170
+ console.log(err.statusCode); // 401
171
+ }
172
+ }
173
+ ```
174
+
175
+ ## License
176
+
177
+ MIT
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Extracts short audio clips from different positions in the audio,
3
+ * runs language detection on each clip, and aggregates the results.
4
+ *
5
+ * Requires ffmpeg for clip extraction. Audio duration is determined
6
+ * via @pico-brief/audio-duration (no ffprobe needed).
7
+ */
8
+ export declare function sampleAndDetect(audio: Buffer | string, ffmpegPath: string, detectFn: (clip: Buffer) => Promise<Map<string, number>>): Promise<Map<string, number>>;
9
+ //# sourceMappingURL=audio-sampler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audio-sampler.d.ts","sourceRoot":"","sources":["../src/audio-sampler.ts"],"names":[],"mappings":"AAaA;;;;;;GAMG;AACH,wBAAsB,eAAe,CACjC,KAAK,EAAE,MAAM,GAAG,MAAM,EACtB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GACzD,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAiE9B"}
@@ -0,0 +1,135 @@
1
+ import { execFile } from "node:child_process";
2
+ import { promisify } from "node:util";
3
+ import { tmpdir } from "node:os";
4
+ import { join } from "node:path";
5
+ import { writeFileSync, readFileSync, unlinkSync } from "node:fs";
6
+ import { randomUUID } from "node:crypto";
7
+ import { getAudioDuration } from "@pico-brief/audio-duration";
8
+ import { SpeechServiceError } from "./errors.js";
9
+ const execFileAsync = promisify(execFile);
10
+ // ─── Public API ─────────────────────────────────────────────────────────────
11
+ /**
12
+ * Extracts short audio clips from different positions in the audio,
13
+ * runs language detection on each clip, and aggregates the results.
14
+ *
15
+ * Requires ffmpeg for clip extraction. Audio duration is determined
16
+ * via @pico-brief/audio-duration (no ffprobe needed).
17
+ */
18
+ export async function sampleAndDetect(audio, ffmpegPath, detectFn) {
19
+ const tempFiles = [];
20
+ try {
21
+ // Prepare input path (save Buffer to temp file if needed)
22
+ let inputPath;
23
+ if (Buffer.isBuffer(audio)) {
24
+ inputPath = tempPath("input");
25
+ writeFileSync(inputPath, audio);
26
+ tempFiles.push(inputPath);
27
+ }
28
+ else {
29
+ inputPath = audio;
30
+ }
31
+ // Get duration via @pico-brief/audio-duration
32
+ const audioBytes = Buffer.isBuffer(audio)
33
+ ? audio
34
+ : readFileSync(inputPath);
35
+ const ab = audioBytes.buffer.slice(audioBytes.byteOffset, audioBytes.byteOffset + audioBytes.byteLength);
36
+ const duration = getAudioDuration(ab);
37
+ if (duration <= 0) {
38
+ throw new SpeechServiceError("Failed to determine audio duration", "INVALID_INPUT");
39
+ }
40
+ // Build sampling ranges
41
+ const ranges = buildSamplingRanges(duration);
42
+ // Extract each clip and run detection
43
+ const results = [];
44
+ for (const range of ranges) {
45
+ const clipPath = tempPath("clip.mp3");
46
+ tempFiles.push(clipPath);
47
+ try {
48
+ await extractClip(ffmpegPath, inputPath, range.start, range.end, clipPath);
49
+ const clipBuffer = readFileSync(clipPath);
50
+ const clipResult = await detectFn(clipBuffer);
51
+ results.push(clipResult);
52
+ }
53
+ catch {
54
+ // Skip clips that fail to extract or detect
55
+ }
56
+ }
57
+ // Aggregate counts across all clips
58
+ const counts = new Map();
59
+ for (const result of results) {
60
+ for (const [lang, count] of result) {
61
+ counts.set(lang, (counts.get(lang) ?? 0) + count);
62
+ }
63
+ }
64
+ if (counts.size === 0) {
65
+ throw new SpeechServiceError("Language detection failed: no audio clips could be analyzed", "TRANSCRIPTION_FAILED");
66
+ }
67
+ return counts;
68
+ }
69
+ finally {
70
+ for (const file of tempFiles) {
71
+ try {
72
+ unlinkSync(file);
73
+ }
74
+ catch { /* ignore cleanup errors */ }
75
+ }
76
+ }
77
+ }
78
+ // ─── Internals ──────────────────────────────────────────────────────────────
79
+ async function extractClip(ffmpegPath, inputPath, start, end, outputPath) {
80
+ await execFileAsync(ffmpegPath, [
81
+ "-y",
82
+ "-ss", formatTimestamp(start),
83
+ "-to", formatTimestamp(end),
84
+ "-i", inputPath,
85
+ "-c", "copy",
86
+ outputPath,
87
+ ]);
88
+ }
89
+ /**
90
+ * Determines how many samples to take based on audio duration,
91
+ * and where to position them.
92
+ *
93
+ * Each sample is ~10 seconds long. For audio >3 minutes, the first and last
94
+ * 10 seconds are also included.
95
+ */
96
+ function buildSamplingRanges(duration) {
97
+ const durationMinutes = duration / 60;
98
+ let numSamples = 1;
99
+ if (durationMinutes > 180) {
100
+ numSamples = Math.min(Math.round(Math.sqrt(duration / 300)), 12);
101
+ }
102
+ else if (durationMinutes > 60) {
103
+ numSamples = 4;
104
+ }
105
+ else if (durationMinutes > 20) {
106
+ numSamples = 3;
107
+ }
108
+ else if (durationMinutes > 5) {
109
+ numSamples = 2;
110
+ }
111
+ const spacing = duration / (numSamples + 1);
112
+ const locations = Array.from({ length: numSamples }, (_, i) => (i + 1) * spacing);
113
+ // Add ±5s jitter so we don't always hit the same spots
114
+ const jittered = locations.map((loc) => loc + Math.random() * 10 - 5);
115
+ const ranges = jittered.map((loc) => ({
116
+ start: Math.max(0, loc - 5),
117
+ end: Math.min(loc + 5, duration),
118
+ }));
119
+ // For audio >3 minutes, also sample the first and last 10 seconds
120
+ if (durationMinutes > 3) {
121
+ ranges.push({ start: 0, end: Math.min(10, duration) });
122
+ ranges.push({ start: Math.max(0, duration - 10), end: duration });
123
+ }
124
+ return ranges;
125
+ }
126
+ function formatTimestamp(seconds) {
127
+ const h = Math.floor(seconds / 3600);
128
+ const m = Math.floor((seconds % 3600) / 60);
129
+ const s = seconds % 60;
130
+ return `${String(h).padStart(2, "0")}:${String(m).padStart(2, "0")}:${s.toFixed(3).padStart(6, "0")}`;
131
+ }
132
+ function tempPath(suffix) {
133
+ return join(tmpdir(), `speech-detect-${randomUUID()}.${suffix}`);
134
+ }
135
+ //# sourceMappingURL=audio-sampler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audio-sampler.js","sourceRoot":"","sources":["../src/audio-sampler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { ClientConfig, SpeechClient } from "./types.js";
2
+ export declare function createSpeechClient(config: ClientConfig): SpeechClient;
3
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACR,YAAY,EACZ,YAAY,EAQf,MAAM,YAAY,CAAC;AAOpB,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,YAAY,GAAG,YAAY,CAoBrE"}
package/dist/client.js ADDED
@@ -0,0 +1,23 @@
1
+ import { VoiceCache } from "./voice-cache.js";
2
+ import { transcribe as transcribeRouter } from "./transcribe.js";
3
+ import { synthesize as synthesizeRouter } from "./synthesize.js";
4
+ import { detectLocales as detectLocalesRouter } from "./detect-locale.js";
5
+ import { fetchVoices as fetchVoicesRouter } from "./fetch-voices.js";
6
+ export function createSpeechClient(config) {
7
+ const voiceCache = new VoiceCache();
8
+ return {
9
+ async transcribe(params) {
10
+ return transcribeRouter(config, params);
11
+ },
12
+ async synthesize(params) {
13
+ return synthesizeRouter(config, params, voiceCache);
14
+ },
15
+ async detectLocales(params) {
16
+ return detectLocalesRouter(config, params);
17
+ },
18
+ async fetchVoices(provider) {
19
+ return fetchVoicesRouter(config, provider);
20
+ },
21
+ };
22
+ }
23
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,UAAU,IAAI,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACjE,OAAO,EAAE,UAAU,IAAI,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACjE,OAAO,EAAE,aAAa,IAAI,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,EAAE,WAAW,IAAI,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAErE,MAAM,UAAU,kBAAkB,CAAC,MAAoB;IACnD,MAAM,UAAU,GAAG,IAAI,UAAU,EAAE,CAAC;IAEpC,OAAO;QACH,KAAK,CAAC,UAAU,CAAC,MAAwB;YACrC,OAAO,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC5C,CAAC;QAED,KAAK,CAAC,UAAU,CAAC,MAAwB;YACrC,OAAO,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC;QACxD,CAAC;QAED,KAAK,CAAC,aAAa,CAAC,MAA2B;YAC3C,OAAO,mBAAmB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC/C,CAAC;QAED,KAAK,CAAC,WAAW,CAAC,QAA6B;YAC3C,OAAO,iBAAiB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAC/C,CAAC;KACJ,CAAC;AACN,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { ClientConfig, DetectLocalesParams } from "./types.js";
2
+ export declare function detectLocales(config: ClientConfig, params: DetectLocalesParams): Promise<Map<string, number>>;
3
+ //# sourceMappingURL=detect-locale.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect-locale.d.ts","sourceRoot":"","sources":["../src/detect-locale.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,mBAAmB,EAAyB,MAAM,YAAY,CAAC;AAW3F,wBAAsB,aAAa,CAAC,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAkBnH"}
@@ -0,0 +1,73 @@
1
+ import { SpeechServiceError } from "./errors.js";
2
+ import { getBaseLanguage } from "./utils.js";
3
+ import { sampleAndDetect } from "./audio-sampler.js";
4
+ import * as assemblyai from "./providers/assemblyai/index.js";
5
+ import * as azure from "./providers/azure/index.js";
6
+ import * as deepgram from "./providers/deepgram/index.js";
7
+ import * as elevenlabs from "./providers/elevenlabs/index.js";
8
+ import * as openai from "./providers/openai/index.js";
9
+ import * as speechmatics from "./providers/speechmatics/index.js";
10
+ export async function detectLocales(config, params) {
11
+ const detectFn = (audio) => detectSingleAudio(config, params.provider, audio);
12
+ if (params.ffmpegPath) {
13
+ return sampleAndDetect(params.audio, params.ffmpegPath, (clip) => detectFn(clip));
14
+ }
15
+ // No ffmpeg — truncate Buffer to save cost, or pass URL as-is
16
+ let audio = params.audio;
17
+ if (Buffer.isBuffer(audio)) {
18
+ const maxBytes = params.maxBytes ?? 500_000;
19
+ if (audio.length > maxBytes) {
20
+ audio = audio.subarray(0, maxBytes);
21
+ }
22
+ }
23
+ return detectFn(audio);
24
+ }
25
+ async function detectSingleAudio(config, provider, audio) {
26
+ switch (provider) {
27
+ case "azure": {
28
+ const cfg = requireConfig(config, "azure", "Azure");
29
+ return azure.detectLanguages(cfg, audio);
30
+ }
31
+ case "speechmatics": {
32
+ const cfg = requireConfig(config, "speechmatics", "Speechmatics");
33
+ return speechmatics.detectLanguages(cfg, audio);
34
+ }
35
+ case "assemblyai": {
36
+ const cfg = requireConfig(config, "assemblyai", "AssemblyAI");
37
+ const result = await assemblyai.transcribe(cfg, audio, undefined);
38
+ return singleLanguageResult(result.language);
39
+ }
40
+ case "deepgram": {
41
+ const cfg = requireConfig(config, "deepgram", "Deepgram");
42
+ const result = await deepgram.transcribe(cfg, audio, undefined);
43
+ return singleLanguageResult(result.language);
44
+ }
45
+ case "elevenlabs": {
46
+ const cfg = requireConfig(config, "elevenlabs", "ElevenLabs");
47
+ const result = await elevenlabs.transcribe(cfg, audio, undefined);
48
+ return singleLanguageResult(result.language);
49
+ }
50
+ case "openai": {
51
+ const cfg = requireConfig(config, "openai", "OpenAI");
52
+ const result = await openai.transcribe(cfg, audio, undefined);
53
+ return singleLanguageResult(result.language);
54
+ }
55
+ default:
56
+ throw new SpeechServiceError(`Unknown detectLocales provider: ${provider}`, "UNKNOWN_PROVIDER");
57
+ }
58
+ }
59
+ function requireConfig(config, provider, displayName) {
60
+ const providerConfig = config[provider];
61
+ if (!providerConfig) {
62
+ throw new SpeechServiceError(`${displayName} is not configured. Add "${provider}" to your config.`, "NOT_CONFIGURED", provider);
63
+ }
64
+ return providerConfig;
65
+ }
66
+ function singleLanguageResult(language) {
67
+ const counts = new Map();
68
+ if (language) {
69
+ counts.set(getBaseLanguage(language), 1);
70
+ }
71
+ return counts;
72
+ }
73
+ //# sourceMappingURL=detect-locale.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect-locale.js","sourceRoot":"","sources":["../src/detect-locale.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export declare class SpeechServiceError extends Error {
2
+ readonly code: string;
3
+ readonly provider?: string | undefined;
4
+ readonly statusCode?: number | undefined;
5
+ constructor(message: string, code: string, provider?: string | undefined, statusCode?: number | undefined);
6
+ }
7
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,kBAAmB,SAAQ,KAAK;aAGrB,IAAI,EAAE,MAAM;aACZ,QAAQ,CAAC,EAAE,MAAM;aACjB,UAAU,CAAC,EAAE,MAAM;gBAHnC,OAAO,EAAE,MAAM,EACC,IAAI,EAAE,MAAM,EACZ,QAAQ,CAAC,EAAE,MAAM,YAAA,EACjB,UAAU,CAAC,EAAE,MAAM,YAAA;CAK1C"}
package/dist/errors.js ADDED
@@ -0,0 +1,13 @@
1
+ export class SpeechServiceError extends Error {
2
+ code;
3
+ provider;
4
+ statusCode;
5
+ constructor(message, code, provider, statusCode) {
6
+ super(message);
7
+ this.code = code;
8
+ this.provider = provider;
9
+ this.statusCode = statusCode;
10
+ this.name = "SpeechServiceError";
11
+ }
12
+ }
13
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAGrB;IACA;IACA;IAJpB,YACI,OAAe,EACC,IAAY,EACZ,QAAiB,EACjB,UAAmB;QAEnC,KAAK,CAAC,OAAO,CAAC,CAAC;QAJC,SAAI,GAAJ,IAAI,CAAQ;QACZ,aAAQ,GAAR,QAAQ,CAAS;QACjB,eAAU,GAAV,UAAU,CAAS;QAGnC,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IACrC,CAAC;CACJ"}
@@ -0,0 +1,3 @@
1
+ import type { ClientConfig, FetchVoicesProvider, VoiceInfo } from "./types.js";
2
+ export declare function fetchVoices(config: ClientConfig, provider: FetchVoicesProvider): Promise<VoiceInfo[]>;
3
+ //# sourceMappingURL=fetch-voices.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch-voices.d.ts","sourceRoot":"","sources":["../src/fetch-voices.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAU/E,wBAAsB,WAAW,CAAC,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,mBAAmB,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAoC3G"}
@@ -0,0 +1,50 @@
1
+ import { SpeechServiceError } from "./errors.js";
2
+ import * as azure from "./providers/azure/index.js";
3
+ import * as cartesia from "./providers/cartesia/index.js";
4
+ import * as deepgram from "./providers/deepgram/index.js";
5
+ import * as elevenlabs from "./providers/elevenlabs/index.js";
6
+ import * as google from "./providers/google/index.js";
7
+ import * as openai from "./providers/openai/index.js";
8
+ import * as playht from "./providers/playht/index.js";
9
+ export async function fetchVoices(config, provider) {
10
+ switch (provider) {
11
+ case "azure": {
12
+ const cfg = requireConfig(config, "azure", "Azure");
13
+ return azure.fetchVoices(cfg);
14
+ }
15
+ case "cartesia": {
16
+ const cfg = requireConfig(config, "cartesia", "Cartesia");
17
+ return cartesia.fetchVoices(cfg);
18
+ }
19
+ case "deepgram": {
20
+ const cfg = requireConfig(config, "deepgram", "Deepgram");
21
+ return deepgram.fetchVoices(cfg);
22
+ }
23
+ case "elevenlabs": {
24
+ const cfg = requireConfig(config, "elevenlabs", "ElevenLabs");
25
+ return elevenlabs.fetchVoices(cfg);
26
+ }
27
+ case "google": {
28
+ const cfg = requireConfig(config, "google", "Google");
29
+ return google.fetchVoices(cfg);
30
+ }
31
+ case "openai": {
32
+ const cfg = requireConfig(config, "openai", "OpenAI");
33
+ return openai.fetchVoices(cfg);
34
+ }
35
+ case "playht": {
36
+ const cfg = requireConfig(config, "playht", "PlayHT");
37
+ return playht.fetchVoices(cfg);
38
+ }
39
+ default:
40
+ throw new SpeechServiceError(`Unknown TTS provider: ${provider}`, "UNKNOWN_PROVIDER");
41
+ }
42
+ }
43
+ function requireConfig(config, provider, displayName) {
44
+ const providerConfig = config[provider];
45
+ if (!providerConfig) {
46
+ throw new SpeechServiceError(`${displayName} is not configured. Add "${provider}" to your config.`, "NOT_CONFIGURED", provider);
47
+ }
48
+ return providerConfig;
49
+ }
50
+ //# sourceMappingURL=fetch-voices.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch-voices.js","sourceRoot":"","sources":["../src/fetch-voices.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,KAAK,MAAM,4BAA4B,CAAC;AACpD,OAAO,KAAK,QAAQ,MAAM,+BAA+B,CAAC;AAC1D,OAAO,KAAK,QAAQ,MAAM,+BAA+B,CAAC;AAC1D,OAAO,KAAK,UAAU,MAAM,iCAAiC,CAAC;AAC9D,OAAO,KAAK,MAAM,MAAM,6BAA6B,CAAC;AACtD,OAAO,KAAK,MAAM,MAAM,6BAA6B,CAAC;AACtD,OAAO,KAAK,MAAM,MAAM,6BAA6B,CAAC;AAEtD,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,MAAoB,EAAE,QAA6B;IACjF,QAAQ,QAAQ,EAAE,CAAC;QACf,KAAK,OAAO,CAAC,CAAC,CAAC;YACX,MAAM,GAAG,GAAG,aAAa,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;YACpD,OAAO,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QAClC,CAAC;QACD,KAAK,UAAU,CAAC,CAAC,CAAC;YACd,MAAM,GAAG,GAAG,aAAa,CAAC,MAAM,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;YAC1D,OAAO,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QACrC,CAAC;QACD,KAAK,UAAU,CAAC,CAAC,CAAC;YACd,MAAM,GAAG,GAAG,aAAa,CAAC,MAAM,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;YAC1D,OAAO,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QACrC,CAAC;QACD,KAAK,YAAY,CAAC,CAAC,CAAC;YAChB,MAAM,GAAG,GAAG,aAAa,CAAC,MAAM,EAAE,YAAY,EAAE,YAAY,CAAC,CAAC;YAC9D,OAAO,UAAU,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QACvC,CAAC;QACD,KAAK,QAAQ,CAAC,CAAC,CAAC;YACZ,MAAM,GAAG,GAAG,aAAa,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;YACtD,OAAO,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QACnC,CAAC;QACD,KAAK,QAAQ,CAAC,CAAC,CAAC;YACZ,MAAM,GAAG,GAAG,aAAa,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;YACtD,OAAO,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QACnC,CAAC;QACD,KAAK,QAAQ,CAAC,CAAC,CAAC;YACZ,MAAM,GAAG,GAAG,aAAa,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;YACtD,OAAO,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QACnC,CAAC;QACD;YACI,MAAM,IAAI,kBAAkB,CACxB,yBAAyB,QAAkB,EAAE,EAC7C,kBAAkB,CACrB,CAAC;IACV,CAAC;AACL,CAAC;AAED,SAAS,aAAa,CAClB,MAAoB,EACpB,QAAW,EACX,WAAmB;IAEnB,MAAM,cAAc,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;IACxC,IAAI,CAAC,cAAc,EAAE,CAAC;QAClB,MAAM,IAAI,kBAAkB,CACxB,GAAG,WAAW,4BAA4B,QAAQ,mBAAmB,EACrE,gBAAgB,EAChB,QAAQ,CACX,CAAC;IACN,CAAC;IACD,OAAO,cAA8C,CAAC;AAC1D,CAAC"}
@@ -0,0 +1,10 @@
1
+ export { createSpeechClient } from "./client.js";
2
+ export { transcribe } from "./transcribe.js";
3
+ export { synthesize } from "./synthesize.js";
4
+ export { detectLocales } from "./detect-locale.js";
5
+ export { fetchVoices } from "./fetch-voices.js";
6
+ export { SpeechServiceError } from "./errors.js";
7
+ export { VoiceCache } from "./voice-cache.js";
8
+ export { resolveVoice } from "./voice-resolver.js";
9
+ export type { ClientConfig, SpeechClient, AssemblyAIConfig, AzureConfig, CartesiaConfig, DeepgramConfig, ElevenLabsConfig, GoogleConfig, OpenAIConfig, PlayHTConfig, RevAIConfig, SpeechmaticsConfig, TranscribeParams, TranscribeResult, TranscribedWord, TranscribeProvider, AssemblyAITranscribeOptions, AzureTranscribeOptions, DeepgramTranscribeOptions, ElevenLabsTranscribeOptions, GoogleTranscribeOptions, OpenAITranscribeOptions, RevAITranscribeOptions, SpeechmaticsTranscribeOptions, SynthesizeParams, SynthesizeResult, SynthesizeProvider, VoiceInfo, AzureSynthesizeOptions, CartesiaSynthesizeOptions, DeepgramSynthesizeOptions, ElevenLabsSynthesizeOptions, GoogleSynthesizeOptions, OpenAISynthesizeOptions, PlayHTSynthesizeOptions, DetectLocalesParams, DetectLocalesProvider, FetchVoicesProvider, } from "./types.js";
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAGjD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGhD,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGnD,YAAY,EAER,YAAY,EACZ,YAAY,EAEZ,gBAAgB,EAChB,WAAW,EACX,cAAc,EACd,cAAc,EACd,gBAAgB,EAChB,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,kBAAkB,EAElB,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,kBAAkB,EAClB,2BAA2B,EAC3B,sBAAsB,EACtB,yBAAyB,EACzB,2BAA2B,EAC3B,uBAAuB,EACvB,uBAAuB,EACvB,sBAAsB,EACtB,6BAA6B,EAE7B,gBAAgB,EAChB,gBAAgB,EAChB,kBAAkB,EAClB,SAAS,EACT,sBAAsB,EACtB,yBAAyB,EACzB,yBAAyB,EACzB,2BAA2B,EAC3B,uBAAuB,EACvB,uBAAuB,EACvB,uBAAuB,EAEvB,mBAAmB,EACnB,qBAAqB,EAErB,mBAAmB,GACtB,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,12 @@
1
+ // ─── Client ─────────────────────────────────────────────────────────────────
2
+ export { createSpeechClient } from "./client.js";
3
+ // ─── Standalone Functions ───────────────────────────────────────────────────
4
+ export { transcribe } from "./transcribe.js";
5
+ export { synthesize } from "./synthesize.js";
6
+ export { detectLocales } from "./detect-locale.js";
7
+ export { fetchVoices } from "./fetch-voices.js";
8
+ // ─── Core ───────────────────────────────────────────────────────────────────
9
+ export { SpeechServiceError } from "./errors.js";
10
+ export { VoiceCache } from "./voice-cache.js";
11
+ export { resolveVoice } from "./voice-resolver.js";
12
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEjD,+EAA+E;AAC/E,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,+EAA+E;AAC/E,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { transcribe } from "./transcribe.js";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/assemblyai/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { transcribe } from "./transcribe.js";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/providers/assemblyai/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { AssemblyAIConfig, AssemblyAITranscribeOptions, TranscribeResult } from "../../types.js";
2
+ export declare function transcribe(config: AssemblyAIConfig, audio: Buffer | string, languages: string[] | undefined, options?: AssemblyAITranscribeOptions): Promise<TranscribeResult>;
3
+ //# sourceMappingURL=transcribe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transcribe.d.ts","sourceRoot":"","sources":["../../../src/providers/assemblyai/transcribe.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACR,gBAAgB,EAChB,2BAA2B,EAC3B,gBAAgB,EAEnB,MAAM,gBAAgB,CAAC;AAMxB,wBAAsB,UAAU,CAC5B,MAAM,EAAE,gBAAgB,EACxB,KAAK,EAAE,MAAM,GAAG,MAAM,EACtB,SAAS,EAAE,MAAM,EAAE,GAAG,SAAS,EAC/B,OAAO,GAAE,2BAAgC,GAC1C,OAAO,CAAC,gBAAgB,CAAC,CA+G3B"}