from __future__ import annotations

import json
import queue
import time
import wave

import httpx
import pytest

from services.ai_voice_runtime_service.audiosocket import pcm16le_to_wav_bytes
from services.ai_voice_runtime_service.providers import asr as asr_module


class _DummyResponse:
    def __init__(self, json_payload: dict | None = None) -> None:
        self.content = b"{}"
        self._json_payload = json_payload or {}

    def raise_for_status(self) -> None:
        return None

    def json(self) -> dict:
        return self._json_payload


def test_yandex_asr_provider_posts_lpcm_with_tts_credential_fallback(monkeypatch):
    calls: list[dict] = []
    pcm = b"\x01\x00" * 160
    wav_bytes = pcm16le_to_wav_bytes(pcm, sample_rate_hz=8000)

    class _DummyClient:
        def __init__(self, *, timeout: float) -> None:
            self.timeout = timeout

        def __enter__(self) -> "_DummyClient":
            return self

        def __exit__(self, exc_type, exc, tb) -> None:
            return None

        def post(
            self,
            url: str,
            *,
            headers: dict[str, str],
            params: dict[str, str],
            content: bytes,
        ) -> _DummyResponse:
            calls.append(
                {
                    "url": url,
                    "headers": headers,
                    "params": params,
                    "content": content,
                    "timeout": self.timeout,
                }
            )
            return _DummyResponse({"result": "almaty schedule"})

    monkeypatch.delenv("AI_VOICE_ASR_YANDEX_API_KEY", raising=False)
    monkeypatch.delenv("AI_VOICE_ASR_YANDEX_IAM_TOKEN", raising=False)
    monkeypatch.setenv("AI_VOICE_TTS_YANDEX_API_KEY", "tts-yandex-key")
    monkeypatch.setenv("AI_VOICE_ASR_YANDEX_API_BASE", "https://stt.example.test")
    monkeypatch.setenv("AI_VOICE_ASR_YANDEX_FOLDER_ID", "folder-test")
    monkeypatch.setenv("AI_VOICE_ASR_YANDEX_TIMEOUT_SECONDS", "5")
    monkeypatch.setattr(asr_module.httpx, "Client", _DummyClient)

    provider = asr_module.YandexSpeechKitASRProvider()
    result = provider.transcribe(wav_bytes, language_hint="ru")

    assert result.text == "almaty schedule"
    assert result.language == "ru-RU"
    assert len(calls) == 1
    assert calls[0]["url"] == "https://stt.example.test/speech/v1/stt:recognize"
    assert calls[0]["headers"]["Authorization"] == "Api-Key tts-yandex-key"
    assert calls[0]["headers"]["Content-Type"] == "application/octet-stream"
    assert calls[0]["params"]["lang"] == "ru-RU"
    assert calls[0]["params"]["format"] == "lpcm"
    assert calls[0]["params"]["sampleRateHertz"] == "8000"
    assert calls[0]["params"]["topic"] == "general"
    assert calls[0]["params"]["folderId"] == "folder-test"
    assert calls[0]["content"] == pcm
    assert calls[0]["timeout"] == 5.0


def test_elevenlabs_asr_provider_posts_wav_with_tts_credential_fallback(monkeypatch):
    calls: list[dict] = []
    pcm = b"\x01\x00" * 160
    wav_bytes = pcm16le_to_wav_bytes(pcm, sample_rate_hz=8000)

    class _DummyClient:
        def __init__(self, *, timeout: float) -> None:
            self.timeout = timeout

        def __enter__(self) -> "_DummyClient":
            return self

        def __exit__(self, exc_type, exc, tb) -> None:
            return None

        def post(
            self,
            url: str,
            *,
            headers: dict[str, str],
            data: dict[str, str],
            files: dict[str, tuple[str, bytes, str]],
        ) -> _DummyResponse:
            calls.append(
                {
                    "url": url,
                    "headers": headers,
                    "data": data,
                    "files": files,
                    "timeout": self.timeout,
                }
            )
            return _DummyResponse({"text": "schedule", "language_code": "rus"})

    monkeypatch.delenv("AI_VOICE_ASR_ELEVENLABS_API_KEY", raising=False)
    monkeypatch.setenv("AI_VOICE_TTS_ELEVENLABS_API_KEY", "tts-elevenlabs-key")
    monkeypatch.setenv("AI_VOICE_ASR_ELEVENLABS_API_BASE", "https://api.elevenlabs.example")
    monkeypatch.setenv("AI_VOICE_ASR_ELEVENLABS_MODEL_ID", "scribe_v1")
    monkeypatch.setattr(asr_module.httpx, "Client", _DummyClient)

    provider = asr_module.ElevenLabsASRProvider()
    result = provider.transcribe(wav_bytes, language_hint="ru")

    assert result.text == "schedule"
    assert result.language == "ru"
    assert len(calls) == 1
    assert calls[0]["url"] == "https://api.elevenlabs.example/v1/speech-to-text"
    assert calls[0]["headers"]["xi-api-key"] == "tts-elevenlabs-key"
    assert calls[0]["data"]["model_id"] == "scribe_v1"
    assert calls[0]["data"]["language_code"] == "rus"
    assert calls[0]["files"]["file"][0] == "turn.wav"
    assert calls[0]["files"]["file"][2] == "audio/wav"
    assert calls[0]["timeout"] == 20.0


