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:
@@ -8,6 +8,7 @@ from datetime import datetime
|
||||
|
||||
from sqlalchemy import (
|
||||
JSON,
|
||||
Boolean,
|
||||
Column,
|
||||
DateTime,
|
||||
Float,
|
||||
@@ -111,6 +112,7 @@ class Device(Base):
|
||||
priority = Column(Integer, default=10) # Routing priority (lower = higher priority)
|
||||
is_online = Column(String, default="false")
|
||||
capabilities = Column(JSON, default=list) # ["voice", "video", "sms"]
|
||||
dnd = Column(Boolean, default=False, nullable=False)
|
||||
last_seen = Column(DateTime, nullable=True)
|
||||
created_at = Column(DateTime, default=func.now())
|
||||
updated_at = Column(DateTime, default=func.now(), onupdate=func.now())
|
||||
@@ -119,6 +121,55 @@ class Device(Base):
|
||||
return f"<Device {self.id} {self.name} ({self.type})>"
|
||||
|
||||
|
||||
class RoutingRuleRecord(Base):
|
||||
__tablename__ = "routing_rules"
|
||||
|
||||
id = Column(String, primary_key=True)
|
||||
name = Column(String, nullable=False)
|
||||
priority = Column(Integer, default=100, nullable=False) # lower runs first
|
||||
enabled = Column(Boolean, default=True, nullable=False)
|
||||
match = Column(JSON, nullable=False) # caller_pattern, dnis, time_range, days
|
||||
action = Column(JSON, nullable=False) # {type, ...}
|
||||
created_at = Column(DateTime, default=func.now())
|
||||
updated_at = Column(DateTime, default=func.now(), onupdate=func.now())
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"<RoutingRule {self.id} {self.name} p={self.priority}>"
|
||||
|
||||
|
||||
class TranscriptChunk(Base):
|
||||
__tablename__ = "transcript_chunks"
|
||||
|
||||
id = Column(String, primary_key=True)
|
||||
call_id = Column(String, index=True, nullable=False)
|
||||
seq = Column(Integer, nullable=False)
|
||||
t_offset_ms = Column(Integer, default=0) # offset from call start
|
||||
speaker = Column(String, default="unknown") # caller / agent / receptionist / unknown
|
||||
text = Column(Text, nullable=False)
|
||||
confidence = Column(Float, nullable=True)
|
||||
created_at = Column(DateTime, default=func.now())
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"<TranscriptChunk {self.call_id}#{self.seq}>"
|
||||
|
||||
|
||||
class RecordingRecord(Base):
|
||||
__tablename__ = "recordings"
|
||||
|
||||
id = Column(String, primary_key=True)
|
||||
call_id = Column(String, index=True, nullable=False)
|
||||
path = Column(String, nullable=False)
|
||||
format = Column(String, default="wav")
|
||||
duration_s = Column(Float, default=0.0)
|
||||
size_bytes = Column(Integer, default=0)
|
||||
channels = Column(Integer, default=1)
|
||||
started_at = Column(DateTime, default=func.now())
|
||||
ended_at = Column(DateTime, nullable=True)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"<Recording {self.id} call={self.call_id} {self.path}>"
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Engine & Session
|
||||
# ============================================================
|
||||
|
||||
Reference in New Issue
Block a user