feat: add py.typed, Ray handles for clients, and pre-commit config
All checks were successful
CI / Test (push) Successful in 4m8s
CI / Lint (push) Successful in 4m19s
CI / Release (push) Successful in 58s
CI / Notify (push) Successful in 2s

- Add py.typed marker for PEP 561 type hint support
- Add ray_utils module for Ray handle detection and caching
- Update all clients (Embeddings, LLM, TTS, STT, Reranker) to use
  Ray handles when running inside Ray cluster for faster internal calls
- Add .pre-commit-config.yaml with ruff and standard hooks
- Add pre-commit and ray[serve] to optional dependencies
- Bump ruff version to 0.4.0
This commit is contained in:
2026-02-02 09:08:43 -05:00
parent dbf1a93141
commit 408f31e56d
10 changed files with 1506 additions and 8 deletions

View File

@@ -1,13 +1,16 @@
"""
TTS service client (Coqui XTTS).
Supports both HTTP (external) and Ray handles (internal) for optimal performance.
"""
import logging
from typing import Optional
from typing import Any, Optional
import httpx
from handler_base.config import TTSSettings
from handler_base.ray_utils import get_ray_handle
from handler_base.telemetry import create_span
logger = logging.getLogger(__name__)
@@ -17,17 +20,33 @@ class TTSClient:
"""
Client for the TTS service (Coqui XTTS).
When running inside Ray, automatically uses Ray handles for faster
internal communication. Falls back to HTTP for external calls.
Usage:
client = TTSClient()
audio_bytes = await client.synthesize("Hello world")
"""
# Ray Serve deployment configuration
RAY_DEPLOYMENT_NAME = "TTSDeployment"
RAY_APP_NAME = "tts"
def __init__(self, settings: Optional[TTSSettings] = None):
self.settings = settings or TTSSettings()
self._client = httpx.AsyncClient(
base_url=self.settings.tts_url,
timeout=120.0, # TTS can be slow
)
self._ray_handle: Optional[Any] = None
self._ray_checked = False
def _get_ray_handle(self) -> Optional[Any]:
"""Get Ray handle, checking only once."""
if not self._ray_checked:
self._ray_handle = get_ray_handle(self.RAY_DEPLOYMENT_NAME, self.RAY_APP_NAME)
self._ray_checked = True
return self._ray_handle
async def close(self) -> None:
"""Close the HTTP client."""
@@ -64,6 +83,23 @@ class TTSClient:
if speaker:
params["speaker_id"] = speaker
# Try Ray handle first (faster internal path)
handle = self._get_ray_handle()
if handle:
try:
if span:
span.set_attribute("tts.transport", "ray")
audio_bytes = await handle.synthesize.remote(text, language, speaker)
if span:
span.set_attribute("tts.audio_size", len(audio_bytes))
return audio_bytes
except Exception as e:
logger.warning(f"Ray handle failed, falling back to HTTP: {e}")
# HTTP fallback
if span:
span.set_attribute("tts.transport", "http")
response = await self._client.get("/api/tts", params=params)
response.raise_for_status()