def test_elevenlabs_asr_provider_surfaces_http_auth_errors(monkeypatch):
    request = httpx.Request("POST", "https://api.elevenlabs.example/v1/speech-to-text")
    response = httpx.Response(401, request=request)

    class _DummyClient:
        def __init__(self, *, timeout: float) -> None:
            self.timeout = timeout

        def __enter__(self) -> "_DummyClient":
            return self

        def __exit__(self, exc_type, exc, tb) -> None:
            return None

        def post(
            self,
            url: str,
            *,
            headers: dict[str, str],
            data: dict[str, str],
            files: dict[str, tuple[str, bytes, str]],
        ) -> _DummyResponse:
            del url, headers, data, files
            class _FailingResponse(_DummyResponse):
                def raise_for_status(self_nonlocal) -> None:
                    raise httpx.HTTPStatusError("401 Unauthorized", request=request, response=response)

            return _FailingResponse()

    monkeypatch.setenv("AI_VOICE_ASR_ELEVENLABS_API_KEY", "asr-elevenlabs-key")
    monkeypatch.setattr(asr_module.httpx, "Client", _DummyClient)

    provider = asr_module.ElevenLabsASRProvider()

    with pytest.raises(httpx.HTTPStatusError):
        provider.transcribe(b"\x01\x00" * 160, language_hint="ru")


def test_yandex_asr_provider_uses_iam_token(monkeypatch):
    calls: list[dict] = []

    class _DummyClient:
        def __init__(self, *, timeout: float) -> None:
            self.timeout = timeout

        def __enter__(self) -> "_DummyClient":
            return self

        def __exit__(self, exc_type, exc, tb) -> None:
            return None

        def post(
            self,
            url: str,
            *,
            headers: dict[str, str],
            params: dict[str, str],
            content: bytes,
        ) -> _DummyResponse:
            calls.append({"url": url, "headers": headers, "params": params, "content": content})
            return _DummyResponse({"result": "operator"})

    monkeypatch.delenv("AI_VOICE_ASR_YANDEX_API_KEY", raising=False)
    monkeypatch.delenv("AI_VOICE_TTS_YANDEX_API_KEY", raising=False)
    monkeypatch.setenv("AI_VOICE_ASR_YANDEX_IAM_TOKEN", "iam-token")
    monkeypatch.setenv("AI_VOICE_ASR_YANDEX_API_BASE", "https://stt.example.test")
    monkeypatch.setattr(asr_module.httpx, "Client", _DummyClient)

    provider = asr_module.YandexSpeechKitASRProvider()
    result = provider.transcribe(b"\x02\x00" * 80, language_hint="kk")

    assert result.text == "operator"
    assert result.language == "kk-KZ"
    assert calls[0]["headers"]["Authorization"] == "Bearer iam-token"
    assert calls[0]["params"]["lang"] == "kk-KZ"


