
























@@ -1,51 +1,19 @@
1-import path from "node:path";
21import type {
32AudioTranscriptionRequest,
43AudioTranscriptionResult,
54MediaUnderstandingProvider,
65} from "openclaw/plugin-sdk/media-understanding";
7-import { normalizeElevenLabsBaseUrl } from "./shared.js";
6+import {
7+assertOkOrThrowHttpError,
8+buildAudioTranscriptionFormData,
9+postTranscriptionRequest,
10+resolveProviderHttpRequestConfig,
11+requireTranscriptionText,
12+} from "openclaw/plugin-sdk/provider-http";
13+import { DEFAULT_ELEVENLABS_BASE_URL, normalizeElevenLabsBaseUrl } from "./shared.js";
814915const DEFAULT_ELEVENLABS_STT_MODEL = "scribe_v2";
101611-function resolveUploadFileName(fileName?: string, mime?: string): string {
12-const trimmed = fileName?.trim();
13-const baseName = trimmed ? path.basename(trimmed) : "audio";
14-const lowerMime = mime?.trim().toLowerCase();
15-16-if (/\.aac$/i.test(baseName)) {
17-return `${baseName.slice(0, -4) || "audio"}.m4a`;
18-}
19-if (!path.extname(baseName) && lowerMime === "audio/aac") {
20-return `${baseName || "audio"}.m4a`;
21-}
22-return baseName;
23-}
24-25-async function readErrorDetail(res: Response): Promise<string | undefined> {
26-const text = (await res.text()).trim();
27-if (!text) {
28-return undefined;
29-}
30-try {
31-const json = JSON.parse(text) as {
32-detail?: { message?: string; detail?: string; status?: string; code?: string };
33-message?: string;
34-error?: string;
35-};
36-return (
37-json.message ??
38-json.detail?.message ??
39-json.detail?.detail ??
40-json.error ??
41-json.detail?.status ??
42-json.detail?.code
43-);
44-} catch {
45-return text.slice(0, 300);
46-}
47-}
48-4917export async function transcribeElevenLabsAudio(
5018req: AudioTranscriptionRequest,
5119): Promise<AudioTranscriptionResult> {
@@ -56,46 +24,51 @@ export async function transcribeElevenLabsAudio(
5624}
57255826const model = req.model?.trim() || DEFAULT_ELEVENLABS_STT_MODEL;
59-const controller = new AbortController();
60-const timeout = setTimeout(() => controller.abort(), req.timeoutMs);
61-62-try {
63-const form = new FormData();
64-const bytes = new Uint8Array(req.buffer);
65-const blob = new Blob([bytes], { type: req.mime ?? "application/octet-stream" });
66-form.append("file", blob, resolveUploadFileName(req.fileName, req.mime));
67-form.append("model_id", model);
68-if (req.language?.trim()) {
69-form.append("language_code", req.language.trim());
70-}
71-if (req.prompt?.trim()) {
72-form.append("prompt", req.prompt.trim());
73-}
74-75-const res = await fetchFn(`${normalizeElevenLabsBaseUrl(req.baseUrl)}/v1/speech-to-text`, {
76-method: "POST",
77-headers: {
27+const { baseUrl, allowPrivateNetwork, headers, dispatcherPolicy } =
28+resolveProviderHttpRequestConfig({
29+baseUrl: normalizeElevenLabsBaseUrl(req.baseUrl),
30+defaultBaseUrl: DEFAULT_ELEVENLABS_BASE_URL,
31+headers: req.headers,
32+request: req.request,
33+defaultHeaders: {
7834"xi-api-key": apiKey,
7935},
80-body: form,
81-signal: controller.signal,
36+provider: "elevenlabs",
37+api: "elevenlabs-speech-to-text",
38+capability: "audio",
39+transport: "media-understanding",
8240});
41+const form = buildAudioTranscriptionFormData({
42+buffer: req.buffer,
43+fileName: req.fileName,
44+mime: req.mime,
45+fields: {
46+model_id: model,
47+language_code: req.language,
48+prompt: req.prompt,
49+},
50+});
51+const { response, release } = await postTranscriptionRequest({
52+url: `${baseUrl}/v1/speech-to-text`,
53+ headers,
54+body: form,
55+timeoutMs: req.timeoutMs,
56+ fetchFn,
57+ allowPrivateNetwork,
58+ dispatcherPolicy,
59+auditContext: "elevenlabs speech-to-text",
60+});
836184-if (!res.ok) {
85-const detail = await readErrorDetail(res);
86-throw new Error(
87-`ElevenLabs audio transcription failed (${res.status})${detail ? `: ${detail}` : ""}`,
88-);
89-}
90-91-const payload = (await res.json()) as { text?: string };
92-const text = payload.text?.trim();
93-if (!text) {
94-throw new Error("ElevenLabs audio transcription response missing text");
95-}
62+try {
63+await assertOkOrThrowHttpError(response, "ElevenLabs audio transcription failed");
64+const payload = (await response.json()) as { text?: string };
65+const text = requireTranscriptionText(
66+payload.text,
67+"ElevenLabs audio transcription response missing text",
68+);
9669return { text, model };
9770} finally {
98-clearTimeout(timeout);
71+await release();
9972}
10073}
10174此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。