from abc import ABC, abstractmethod from pydantic import BaseModel from yuxi.utils.logging_config import logger class VoiceSegment(BaseModel): audio_data: bytes sample_rate: int = 16000 channels: int = 1 encoding: str = "pcm_s16le" duration_ms: int = 0 class STTResult(BaseModel): text: str confidence: float = 0.0 language: str | None = None class STTProvider(ABC): @abstractmethod async def transcribe(self, segment: VoiceSegment) -> STTResult: ... class TTSProvider(ABC): @abstractmethod async def synthesize(self, text: str, voice: str = "default") -> bytes: ... class VoicePolicy: def __init__(self): self._stt_provider: STTProvider | None = None self._tts_provider: TTSProvider | None = None def configure_stt(self, provider: STTProvider) -> None: self._stt_provider = provider def configure_tts(self, provider: TTSProvider) -> None: self._tts_provider = provider async def process_voice(self, segment: VoiceSegment) -> str | None: if not self._stt_provider: return None try: result = await self._stt_provider.transcribe(segment) except Exception as e: logger.error(f"STT transcription failed: {e}") return None return result.text or None async def text_to_speech(self, text: str) -> bytes | None: if not self._tts_provider: return None try: return await self._tts_provider.synthesize(text) except Exception as e: logger.error(f"TTS synthesis failed: {e}") return None