def test_yandex_asr_provider_supports_kz_v3_async_rest(monkeypatch):
    calls: list[dict] = []

    class _DummyClient:
        def __init__(self, *, timeout: float) -> None:
            self.timeout = timeout

        def __enter__(self) -> "_DummyClient":
            return self

        def __exit__(self, exc_type, exc, tb) -> None:
            return None

        def post(self, url: str, *, headers: dict[str, str], json: dict) -> _DummyResponse:
            calls.append({"method": "POST", "url": url, "headers": headers, "json": json})
            return _DummyResponse({"id": "operation-1", "done": False})

        def get(
            self,
            url: str,
            *,
            headers: dict[str, str],
            params: dict[str, str] | None = None,
        ) -> _DummyResponse:
            calls.append({"method": "GET", "url": url, "headers": headers, "params": params or {}})
            if "operation.api.cloud.yandex.net/operations/" in url:
                return _DummyResponse({"id": "operation-1", "done": True})
            return _DummyResponse(
                {
                    "finalRefinement": {
                        "normalizedText": {
                            "alternatives": [
                                {
                                    "text": "almaty schedule",
                                }
                            ]
                        }
                    }
                }
            )

    monkeypatch.setenv("AI_VOICE_ASR_YANDEX_API_KEY", "asr-key")
    monkeypatch.setenv("AI_VOICE_ASR_YANDEX_API_BASE", "https://stt.api.ml.yandexcloud.kz")
    monkeypatch.delenv("AI_VOICE_ASR_YANDEX_OPERATIONS_BASE", raising=False)
    monkeypatch.setenv("AI_VOICE_ASR_YANDEX_FOLDER_ID", "folder-test")
    monkeypatch.setenv("AI_VOICE_ASR_YANDEX_POLL_INTERVAL_SECONDS", "0.05")
    monkeypatch.setattr(asr_module.httpx, "Client", _DummyClient)

    provider = asr_module.YandexSpeechKitASRProvider()
    result = provider.transcribe(b"\x03\x00" * 80, language_hint="ru")

    assert result.text == "almaty schedule"
    assert result.language == "ru-RU"
    assert calls[0]["url"] == "https://stt.api.cloud.yandex.net/stt/v3/recognizeFileAsync"
    assert calls[0]["headers"]["Authorization"] == "Api-Key asr-key"
    assert calls[0]["headers"]["Content-Type"] == "application/json"
    assert calls[0]["headers"]["x-folder-id"] == "folder-test"
    assert calls[0]["json"]["recognitionModel"]["audioFormat"]["rawAudio"]["sampleRateHertz"] == "8000"
    assert calls[0]["json"]["recognitionModel"]["languageRestriction"]["languageCode"] == ["ru-RU"]
    assert calls[1]["url"] == "https://operation.api.cloud.yandex.net/operations/operation-1"
    assert calls[1]["params"] == {}
    assert calls[2]["url"] == "https://stt.api.cloud.yandex.net/stt/v3/getRecognition"
    assert calls[2]["params"] == {"operationId": "operation-1"}


def test_yandex_buffered_streaming_provider_buffers_pcm_until_finalize():
    calls: list[dict] = []

    class _FakeYandexASR:
        def transcribe(self, audio_bytes: bytes, *, language_hint: str | None = None):
            calls.append({"audio_bytes": audio_bytes, "language_hint": language_hint})
            return asr_module.ASRTranscription(text="need schedule", language=language_hint, confidence=None)

    provider = asr_module.YandexSpeechKitBufferedStreamingASRProvider(asr_provider=_FakeYandexASR())  # type: ignore[arg-type]
    stream_id = provider.open_stream("session-1", language_hint="ru")

    provider.push_pcm(stream_id, b"\x10\x00")
    provider.push_pcm(stream_id, b"\x20\x00")

    assert provider.poll_partial(stream_id) is None

    result = provider.finalize(stream_id)
    provider.close_stream(stream_id)

    assert result.text == "need schedule"
    assert calls == [{"audio_bytes": b"\x10\x00\x20\x00", "language_hint": "ru"}]


