@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
JavaScript
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