Add show improvement features: crossfade, emotions, returning callers, transcripts, screening
- Music crossfade: smooth 3-second blend between tracks instead of hard stop/start - Emotional detection: analyze host mood from recent messages so callers adapt tone - AI caller summaries: generate call summaries with timestamps for show history - Returning callers: persist regular callers across sessions with call history - Session export: generate transcripts with speaker labels and chapter markers - Caller screening: AI pre-screens phone callers to get name and topic while queued Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
95
backend/services/regulars.py
Normal file
95
backend/services/regulars.py
Normal file
@@ -0,0 +1,95 @@
|
||||
"""Returning caller persistence service"""
|
||||
|
||||
import json
|
||||
import time
|
||||
import uuid
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
DATA_FILE = Path(__file__).parent.parent.parent / "data" / "regulars.json"
|
||||
MAX_REGULARS = 12
|
||||
|
||||
|
||||
class RegularCallerService:
|
||||
"""Manages persistent 'regular' callers who return across sessions"""
|
||||
|
||||
def __init__(self):
|
||||
self._regulars: list[dict] = []
|
||||
self._load()
|
||||
|
||||
def _load(self):
|
||||
if DATA_FILE.exists():
|
||||
try:
|
||||
with open(DATA_FILE) as f:
|
||||
data = json.load(f)
|
||||
self._regulars = data.get("regulars", [])
|
||||
print(f"[Regulars] Loaded {len(self._regulars)} regular callers")
|
||||
except Exception as e:
|
||||
print(f"[Regulars] Failed to load: {e}")
|
||||
self._regulars = []
|
||||
|
||||
def _save(self):
|
||||
try:
|
||||
DATA_FILE.parent.mkdir(parents=True, exist_ok=True)
|
||||
with open(DATA_FILE, "w") as f:
|
||||
json.dump({"regulars": self._regulars}, f, indent=2)
|
||||
except Exception as e:
|
||||
print(f"[Regulars] Failed to save: {e}")
|
||||
|
||||
def get_regulars(self) -> list[dict]:
|
||||
return list(self._regulars)
|
||||
|
||||
def get_returning_callers(self, count: int = 2) -> list[dict]:
|
||||
"""Get up to `count` regulars for returning caller slots"""
|
||||
import random
|
||||
if not self._regulars:
|
||||
return []
|
||||
available = [r for r in self._regulars if len(r.get("call_history", [])) > 0]
|
||||
if not available:
|
||||
return []
|
||||
return random.sample(available, min(count, len(available)))
|
||||
|
||||
def add_regular(self, name: str, gender: str, age: int, job: str,
|
||||
location: str, personality_traits: list[str],
|
||||
first_call_summary: str) -> dict:
|
||||
"""Promote a first-time caller to regular"""
|
||||
# Retire oldest if at cap
|
||||
if len(self._regulars) >= MAX_REGULARS:
|
||||
self._regulars.sort(key=lambda r: r.get("last_call", 0))
|
||||
retired = self._regulars.pop(0)
|
||||
print(f"[Regulars] Retired {retired['name']} to make room")
|
||||
|
||||
regular = {
|
||||
"id": str(uuid.uuid4())[:8],
|
||||
"name": name,
|
||||
"gender": gender,
|
||||
"age": age,
|
||||
"job": job,
|
||||
"location": location,
|
||||
"personality_traits": personality_traits,
|
||||
"call_history": [
|
||||
{"summary": first_call_summary, "timestamp": time.time()}
|
||||
],
|
||||
"last_call": time.time(),
|
||||
"created_at": time.time(),
|
||||
}
|
||||
self._regulars.append(regular)
|
||||
self._save()
|
||||
print(f"[Regulars] Promoted {name} to regular (total: {len(self._regulars)})")
|
||||
return regular
|
||||
|
||||
def update_after_call(self, regular_id: str, call_summary: str):
|
||||
"""Update a regular's history after a returning call"""
|
||||
for regular in self._regulars:
|
||||
if regular["id"] == regular_id:
|
||||
regular.setdefault("call_history", []).append(
|
||||
{"summary": call_summary, "timestamp": time.time()}
|
||||
)
|
||||
regular["last_call"] = time.time()
|
||||
self._save()
|
||||
print(f"[Regulars] Updated {regular['name']} call history ({len(regular['call_history'])} calls)")
|
||||
return
|
||||
print(f"[Regulars] Regular {regular_id} not found for update")
|
||||
|
||||
|
||||
regular_caller_service = RegularCallerService()
|
||||
Reference in New Issue
Block a user