ChatCal.ai-1 / core /session.py
Peter Michael Gits
feat: Initial ChatCal Voice-Enabled Assistant v0.1.0
32e756c
"""
Session Data Model for ChatCal Voice.
Handles conversation state, user information, and session persistence
in the Hugging Face Gradio environment.
"""
from typing import Dict, List, Any, Optional
from datetime import datetime
from dataclasses import dataclass, field
@dataclass
class SessionData:
"""Data structure for user sessions."""
session_id: str
created_at: datetime = field(default_factory=datetime.now)
last_activity: datetime = field(default_factory=datetime.now)
# User information extracted from conversation
user_info: Dict[str, Any] = field(default_factory=lambda: {
"name": None,
"email": None,
"phone": None,
"preferences": {},
"timezone": None
})
# Conversation history
conversation_history: List[Dict[str, str]] = field(default_factory=list)
# Session state for multi-turn operations
session_state: Dict[str, Any] = field(default_factory=lambda: {
"pending_operation": None, # "booking", "cancellation", "availability"
"operation_context": {}, # Context data for operations
"awaiting_clarification": False,
"last_voice_input": None,
"voice_enabled": True
})
# Booking history for this session
booking_history: List[Dict[str, Any]] = field(default_factory=list)
def add_message(self, role: str, content: str):
"""Add a message to conversation history."""
self.conversation_history.append({
"role": role, # "user" or "assistant"
"content": content,
"timestamp": datetime.now().isoformat()
})
# Keep only recent messages to prevent memory issues
max_history = 50
if len(self.conversation_history) > max_history:
self.conversation_history = self.conversation_history[-max_history:]
self.last_activity = datetime.now()
def get_recent_messages(self, count: int = 10) -> List[Dict[str, str]]:
"""Get recent conversation messages."""
return self.conversation_history[-count:] if self.conversation_history else []
def update_user_info(self, **kwargs):
"""Update user information."""
for key, value in kwargs.items():
if key in self.user_info and value:
self.user_info[key] = value
self.last_activity = datetime.now()
def has_required_user_info(self) -> bool:
"""Check if session has minimum required user information."""
return (
bool(self.user_info.get("name")) and
(bool(self.user_info.get("email")) or bool(self.user_info.get("phone")))
)
def get_user_summary(self) -> str:
"""Get a summary of user information."""
name = self.user_info.get("name", "Unknown")
contact = self.user_info.get("email") or self.user_info.get("phone") or "No contact"
return f"{name} ({contact})"
def set_pending_operation(self, operation: str, context: Dict[str, Any] = None):
"""Set a pending operation with context."""
self.session_state["pending_operation"] = operation
self.session_state["operation_context"] = context or {}
self.session_state["awaiting_clarification"] = False
self.last_activity = datetime.now()
def clear_pending_operation(self):
"""Clear any pending operation."""
self.session_state["pending_operation"] = None
self.session_state["operation_context"] = {}
self.session_state["awaiting_clarification"] = False
self.last_activity = datetime.now()
def add_booking(self, booking_info: Dict[str, Any]):
"""Add a booking to the session history."""
booking_info["session_id"] = self.session_id
booking_info["timestamp"] = datetime.now().isoformat()
self.booking_history.append(booking_info)
self.last_activity = datetime.now()
def get_session_duration_minutes(self) -> int:
"""Get session duration in minutes."""
delta = datetime.now() - self.created_at
return int(delta.total_seconds() / 60)
def is_expired(self, timeout_minutes: int = 30) -> bool:
"""Check if session is expired."""
delta = datetime.now() - self.last_activity
return delta.total_seconds() > (timeout_minutes * 60)
def to_dict(self) -> Dict[str, Any]:
"""Convert session to dictionary for serialization."""
return {
"session_id": self.session_id,
"created_at": self.created_at.isoformat(),
"last_activity": self.last_activity.isoformat(),
"user_info": self.user_info,
"conversation_count": len(self.conversation_history),
"session_state": self.session_state,
"booking_count": len(self.booking_history)
}
@classmethod
def from_dict(cls, data: Dict[str, Any]) -> 'SessionData':
"""Create session from dictionary."""
session = cls(session_id=data["session_id"])
session.created_at = datetime.fromisoformat(data["created_at"])
session.last_activity = datetime.fromisoformat(data["last_activity"])
session.user_info = data.get("user_info", {})
session.session_state = data.get("session_state", {})
return session