from pathlib import Path from typing import Any from .ai import AIClientError from .speech import SpeechRecognitionError class YandexAIError(AIClientError): pass def create_async_sdk(folder_id: str) -> Any: try: from yandex_ai_studio_sdk import AsyncAIStudio except ImportError as exc: raise RuntimeError( "Yandex AI Studio SDK is not installed. " "Run: python -m pip install -r requirements.txt" ) from exc return AsyncAIStudio(folder_id=folder_id) def create_sync_sdk(folder_id: str) -> Any: try: from yandex_ai_studio_sdk import AIStudio except ImportError as exc: raise RuntimeError( "Yandex AI Studio SDK is not installed. " "Run: python -m pip install -r requirements.txt" ) from exc return AIStudio(folder_id=folder_id) class YandexAIClient: provider = "yandex" display_name = "Yandex AI Studio" def __init__(self, folder_id: str, sdk: Any | None = None) -> None: self.folder_id = folder_id.strip("/") self._sdk = sdk if sdk is not None else create_async_sdk(self.folder_id) def normalize_model(self, model: str) -> str: normalized = model.strip() if normalized.startswith("gpt://"): return normalized return f"gpt://{self.folder_id}/{normalized.lstrip('/')}" async def list_models(self) -> list[str]: try: models = await self._sdk.chat.completions.list() except Exception as exc: raise YandexAIError(f"Не удалось получить список моделей: {exc}") from exc model_names = { str(uri) for model in models if (uri := getattr(model, "uri", None)) } return sorted(model_names) async def chat( self, model: str, messages: list[dict[str, str]], json_mode: bool = False, ) -> str: sdk_messages = [ { "role": message.get("role", "user"), "text": message.get("content", ""), } for message in messages ] try: completion = self._sdk.models.completions(self.normalize_model(model)) if json_mode: completion = completion.configure(response_format="json") result = await completion.run(sdk_messages, timeout=180) content = getattr(result[0], "text", None) except Exception as exc: raise YandexAIError(f"Запрос к модели завершился ошибкой: {exc}") from exc if isinstance(content, str) and content.strip(): return content.strip() raise YandexAIError("Yandex AI Studio вернула пустой ответ.") class YandexSpeechRecognizer: def __init__( self, folder_id: str, language: str, model: str, sdk: Any | None = None, ) -> None: self.folder_id = folder_id.strip("/") self.language = language self.model = model self._sdk = sdk if sdk is not None else create_sync_sdk(self.folder_id) def transcribe(self, audio_path: str | Path) -> str: try: audio = Path(audio_path).read_bytes() recognizer = self._sdk.speechkit.speech_to_text( audio_format=self._sdk.speechkit.AudioFormat.OGG_OPUS, language_codes=self.language, model=self.model, ) result = recognizer.run(audio, timeout=180) text = getattr(result, "text", None) except Exception as exc: raise SpeechRecognitionError("Yandex SpeechKit transcription failed") from exc return text.strip() if isinstance(text, str) else ""