"""In-memory session manager for pitch battles.""" from __future__ import annotations import re import uuid from typing import Any SESSIONS: dict[str, dict[str, Any]] = {} def create_session( startup: dict, persona: str, difficulty: str, input_mode: str, ) -> dict[str, Any]: """Create a new pitch battle session.""" session_id = str(uuid.uuid4()) session = { "session_id": session_id, "startup": startup, "persona": persona, "difficulty": difficulty, "input_mode": input_mode, "round": 1, "history": [], "voice_pitch": None, "pending_voice_turns": {}, "confirmed_voice_turns": [], } SESSIONS[session_id] = session return session def get_session(session_id: str) -> dict[str, Any] | None: """Return a session by id, or None if missing.""" return SESSIONS.get(session_id) def append_user_message(session_id: str, message: str) -> None: """Append a user message to session history.""" session = SESSIONS.get(session_id) if not session: return session["history"].append({"role": "user", "content": message}) def append_ai_message(session_id: str, message: str, attack_tag: str) -> None: """Append an AI opponent message to session history.""" session = SESSIONS.get(session_id) if not session: return session["history"].append( {"role": "assistant", "content": message, "attack_tag": attack_tag} ) def increment_round(session_id: str) -> int: """Increment and return the current round number.""" session = SESSIONS.get(session_id) if not session: return 0 session["round"] = session.get("round", 1) + 1 return session["round"] def get_history(session_id: str) -> list[dict[str, Any]]: """Return conversation history for a session.""" session = SESSIONS.get(session_id) if not session: return [] return list(session.get("history", [])) def reset_session(session_id: str) -> bool: """Delete a session. Returns True if it existed.""" if session_id in SESSIONS: del SESSIONS[session_id] return True return False def set_voice_pitch(session_id: str, voice_pitch: dict[str, Any]) -> None: """Store opening voice pitch metadata on session.""" session = SESSIONS.get(session_id) if session: session["voice_pitch"] = voice_pitch def store_pending_voice_turn(session_id: str, turn_record: dict[str, Any]) -> None: """Store a pending (unconfirmed) voice turn.""" session = SESSIONS.get(session_id) if not session: return pending = session.setdefault("pending_voice_turns", {}) vid = turn_record.get("voice_turn_id", "") if vid: pending[vid] = turn_record def confirm_voice_turn( session_id: str, voice_turn_id: str, final_transcript: str, ) -> bool: """Confirm a pending voice turn and move it to confirmed_voice_turns.""" session = SESSIONS.get(session_id) if not session: return False pending = session.get("pending_voice_turns") or {} turn = pending.get(voice_turn_id) if not turn: return False turn = dict(turn) turn["transcript"] = str(final_transcript).strip() turn["confirmed"] = True turn["word_count"] = len(re.findall(r"\b\w+\b", turn["transcript"])) session.setdefault("confirmed_voice_turns", []).append(turn) del pending[voice_turn_id] return True def get_pending_voice_turn(session_id: str, voice_turn_id: str) -> dict[str, Any] | None: """Return a pending voice turn by id.""" session = SESSIONS.get(session_id) if not session: return None return (session.get("pending_voice_turns") or {}).get(voice_turn_id)