def test_elevenlabs_realtime_streaming_provider_returns_partial_and_final():
    calls: list[dict] = []

    class _FakeRealtimeWebSocket:
        def __init__(self) -> None:
            self.sent_payloads: list[dict] = []
            self.incoming: queue.Queue[str | None] = queue.Queue()
            self.incoming.put(
                json.dumps(
                    {
                        "message_type": "session_started",
                        "session_id": "session-test",
                        "config": {"sample_rate": 16000, "audio_format": "pcm_16000"},
                    }
                )
            )

        def send(self, raw_payload: str) -> None:
            payload = json.loads(raw_payload)
            self.sent_payloads.append(payload)
            if payload.get("commit"):
                self.incoming.put(
                    json.dumps(
                        {
                            "message_type": "committed_transcript",
                            "text": "нужно узнать график работы",
                            "language_code": "ru",
                        }
                    )
                )
            else:
                self.incoming.put(
                    json.dumps(
                        {
                            "message_type": "partial_transcript",
                            "text": "нужно узнать график",
                            "language_code": "ru",
                        }
                    )
                )

        def recv(self) -> str:
            item = self.incoming.get(timeout=1)
            if item is None:
                raise RuntimeError("closed")
            return item

        def close(self) -> None:
            self.incoming.put(None)

    websocket = _FakeRealtimeWebSocket()

    def _factory(url: str, *, header: list[str], timeout: float):
        calls.append({"url": url, "header": header, "timeout": timeout})
        return websocket

    provider = asr_module.ElevenLabsRealtimeStreamingASRProvider(
        api_base="https://api.elevenlabs.example",
        api_key="asr-key",
        timeout_seconds=3,
        finalize_timeout_seconds=1,
        websocket_factory=_factory,
    )
    stream_id = provider.open_stream("session-1", language_hint="ru")
    provider.push_pcm(stream_id, b"\x01\x00" * 160)

    partial = None
    for _ in range(20):
        partial = provider.poll_partial(stream_id)
        if partial is not None:
            break
        time.sleep(0.02)

    assert partial is not None
    assert partial.text == "нужно узнать график"
    assert partial.is_final is False

    final = provider.finalize(stream_id)
    provider.close_stream(stream_id)

    assert final.text == "нужно узнать график работы"
    assert final.language == "ru"
    assert calls[0]["url"].startswith("wss://api.elevenlabs.example/v1/speech-to-text/realtime?")
    assert "model_id=scribe_v2_realtime" in calls[0]["url"]
    assert "audio_format=pcm_16000" in calls[0]["url"]
    assert "language_code=ru" in calls[0]["url"]
    assert calls[0]["header"] == ["xi-api-key: asr-key"]
    assert calls[0]["timeout"] == 3.0
    assert len(websocket.sent_payloads) == 2
    assert websocket.sent_payloads[0]["message_type"] == "input_audio_chunk"
    assert websocket.sent_payloads[0]["commit"] is False
    assert websocket.sent_payloads[0]["sample_rate"] == 16000
    assert websocket.sent_payloads[0]["audio_base_64"]
    assert websocket.sent_payloads[1]["commit"] is True


def test_elevenlabs_realtime_streaming_provider_finalizes_from_stable_partial_on_timeout():
    class _FakeRealtimeWebSocket:
        def __init__(self) -> None:
            self.sent_payloads: list[dict] = []
            self.incoming: queue.Queue[str | None] = queue.Queue()

        def send(self, raw_payload: str) -> None:
            payload = json.loads(raw_payload)
            self.sent_payloads.append(payload)
            if not payload.get("commit"):
                partial = json.dumps(
                    {
                        "message_type": "partial_transcript",
                        "text": "need schedule",
                        "language_code": "ru",
                    }
                )
                self.incoming.put(partial)
                self.incoming.put(partial)

        def recv(self) -> str:
            item = self.incoming.get(timeout=1)
            if item is None:
                raise RuntimeError("closed")
            return item

        def close(self) -> None:
            self.incoming.put(None)

    websocket = _FakeRealtimeWebSocket()

    provider = asr_module.ElevenLabsRealtimeStreamingASRProvider(
        api_base="https://api.elevenlabs.example",
        api_key="asr-key",
        timeout_seconds=1,
        finalize_timeout_seconds=0.25,
        websocket_factory=lambda url, *, header, timeout: websocket,
    )
    stream_id = provider.open_stream("session-1", language_hint="ru")
    provider.push_pcm(stream_id, b"\x01\x00" * 160)

    partial = None
    for _ in range(20):
        partial = provider.poll_partial(stream_id)
        if partial is not None and partial.is_stable:
            break
        time.sleep(0.02)

    assert partial is not None
    assert partial.is_stable is True

    final = provider.finalize(stream_id)
    provider.close_stream(stream_id)

    assert final.text == "need schedule"
    assert final.language == "ru"
    assert websocket.sent_payloads[-1]["commit"] is True


