import os from typing import Optional from speechmatics.models import ConnectionSettings, BatchTranscriptionConfig, FetchData from speechmatics.batch_client import BatchClient from httpx import HTTPStatusError from requests_toolbelt import MultipartEncoder from . import APIProvider, PermanentError, register @register("speechmatics") class SpeechmaticsProvider(APIProvider): def transcribe( self, model_variant: str, audio_file_path: Optional[str], sample: dict, use_url: bool = False, language: str = "en", ) -> str: api_key = os.getenv("SPEECHMATICS_API_KEY") if not api_key: raise ValueError("SPEECHMATICS_API_KEY environment variable not set") settings = ConnectionSettings( url="https://asr.api.speechmatics.com/v2", auth_token=api_key ) with BatchClient(settings) as client: config = BatchTranscriptionConfig( language=language, enable_entities=True, operating_point=model_variant, ) job_id = None audio_url = None try: if use_url: audio_url = sample["row"]["audio"][0]["src"] config.fetch_data = FetchData(url=audio_url) multipart_data = MultipartEncoder( fields={"config": config.as_config().encode("utf-8")} ) response = client.send_request( "POST", "jobs", data=multipart_data.to_string(), headers={"Content-Type": multipart_data.content_type}, ) job_id = response.json()["id"] else: job_id = client.submit_job(audio_file_path, config) transcript = client.wait_for_completion( job_id, transcription_format="txt" ) return transcript except HTTPStatusError as e: if e.response.status_code == 401: raise ValueError( "Invalid Speechmatics API credentials" ) from e elif e.response.status_code == 400: raise ValueError( f"Speechmatics API responded with 400 Bad request: {e.response.text}" ) raise e except Exception as e: if job_id is not None: status = client.check_job_status(job_id) if ( audio_url is not None and "job" in status and "errors" in status["job"] and isinstance(status["job"]["errors"], list) and len(status["job"]["errors"]) > 0 ): errors = status["job"]["errors"] if "message" in errors[-1] and "failed to fetch file" in errors[-1]["message"]: raise PermanentError(f"could not fetch URL {audio_url}, not retrying") from e raise Exception( f"Speechmatics transcription failed: {str(e)}" ) from e