@omg-dev/media 0.4.25 → 0.4.26

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/dist/index.mjs CHANGED
@@ -87,5 +87,53 @@ async function generateVideo(opts) {
87
87
  job
88
88
  };
89
89
  }
90
+ /**
91
+ * Text → speech. Submits, polls to completion, and returns a durable CDN URL
92
+ * to the generated mp3. TTS runs in seconds, but in a server route still
93
+ * prefer submit + getJob (or an `on()` handler) — see the media docs.
94
+ *
95
+ * const { url } = await generateSpeech({ text: "Welcome back!" })
96
+ */
97
+ async function generateSpeech(opts) {
98
+ const { text, voiceId, model, input, ...rest } = opts;
99
+ const job = await generate({
100
+ model: model ?? "elevenlabs/eleven_turbo_v2_5",
101
+ input: {
102
+ text,
103
+ ...voiceId ? { voice_id: voiceId } : {},
104
+ ...input
105
+ },
106
+ ...rest
107
+ });
108
+ const url = job.results?.[0]?.url;
109
+ if (!url) throw new Error(`media generateSpeech: job ${job.jobId} produced no result`);
110
+ return {
111
+ url,
112
+ job
113
+ };
114
+ }
115
+ /**
116
+ * Speech → text. Submits, polls to completion, and returns the transcript.
117
+ *
118
+ * const { text } = await transcribe({ audioUrl, durationSeconds: 42 })
119
+ */
120
+ async function transcribe(opts) {
121
+ const { audioUrl, durationSeconds, model, input, ...rest } = opts;
122
+ const job = await generate({
123
+ model: model ?? "elevenlabs/scribe_v1",
124
+ input: {
125
+ audio_url: audioUrl,
126
+ duration_seconds: durationSeconds,
127
+ ...input
128
+ },
129
+ ...rest
130
+ });
131
+ const text = job.results?.[0]?.text;
132
+ if (text == null) throw new Error(`media transcribe: job ${job.jobId} produced no transcript`);
133
+ return {
134
+ text,
135
+ job
136
+ };
137
+ }
90
138
  //#endregion
91
- export { generate, generateImage, generateVideo, getEndUser, getJob, runWithEndUser, submit };
139
+ export { generate, generateImage, generateSpeech, generateVideo, getEndUser, getJob, runWithEndUser, submit, transcribe };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@omg-dev/media",
3
- "version": "0.4.25",
3
+ "version": "0.4.26",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
package/src/index.ts CHANGED
@@ -52,6 +52,8 @@ export type JobStatus = "queued" | "running" | "succeeded" | "failed"
52
52
  export interface ResultRef {
53
53
  url: string
54
54
  contentType?: string
55
+ /** Inline textual output (speech-to-text transcripts). No url when set. */
56
+ text?: string
55
57
  }
56
58
 
57
59
  export interface Job {
@@ -165,3 +167,71 @@ export async function generateVideo(
165
167
  if (!url) throw new Error(`media generateVideo: job ${job.jobId} produced no result`)
166
168
  return { url, job }
167
169
  }
170
+
171
+ // ── Speech (ElevenLabs) ──────────────────────────────────────────────────────
172
+
173
+ export interface SpeechOptions extends Omit<GenerateOptions, "model" | "input"> {
174
+ /** The text to speak. Billed per character (pass-through). */
175
+ text: string
176
+ /** ElevenLabs voice id; the platform default voice when omitted. */
177
+ voiceId?: string
178
+ /** Curated model id (default "elevenlabs/eleven_turbo_v2_5"). */
179
+ model?: string
180
+ /** Extra model params merged into the input (voice_settings, output_format…). */
181
+ input?: Record<string, unknown>
182
+ }
183
+
184
+ /**
185
+ * Text → speech. Submits, polls to completion, and returns a durable CDN URL
186
+ * to the generated mp3. TTS runs in seconds, but in a server route still
187
+ * prefer submit + getJob (or an `on()` handler) — see the media docs.
188
+ *
189
+ * const { url } = await generateSpeech({ text: "Welcome back!" })
190
+ */
191
+ export async function generateSpeech(
192
+ opts: SpeechOptions,
193
+ ): Promise<{ url: string; job: Job }> {
194
+ const { text, voiceId, model, input, ...rest } = opts
195
+ const job = await generate({
196
+ model: model ?? "elevenlabs/eleven_turbo_v2_5",
197
+ input: { text, ...(voiceId ? { voice_id: voiceId } : {}), ...input },
198
+ ...rest,
199
+ })
200
+ const url = job.results?.[0]?.url
201
+ if (!url) throw new Error(`media generateSpeech: job ${job.jobId} produced no result`)
202
+ return { url, job }
203
+ }
204
+
205
+ export interface TranscribeOptions extends Omit<GenerateOptions, "model" | "input"> {
206
+ /** Public URL of the audio to transcribe (e.g. an uploaded file's URL). */
207
+ audioUrl: string
208
+ /**
209
+ * Length of the audio in seconds — REQUIRED, it is what you're billed on
210
+ * ($0.22/audio-hour pass-through, 60s minimum). Understating it undercharges;
211
+ * read it off the file/recorder before submitting.
212
+ */
213
+ durationSeconds: number
214
+ /** Curated model id (default "elevenlabs/scribe_v1"). */
215
+ model?: string
216
+ /** Extra model params merged into the input (language_code…). */
217
+ input?: Record<string, unknown>
218
+ }
219
+
220
+ /**
221
+ * Speech → text. Submits, polls to completion, and returns the transcript.
222
+ *
223
+ * const { text } = await transcribe({ audioUrl, durationSeconds: 42 })
224
+ */
225
+ export async function transcribe(
226
+ opts: TranscribeOptions,
227
+ ): Promise<{ text: string; job: Job }> {
228
+ const { audioUrl, durationSeconds, model, input, ...rest } = opts
229
+ const job = await generate({
230
+ model: model ?? "elevenlabs/scribe_v1",
231
+ input: { audio_url: audioUrl, duration_seconds: durationSeconds, ...input },
232
+ ...rest,
233
+ })
234
+ const text = job.results?.[0]?.text
235
+ if (text == null) throw new Error(`media transcribe: job ${job.jobId} produced no transcript`)
236
+ return { text, job }
237
+ }