def test_elevenlabs_realtime_streaming_provider_accumulates_autonomous_vad_commits():
    # Regression test: under commit_strategy=vad the server can autonomously commit
    # an early segment mid-utterance, before the client ever asks it to finalize.
    # That must be accumulated, not mistaken for the whole turn's answer — otherwise
    # everything the caller says after that early commit gets silently dropped.
    class _FakeRealtimeWebSocket:
        def __init__(self) -> None:
            self.sent_payloads: list[dict] = []
            self.incoming: queue.Queue[str | None] = queue.Queue()
            self.incoming.put(
                json.dumps(
                    {
                        "message_type": "committed_transcript",
                        "text": "Здравствуйте",
                        "language_code": "ru",
                    }
                )
            )

        def send(self, raw_payload: str) -> None:
            payload = json.loads(raw_payload)
            self.sent_payloads.append(payload)
            if payload.get("commit"):
                self.incoming.put(
                    json.dumps(
                        {
                            "message_type": "committed_transcript",
                            "text": "нужна помощь с газом",
                            "language_code": "ru",
                        }
                    )
                )

        def recv(self) -> str:
            item = self.incoming.get(timeout=1)
            if item is None:
                raise RuntimeError("closed")
            return item

        def close(self) -> None:
            self.incoming.put(None)

    websocket = _FakeRealtimeWebSocket()

    provider = asr_module.ElevenLabsRealtimeStreamingASRProvider(
        api_base="https://api.elevenlabs.example",
        api_key="asr-key",
        timeout_seconds=3,
        finalize_timeout_seconds=1,
        websocket_factory=lambda url, *, header, timeout: websocket,
    )
    stream_id = provider.open_stream("session-1", language_hint="ru")

    early = None
    for _ in range(20):
        early = provider.poll_partial(stream_id)
        if early is not None and early.text:
            break
        time.sleep(0.02)
    assert early is not None
    assert early.text == "Здравствуйте"
    assert early.is_final is False

    provider.push_pcm(stream_id, b"\x01\x00" * 160)
    final = provider.finalize(stream_id)
    provider.close_stream(stream_id)

    assert final.text == "Здравствуйте нужна помощь с газом"
    assert final.language == "ru"


def test_elevenlabs_realtime_streaming_provider_writes_debug_audio_dump(tmp_path):
    class _FakeRealtimeWebSocket:
        def __init__(self) -> None:
            self.incoming: queue.Queue[str | None] = queue.Queue()

        def send(self, raw_payload: str) -> None:
            payload = json.loads(raw_payload)
            if payload.get("commit"):
                self.incoming.put(
                    json.dumps({"message_type": "committed_transcript", "text": "тест", "language_code": "ru"})
                )

        def recv(self) -> str:
            item = self.incoming.get(timeout=1)
            if item is None:
                raise RuntimeError("closed")
            return item

        def close(self) -> None:
            self.incoming.put(None)

    websocket = _FakeRealtimeWebSocket()
    dump_dir = tmp_path / "asr_debug_dumps"

    provider = asr_module.ElevenLabsRealtimeStreamingASRProvider(
        api_base="https://api.elevenlabs.example",
        api_key="asr-key",
        timeout_seconds=1,
        finalize_timeout_seconds=1,
        websocket_factory=lambda url, *, header, timeout: websocket,
        debug_dump_audio=True,
        debug_dump_dir=dump_dir,
    )
    stream_id = provider.open_stream("session-1", language_hint="ru")
    provider.push_pcm(stream_id, b"\x10\x00" * 160)
    provider.finalize(stream_id)
    provider.close_stream(stream_id)

    dumped = dump_dir / f"{stream_id}.wav"
    assert dumped.exists()
    with wave.open(str(dumped), "rb") as wav_file:
        assert wav_file.getframerate() == 16000
        assert wav_file.getnframes() > 0


