// Operator-hardware fallback backend. Forwards transcribe requests to // the operator's Parakeet (or any Whisper-API-compatible) endpoint and // analyze requests to their Gemma (or any OpenAI-API-compatible) endpoint. // // v0.1 is a stub — the endpoints are wired up, but no operator has // pointed a real Parakeet/Gemma at the relay yet. Returns a 503 // "hardware fallback not yet wired" so the credits.js routing logic // still applies but users get a clear message instead of a silent // failure. export function createHardwareBackend({ parakeetBaseURL = "", gemmaBaseURL = "", } = {}) { const hasParakeet = !!parakeetBaseURL; const hasGemma = !!gemmaBaseURL; return { hasTranscribe: hasParakeet, hasAnalyze: hasGemma, async transcribeAudio() { if (!hasParakeet) { const err = new Error( "operator-hardware transcribe path is not configured (relay_parakeet_base_url is empty)" ); err.status = 503; throw err; } // TODO v0.2: POST audio to parakeetBaseURL using the OpenAI // audio-transcriptions wire format Recap already speaks. Return // { text, segments, duration_seconds } in the same shape as // gemini.js's transcribeAudio. const err = new Error("operator-hardware transcribe path not yet implemented in relay v0.1"); err.status = 503; throw err; }, async analyzeText() { if (!hasGemma) { const err = new Error( "operator-hardware analyze path is not configured (relay_gemma_base_url is empty)" ); err.status = 503; throw err; } // TODO v0.2: POST prompt to gemmaBaseURL using either /api/generate // (Ollama native) or /v1/chat/completions (OpenAI-compatible). // Return { text } matching gemini.js's analyzeText. const err = new Error("operator-hardware analyze path not yet implemented in relay v0.1"); err.status = 503; throw err; }, }; }