feat: add call history API endpoints and TTS service client

Adds read-only access to persisted call records for the dashboard
and implements a client for the Rhema text-to-speech service.

- api/call_history.py: New router providing paged call lists
  and detailed call records with transcript metadata.
- services/tts.py: Async client for OpenAI-compatible TTS
  endpoints (Rhema/Kokoro) used for call-flow steps.
This commit is contained in:
2026-05-22 06:28:33 -04:00
parent dbdb03beb9
commit 63f1a270bb
28 changed files with 2275 additions and 11 deletions

View File

@@ -76,6 +76,38 @@ class HoldSlayerSettings(BaseSettings):
hold_check_interval: float = Field(default=2.0, validation_alias="HOLD_CHECK_INTERVAL")
class TTSSettings(BaseSettings):
"""Rhema TTS service configuration (OpenAI-compatible /v1/audio/speech)."""
model_config = SettingsConfigDict(env_prefix="TTS_")
base_url: str = "http://localhost:8000"
model: str = "speaches-ai/Kokoro-82M-v1.0-ONNX"
voice: str = "af_heart"
api_key: str = ""
timeout: float = 30.0
sample_rate: int = 16000
class ReceptionistSettings(BaseSettings):
"""AI Receptionist behavior settings."""
model_config = SettingsConfigDict(env_prefix="RECEPTIONIST_")
enabled: bool = True
greeting_template: str = (
"Hi, you've reached Robert's line. Who's calling, and what's this about?"
)
message_prompt: str = "Please leave your message after the tone."
listen_timeout_s: float = 15.0
end_of_utterance_silence_s: float = 1.2
message_max_seconds: int = 90
llm_persona: str = (
"You are a helpful, concise phone receptionist. Decide whether to ring "
"the owner, take a message, or politely decline."
)
class Settings(BaseSettings):
"""Root application settings."""
@@ -104,6 +136,8 @@ class Settings(BaseSettings):
classifier: ClassifierSettings = Field(default_factory=ClassifierSettings)
llm: LLMSettings = Field(default_factory=LLMSettings)
hold_slayer: HoldSlayerSettings = Field(default_factory=HoldSlayerSettings)
tts: TTSSettings = Field(default_factory=TTSSettings)
receptionist: ReceptionistSettings = Field(default_factory=ReceptionistSettings)
# Singleton