# SPDX-License-Identifier: GPL-3.0-only """Transcription providers. - OpenAICompatibleTranscriber: any endpoint speaking the OpenAI /audio/transcriptions API - OpenAI Whisper, Groq (whisper-large-v3), or a self-hosted whisper.cpp/faster-whisper server exposing that route. - LocalWhisperTranscriber: in-process faster-whisper. Wired up in M5 (needs the model download); the interface and config exist now so it is selectable. """ from __future__ import annotations import os import httpx from ..models import Transcript, TranscriptSegment class OpenAICompatibleTranscriber: def __init__(self, base_url: str, api_key: str, model: str): self.base_url = base_url.rstrip("/") self.api_key = api_key self.model = model self.name = f"openai_compatible:{model}" def transcribe(self, audio_path: str, language: str | None = None) -> Transcript: headers = {"Authorization": f"Bearer {self.api_key}"} if self.api_key else {} data = {"model": self.model, "response_format": "verbose_json"} if language: data["language"] = language with open(audio_path, "rb") as f: files = {"file": (os.path.basename(audio_path), f, "audio/wav")} resp = httpx.post( f"{self.base_url}/audio/transcriptions", headers=headers, data=data, files=files, timeout=600, ) resp.raise_for_status() body = resp.json() segments = [ TranscriptSegment(start=s.get("start", 0.0), end=s.get("end", 0.0), text=s.get("text", "")) for s in body.get("segments", []) ] return Transcript( recording_id="", language=body.get("language") or language or "en", model=self.name, text=body.get("text", ""), segments=segments, ) class LocalWhisperTranscriber: def __init__(self, model: str, device: str, compute_type: str): self.model = model self.device = device self.compute_type = compute_type self.name = f"faster-whisper:{model}" def transcribe(self, audio_path: str, language: str | None = None) -> Transcript: # M5: load faster_whisper.WhisperModel(self.model, device, compute_type) and run it. raise NotImplementedError("Local faster-whisper transcription lands in M5")