UNPKG

@copilotkit/runtime

Version:

<img src="https://github.com/user-attachments/assets/0a6b64d9-e193-4940-a3f6-60334ac34084" alt="banner" style="border-radius: 12px; border: 2px solid #d6d4fa;" />

113 lines (111 loc) 5.79 kB
require("reflect-metadata"); const require_runtime = require('../../../_virtual/_rolldown/runtime.cjs'); let _copilotkit_shared = require("@copilotkit/shared"); //#region src/v2/runtime/handlers/handle-transcribe.ts /** * HTTP status codes for transcription error codes */ const ERROR_STATUS_CODES = { [_copilotkit_shared.TranscriptionErrorCode.SERVICE_NOT_CONFIGURED]: 503, [_copilotkit_shared.TranscriptionErrorCode.INVALID_AUDIO_FORMAT]: 400, [_copilotkit_shared.TranscriptionErrorCode.AUDIO_TOO_LONG]: 400, [_copilotkit_shared.TranscriptionErrorCode.AUDIO_TOO_SHORT]: 400, [_copilotkit_shared.TranscriptionErrorCode.RATE_LIMITED]: 429, [_copilotkit_shared.TranscriptionErrorCode.AUTH_FAILED]: 401, [_copilotkit_shared.TranscriptionErrorCode.PROVIDER_ERROR]: 500, [_copilotkit_shared.TranscriptionErrorCode.NETWORK_ERROR]: 502, [_copilotkit_shared.TranscriptionErrorCode.INVALID_REQUEST]: 400 }; const VALID_AUDIO_TYPES = [ "audio/mpeg", "audio/mp3", "audio/mp4", "audio/wav", "audio/webm", "audio/ogg", "audio/flac", "audio/aac" ]; function isValidAudioType(type) { const baseType = type.split(";")[0]?.trim() ?? ""; return VALID_AUDIO_TYPES.includes(baseType) || baseType === "" || baseType === "application/octet-stream"; } function createErrorResponse(errorResponse) { const status = ERROR_STATUS_CODES[errorResponse.error] ?? 500; return new Response(JSON.stringify(errorResponse), { status, headers: { "Content-Type": "application/json" } }); } function base64ToFile(base64, mimeType, filename) { const base64Data = base64.includes(",") ? base64.split(",")[1] ?? base64 : base64; const binaryString = atob(base64Data); const bytes = new Uint8Array(binaryString.length); for (let i = 0; i < binaryString.length; i++) bytes[i] = binaryString.charCodeAt(i); return new File([bytes], filename, { type: mimeType }); } async function extractAudioFromFormData(request) { let audioFile = (await request.formData()).get("audio"); if (!audioFile || !(audioFile instanceof File)) return { error: createErrorResponse(_copilotkit_shared.TranscriptionErrors.invalidRequest("No audio file found in form data. Please include an 'audio' field.")) }; if (!isValidAudioType(audioFile.type)) return { error: createErrorResponse(_copilotkit_shared.TranscriptionErrors.invalidAudioFormat(audioFile.type, VALID_AUDIO_TYPES)) }; if (!audioFile.type || audioFile.type === "application/octet-stream") audioFile = new File([audioFile], audioFile.name || "recording.webm", { type: "audio/webm" }); return { file: audioFile }; } async function extractAudioFromJson(request) { let body; try { body = await request.json(); } catch { return { error: createErrorResponse(_copilotkit_shared.TranscriptionErrors.invalidRequest("Request body must be valid JSON")) }; } if (!body.audio || typeof body.audio !== "string") return { error: createErrorResponse(_copilotkit_shared.TranscriptionErrors.invalidRequest("Request must include 'audio' field with base64-encoded audio data")) }; if (!body.mimeType || typeof body.mimeType !== "string") return { error: createErrorResponse(_copilotkit_shared.TranscriptionErrors.invalidRequest("Request must include 'mimeType' field (e.g., 'audio/webm')")) }; if (!isValidAudioType(body.mimeType)) return { error: createErrorResponse(_copilotkit_shared.TranscriptionErrors.invalidAudioFormat(body.mimeType, VALID_AUDIO_TYPES)) }; try { const filename = body.filename || "recording.webm"; return { file: base64ToFile(body.audio, body.mimeType, filename) }; } catch { return { error: createErrorResponse(_copilotkit_shared.TranscriptionErrors.invalidRequest("Failed to decode base64 audio data")) }; } } /** * Categorize provider errors into appropriate transcription error responses. */ function categorizeProviderError(error) { const message = error instanceof Error ? error.message : "Unknown error occurred"; const errorStr = String(error).toLowerCase(); if (errorStr.includes("rate") || errorStr.includes("429") || errorStr.includes("too many")) return _copilotkit_shared.TranscriptionErrors.rateLimited(); if (errorStr.includes("auth") || errorStr.includes("401") || errorStr.includes("api key") || errorStr.includes("unauthorized")) return _copilotkit_shared.TranscriptionErrors.authFailed(); if (errorStr.includes("too long") || errorStr.includes("duration") || errorStr.includes("length")) return _copilotkit_shared.TranscriptionErrors.audioTooLong(); return _copilotkit_shared.TranscriptionErrors.providerError(message); } async function handleTranscribe({ runtime, request }) { try { if (!runtime.transcriptionService) return createErrorResponse(_copilotkit_shared.TranscriptionErrors.serviceNotConfigured()); const contentType = request.headers.get("content-type") || ""; let extractResult; if (contentType.includes("multipart/form-data")) extractResult = await extractAudioFromFormData(request); else if (contentType.includes("application/json")) extractResult = await extractAudioFromJson(request); else return createErrorResponse(_copilotkit_shared.TranscriptionErrors.invalidRequest("Request must be multipart/form-data or application/json with base64 audio")); if ("error" in extractResult) return extractResult.error; const audioFile = extractResult.file; const transcription = await runtime.transcriptionService.transcribeFile({ audioFile, mimeType: audioFile.type, size: audioFile.size }); return new Response(JSON.stringify({ text: transcription, size: audioFile.size, type: audioFile.type }), { status: 200, headers: { "Content-Type": "application/json" } }); } catch (error) { return createErrorResponse(categorizeProviderError(error)); } } //#endregion exports.handleTranscribe = handleTranscribe; //# sourceMappingURL=handle-transcribe.cjs.map