def test_yandex_grpc_streaming_provider_returns_partial_and_final():
    calls: list[dict] = []

    class _Message:
        def __init__(self, **kwargs) -> None:
            self.__dict__.update(kwargs)

        def HasField(self, name: str) -> bool:
            return getattr(self, name, None) is not None

    class _RawAudio(_Message):
        LINEAR16_PCM = 1

    class _TextNormalizationOptions(_Message):
        TEXT_NORMALIZATION_ENABLED = 1
        PHONE_FORMATTING_MODE_DISABLED = 1

    class _LanguageRestrictionOptions(_Message):
        WHITELIST = 1

    class _RecognitionModelOptions(_Message):
        REAL_TIME = 1

    class _DefaultEouClassifier(_Message):
        HIGH = 2

    class _FakeSttPb2:
        RawAudio = _RawAudio
        AudioFormatOptions = _Message
        TextNormalizationOptions = _TextNormalizationOptions
        LanguageRestrictionOptions = _LanguageRestrictionOptions
        RecognitionModelOptions = _RecognitionModelOptions
        DefaultEouClassifier = _DefaultEouClassifier
        EouClassifierOptions = _Message
        StreamingOptions = _Message
        StreamingRequest = _Message
        AudioChunk = _Message
        Eou = _Message

    class _FakeChannel:
        def close(self) -> None:
            calls.append({"method": "close"})

    class _FakeGrpc:
        @staticmethod
        def ssl_channel_credentials():
            return "ssl"

        @staticmethod
        def secure_channel(target: str, credentials):
            calls.append({"method": "secure_channel", "target": target, "credentials": credentials})
            return _FakeChannel()

    class _RecognizerStub:
        def __init__(self, channel) -> None:
            calls.append({"method": "stub_init", "channel": channel})

        def RecognizeStreaming(self, request_iterator, *, metadata, timeout):
            calls.append({"method": "recognize", "metadata": metadata, "timeout": timeout})
            for request in request_iterator:
                calls.append({"method": "request", "request": request})
                if getattr(request, "chunk", None) is not None:
                    yield _Message(
                        partial=_Message(
                            alternatives=[
                                _Message(text="need schedule", confidence=0.7, languages=[]),
                            ]
                        )
                    )
                    continue
                if getattr(request, "eou", None) is not None:
                    yield _Message(
                        final_refinement=_Message(
                            normalized_text=_Message(
                                alternatives=[
                                    _Message(text="need schedule in almaty", confidence=0.91, languages=[]),
                                ]
                            )
                        )
                    )
                    return

    class _FakeGrpcPb2:
        RecognizerStub = _RecognizerStub

    provider = asr_module.YandexSpeechKitGrpcStreamingASRProvider(
        api_key="asr-key",
        grpc_target="stt.test:443",
        timeout_seconds=3,
        grpc_module=_FakeGrpc,
        stt_pb2_module=_FakeSttPb2,
        stt_service_pb2_grpc_module=_FakeGrpcPb2,
    )
    stream_id = provider.open_stream("session-1", language_hint="ru")
    provider.push_pcm(stream_id, b"\x10\x00\x20\x00")

    partial = None
    for _ in range(20):
        partial = provider.poll_partial(stream_id)
        if partial is not None:
            break
        time.sleep(0.02)

    assert partial is not None
    assert partial.text == "need schedule"
    assert partial.is_final is False

    final = provider.finalize(stream_id)
    provider.close_stream(stream_id)

    assert final.text == "need schedule in almaty"
    recognize_call = next(call for call in calls if call.get("method") == "recognize")
    assert ("authorization", "Api-Key asr-key") in recognize_call["metadata"]
    requests = [call["request"] for call in calls if call.get("method") == "request"]
    assert getattr(requests[0], "session_options", None) is not None
    assert getattr(requests[1], "chunk", None).data == b"\x10\x00\x20\x00"
    assert getattr(requests[-1], "eou", None) is not None


def test_yandex_asr_builders():
    assert isinstance(asr_module.build_asr_provider("elevenlabs"), asr_module.ElevenLabsASRProvider)
    assert isinstance(asr_module.build_asr_provider("yandex"), asr_module.YandexSpeechKitASRProvider)
    assert isinstance(asr_module.build_asr_provider("speechkit"), asr_module.YandexSpeechKitASRProvider)
    assert isinstance(
        asr_module.build_streaming_asr_provider("elevenlabs_realtime"),
        asr_module.ElevenLabsRealtimeStreamingASRProvider,
    )
    assert isinstance(
        asr_module.build_streaming_asr_provider("yandex_speechkit"),
        asr_module.YandexSpeechKitGrpcStreamingASRProvider,
    )
    assert isinstance(
        asr_module.build_streaming_asr_provider("yandex_speechkit_buffered"),
        asr_module.YandexSpeechKitBufferedStreamingASRProvider,
    )
