#!/usr/bin/env python3
"""
LiveTalker Real-time Voice Chat with AI Agent
==============================================
Complete voice conversation system with STT, LLM, and TTS
"""

import asyncio
import json
import logging
import time
import base64
import ssl
import numpy as np
from typing import Dict, List, Any, Optional
from datetime import datetime, timedelta
from cryptography import x509
from cryptography.x509.oid import NameOID
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import rsa
import ipaddress

# FastAPI and WebSocket imports
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
from fastapi.responses import HTMLResponse
import uvicorn

# Speech processing imports
import speech_recognition as sr
from gtts import gTTS
import io
import threading
import queue
import wave
import tempfile
import os

# Setup logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# Global state
app = FastAPI()
active_connections: Dict[str, Dict] = {}
recognizer = sr.Recognizer()

class VoiceChatAgent:
    """Simple conversational AI agent"""
    
    def __init__(self):
        self.conversation_history = []
        self.personality = {
            "name": "LiveTalker Assistant",
            "style": "friendly, helpful, and conversational",
            "traits": ["responsive", "empathetic", "knowledgeable"]
        }
    
    def generate_response(self, user_input: str) -> str:
        """Generate AI response (placeholder for actual LLM integration)"""
        # Store user input
        self.conversation_history.append({"role": "user", "content": user_input})
        
        # Simple rule-based responses for testing
        user_lower = user_input.lower()
        
        if "hello" in user_lower or "hi" in user_lower:
            response = "Hello! I'm your LiveTalker voice assistant. How can I help you today?"
        elif "how are you" in user_lower:
            response = "I'm doing great, thank you for asking! I'm here to have a conversation with you."
        elif "what can you do" in user_lower:
            response = "I can have real-time voice conversations with you! I listen to your speech, understand what you're saying, and respond back with voice. We can chat about anything you'd like."
        elif "weather" in user_lower:
            response = "I don't have access to current weather data, but I'd be happy to chat about the weather or anything else!"
        elif "time" in user_lower:
            current_time = datetime.now().strftime("%I:%M %p")
            response = f"The current time is {current_time}. Is there anything else I can help you with?"
        elif "name" in user_lower:
            response = "I'm LiveTalker, your real-time voice assistant! What's your name?"
        elif "goodbye" in user_lower or "bye" in user_lower:
            response = "Goodbye! It was great talking with you. Feel free to start another conversation anytime!"
        elif len(user_input.split()) < 3:
            response = "I heard you, but could you tell me a bit more? I'd love to have a longer conversation!"
        else:
            response = f"That's interesting! You said: '{user_input}'. I'm here to chat and help however I can. What would you like to talk about?"
        
        # Store assistant response
        self.conversation_history.append({"role": "assistant", "content": response})
        return response

def simple_vad(audio: np.ndarray, threshold: float = 0.02) -> tuple:
    """Simple VAD based on energy"""
    if len(audio) == 0:
        return False, 0.0
    
    # Energy-based VAD
    energy = np.sqrt(np.mean(audio**2))
    is_speech = energy > threshold
    confidence = min(energy / threshold, 1.0) if is_speech else energy / threshold
    
    return bool(is_speech), float(confidence)

def audio_to_text(audio_data: bytes) -> Optional[str]:
    """Convert audio to text using speech recognition"""
    try:
        # Create temporary WAV file
        with tempfile.NamedTemporaryFile(delete=False, suffix='.wav') as tmp_file:
            # Convert raw audio to WAV format
            with wave.open(tmp_file.name, 'wb') as wav_file:
                wav_file.setnchannels(1)  # Mono
                wav_file.setsampwidth(2)  # 16-bit
                wav_file.setframerate(16000)  # 16kHz
                wav_file.writeframes(audio_data)
            
            # Recognize speech
            with sr.AudioFile(tmp_file.name) as source:
                audio = recognizer.record(source)
                text = recognizer.recognize_google(audio)
                
            os.unlink(tmp_file.name)  # Clean up
            return text
            
    except sr.UnknownValueError:
        return None  # Could not understand audio
    except sr.RequestError as e:
        logger.error(f"Speech recognition error: {e}")
        return None
    except Exception as e:
        logger.error(f"Audio to text error: {e}")
        return None

def text_to_speech(text: str) -> Optional[bytes]:
    """Convert text to speech audio"""
    try:
        tts = gTTS(text=text, lang='en', slow=False)
        audio_buffer = io.BytesIO()
        tts.write_to_fp(audio_buffer)
        audio_buffer.seek(0)
        return audio_buffer.read()
    except Exception as e:
        logger.error(f"Text to speech error: {e}")
        return None

def create_ssl_certificate():
    """Create self-signed SSL certificate for HTTPS"""
    try:
        # Generate private key
        private_key = rsa.generate_private_key(
            public_exponent=65537,
            key_size=2048,
        )
        
        # Create certificate
        subject = issuer = x509.Name([
            x509.NameAttribute(NameOID.COUNTRY_NAME, "US"),
            x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, "CA"),
            x509.NameAttribute(NameOID.LOCALITY_NAME, "Local"),
            x509.NameAttribute(NameOID.ORGANIZATION_NAME, "LiveTalker"),
            x509.NameAttribute(NameOID.COMMON_NAME, "localhost"),
        ])
        
        cert = x509.CertificateBuilder().subject_name(
            subject
        ).issuer_name(
            issuer
        ).public_key(
            private_key.public_key()
        ).serial_number(
            x509.random_serial_number()
        ).not_valid_before(
            datetime.utcnow()
        ).not_valid_after(
            datetime.utcnow() + timedelta(days=365)
        ).add_extension(
            x509.SubjectAlternativeName([
                x509.DNSName("localhost"),
                x509.DNSName("*.localhost"),
                x509.IPAddress(ipaddress.IPv4Address("127.0.0.1")),
                x509.IPAddress(ipaddress.IPv4Address("0.0.0.0")),
            ]),
            critical=False,
        ).sign(private_key, hashes.SHA256())
        
        # Write certificate and key files
        cert_path = "livetalker.crt"
        key_path = "livetalker.key"
        
        with open(cert_path, "wb") as f:
            f.write(cert.public_bytes(serialization.Encoding.PEM))
        
        with open(key_path, "wb") as f:
            f.write(private_key.private_bytes(
                encoding=serialization.Encoding.PEM,
                format=serialization.PrivateFormat.PKCS8,
                encryption_algorithm=serialization.NoEncryption()
            ))
        
        print(f"✅ SSL certificate created: {cert_path}")
        print(f"✅ SSL private key created: {key_path}")
        return cert_path, key_path
    
    except Exception as e:
        print(f"❌ Failed to create SSL certificate: {e}")
        return None, None

@app.get("/")
async def root():
    """Real-time voice chat interface"""
    html_content = """<!DOCTYPE html>
<html>
<head>
    <title>LiveTalker Real-time Voice Chat</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style>
        body { 
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
            margin: 0; padding: 20px;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white; min-height: 100vh;
        }
        .container { 
            max-width: 1200px; margin: 0 auto; 
            background: rgba(255,255,255,0.1);
            padding: 30px; border-radius: 20px;
            backdrop-filter: blur(15px);
            box-shadow: 0 15px 35px rgba(0,0,0,0.2);
        }
        h1 { 
            text-align: center; margin-bottom: 30px; 
            font-size: 2.5em; font-weight: 700;
            background: linear-gradient(45deg, #ff6b6b, #feca57);
            -webkit-background-clip: text;
            background-clip: text;
            -webkit-text-fill-color: transparent;
        }
        .chat-container {
            display: grid; grid-template-columns: 1fr 300px; gap: 20px;
            height: 70vh; max-height: 600px;
        }
        
        .conversation {
            background: rgba(0,0,0,0.2); border-radius: 15px;
            padding: 20px; overflow-y: auto;
            border: 1px solid rgba(255,255,255,0.1);
        }
        .message {
            margin: 15px 0; padding: 15px; border-radius: 12px;
            max-width: 80%; animation: fadeIn 0.3s ease;
        }
        @keyframes fadeIn {
            from { opacity: 0; transform: translateY(10px); }
            to { opacity: 1; transform: translateY(0); }
        }
        .message.user {
            background: linear-gradient(135deg, #4facfe, #00f2fe);
            margin-left: auto; text-align: right;
            color: #000; font-weight: 500;
        }
        .message.assistant {
            background: linear-gradient(135deg, #fa709a, #fee140);
            margin-right: auto; color: #000; font-weight: 500;
        }
        .message.system {
            background: rgba(255,255,255,0.2);
            text-align: center; margin: 10px auto;
            font-style: italic; max-width: 90%;
        }
        
        .controls {
            background: rgba(0,0,0,0.2); border-radius: 15px;
            padding: 20px; border: 1px solid rgba(255,255,255,0.1);
        }
        .control-section {
            margin-bottom: 20px;
        }
        .control-section h3 {
            margin: 0 0 15px 0; font-size: 1.2em;
            color: #feca57; text-transform: uppercase;
            letter-spacing: 1px;
        }
        
        .mic-button {
            width: 100%; height: 80px; border: none; border-radius: 12px;
            font-size: 18px; font-weight: 600; cursor: pointer;
            transition: all 0.3s ease; margin-bottom: 15px;
            display: flex; align-items: center; justify-content: center;
        }
        .mic-button.inactive {
            background: linear-gradient(135deg, #ff6b6b, #ee5a24);
            color: white;
        }
        .mic-button.active {
            background: linear-gradient(135deg, #20bf6b, #26d0ce);
            color: white; animation: pulse 1.5s infinite;
        }
        @keyframes pulse {
            0%, 100% { transform: scale(1); }
            50% { transform: scale(1.05); }
        }
        
        .status {
            background: rgba(255,255,255,0.1); padding: 12px;
            border-radius: 8px; margin: 10px 0;
            font-size: 14px; text-align: center;
        }
        .status.listening {
            background: rgba(32, 191, 107, 0.3);
            border: 1px solid #20bf6b;
        }
        .status.processing {
            background: rgba(254, 202, 87, 0.3);
            border: 1px solid #feca57;
        }
        .status.speaking {
            background: rgba(250, 112, 154, 0.3);
            border: 1px solid #fa709a;
        }
        
        .stats {
            background: rgba(255,255,255,0.05);
            padding: 15px; border-radius: 10px;
            font-size: 13px; margin-top: 10px;
        }
        .stats div {
            display: flex; justify-content: space-between;
            margin: 5px 0; padding: 3px 0;
        }
        .stats .label { color: #a8a8a8; }
        .stats .value { color: #feca57; font-weight: 600; }
    </style>
</head>
<body>
    <div class="container">
        <h1>🎙️ LiveTalker Voice Chat</h1>
        <div class="chat-container">
            <div class="conversation" id="conversation">
                <div class="message system">
                    Welcome to LiveTalker! Click "Start Conversation" to begin voice chat.
                </div>
            </div>
            
            <div class="controls">
                <div class="control-section">
                    <h3>Voice Controls</h3>
                    <button class="mic-button inactive" id="micButton" onclick="toggleListening()">
                        🎤 Start Conversation
                    </button>
                    <div class="status" id="status">Ready to chat</div>
                </div>
                
                <div class="control-section">
                    <h3>Live Stats</h3>
                    <div class="stats" id="stats">
                        <div><span class="label">Connection:</span> <span class="value" id="connectionStatus">Connecting...</span></div>
                        <div><span class="label">VAD Active:</span> <span class="value" id="vadStatus">No</span></div>
                        <div><span class="label">Speech Confidence:</span> <span class="value" id="confidence">0%</span></div>
                        <div><span class="label">Messages:</span> <span class="value" id="messageCount">0</span></div>
                        <div><span class="label">Session Time:</span> <span class="value" id="sessionTime">00:00</span></div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <script>
        let socket = null;
        let mediaRecorder = null;
        let audioStream = null;
        let isListening = false;
        let messageCount = 0;
        let sessionStartTime = null;
        let audioContext = null;
        let audioProcessor = null;

        // Initialize WebSocket connection
        function initializeWebSocket() {
            const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
            const url = `${protocol}//${location.host}/voice-chat`;
            
            socket = new WebSocket(url);
            
            socket.onopen = function() {
                updateConnectionStatus('Connected');
                addSystemMessage('🔗 Connected to voice chat server');
            };
            
            socket.onmessage = function(event) {
                const data = JSON.parse(event.data);
                handleServerMessage(data);
            };
            
            socket.onclose = function() {
                updateConnectionStatus('Disconnected');
                addSystemMessage('❌ Disconnected from server');
            };
            
            socket.onerror = function(error) {
                console.error('WebSocket error:', error);
                updateConnectionStatus('Error');
            };
        }
        
        function handleServerMessage(data) {
            switch(data.type) {
                case 'config':
                    addSystemMessage(`✅ Session started: ${data.session_id}`);
                    sessionStartTime = Date.now();
                    break;
                    
                case 'vad_result':
                    updateVADStatus(data.is_speech, data.confidence);
                    break;
                    
                case 'transcript':
                    if (data.text) {
                        addUserMessage(data.text);
                    }
                    break;
                    
                case 'agent_response':
                    addAssistantMessage(data.text);
                    updateStatus('Speaking');
                    if (data.audio) {
                        playAudioResponse(data.audio);
                    }
                    break;
                    
                case 'processing_complete':
                    updateStatus(isListening ? 'Listening...' : 'Ready to chat');
                    break;
                    
                case 'error':
                    addSystemMessage(`⚠️ Error: ${data.error}`);
                    break;
            }
        }
        
        async function toggleListening() {
            if (!isListening) {
                await startListening();
            } else {
                stopListening();
            }
        }
        
        async function startListening() {
            try {
                audioStream = await navigator.mediaDevices.getUserMedia({
                    audio: {
                        sampleRate: 16000,
                        channelCount: 1,
                        echoCancellation: true,
                        noiseSuppression: true
                    }
                });
                
                audioContext = new AudioContext({ sampleRate: 16000 });
                const source = audioContext.createMediaStreamSource(audioStream);
                audioProcessor = audioContext.createScriptProcessor(4096, 1, 1);
                
                audioProcessor.onaudioprocess = function(event) {
                    const inputData = event.inputBuffer.getChannelData(0);
                    const pcmData = new Int16Array(inputData.length);
                    
                    for (let i = 0; i < inputData.length; i++) {
                        pcmData[i] = Math.max(-32768, Math.min(32767, inputData[i] * 32767));
                    }
                    
                    if (socket && socket.readyState === WebSocket.OPEN) {
                        const audioData = btoa(String.fromCharCode.apply(null, new Uint8Array(pcmData.buffer)));
                        socket.send(JSON.stringify({
                            type: 'audio',
                            data: audioData
                        }));
                    }
                };
                
                source.connect(audioProcessor);
                audioProcessor.connect(audioContext.destination);
                
                isListening = true;
                updateMicButton();
                updateStatus('Listening...');
                
                if (socket && socket.readyState === WebSocket.OPEN) {
                    socket.send(JSON.stringify({ type: 'start_conversation' }));
                }
                
            } catch (error) {
                console.error('Error starting audio:', error);
                addSystemMessage('❌ Error accessing microphone: ' + error.message);
            }
        }
        
        function stopListening() {
            if (audioStream) {
                audioStream.getTracks().forEach(track => track.stop());
                audioStream = null;
            }
            if (audioProcessor) {
                audioProcessor.disconnect();
                audioProcessor = null;
            }
            if (audioContext) {
                audioContext.close();
                audioContext = null;
            }
            
            isListening = false;
            updateMicButton();
            updateStatus('Ready to chat');
            
            if (socket && socket.readyState === WebSocket.OPEN) {
                socket.send(JSON.stringify({ type: 'stop_listening' }));
            }
        }
        
        function playAudioResponse(audioData) {
            try {
                const audioBytes = atob(audioData);
                const audioArray = new Uint8Array(audioBytes.length);
                for (let i = 0; i < audioBytes.length; i++) {
                    audioArray[i] = audioBytes.charCodeAt(i);
                }
                
                const audioBlob = new Blob([audioArray], { type: 'audio/mpeg' });
                const audioUrl = URL.createObjectURL(audioBlob);
                const audio = new Audio(audioUrl);
                
                audio.onended = function() {
                    URL.revokeObjectURL(audioUrl);
                    updateStatus(isListening ? 'Listening...' : 'Ready to chat');
                };
                
                audio.play().catch(e => console.error('Audio playback error:', e));
            } catch (error) {
                console.error('Error playing audio:', error);
            }
        }
        
        function addUserMessage(text) {
            const conversation = document.getElementById('conversation');
            const messageDiv = document.createElement('div');
            messageDiv.className = 'message user';
            messageDiv.textContent = `You: ${text}`;
            conversation.appendChild(messageDiv);
            conversation.scrollTop = conversation.scrollHeight;
            messageCount++;
            updateMessageCount();
        }
        
        function addAssistantMessage(text) {
            const conversation = document.getElementById('conversation');
            const messageDiv = document.createElement('div');
            messageDiv.className = 'message assistant';
            messageDiv.textContent = `Assistant: ${text}`;
            conversation.appendChild(messageDiv);
            conversation.scrollTop = conversation.scrollHeight;
            messageCount++;
            updateMessageCount();
        }
        
        function addSystemMessage(text) {
            const conversation = document.getElementById('conversation');
            const messageDiv = document.createElement('div');
            messageDiv.className = 'message system';
            messageDiv.textContent = text;
            conversation.appendChild(messageDiv);
            conversation.scrollTop = conversation.scrollHeight;
        }
        
        function updateMicButton() {
            const button = document.getElementById('micButton');
            if (isListening) {
                button.className = 'mic-button active';
                button.textContent = '🛑 Stop Conversation';
            } else {
                button.className = 'mic-button inactive';
                button.textContent = '🎤 Start Conversation';
            }
        }
        
        function updateStatus(text) {
            const status = document.getElementById('status');
            status.textContent = text;
            
            // Update status styling
            status.className = 'status';
            if (text.includes('Listening')) {
                status.classList.add('listening');
            } else if (text.includes('Processing')) {
                status.classList.add('processing');
            } else if (text.includes('Speaking')) {
                status.classList.add('speaking');
            }
        }
        
        function updateConnectionStatus(status) {
            document.getElementById('connectionStatus').textContent = status;
        }
        
        function updateVADStatus(isSpeech, confidence) {
            document.getElementById('vadStatus').textContent = isSpeech ? 'Yes' : 'No';
            document.getElementById('confidence').textContent = `${Math.round(confidence * 100)}%`;
        }
        
        function updateMessageCount() {
            document.getElementById('messageCount').textContent = messageCount;
        }
        
        function updateSessionTime() {
            if (sessionStartTime) {
                const elapsed = Math.floor((Date.now() - sessionStartTime) / 1000);
                const minutes = Math.floor(elapsed / 60);
                const seconds = elapsed % 60;
                document.getElementById('sessionTime').textContent = 
                    `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
            }
        }
        
        // Initialize on page load
        window.onload = function() {
            initializeWebSocket();
            setInterval(updateSessionTime, 1000);
        };
    </script>
</body>
</html>"""
    return HTMLResponse(content=html_content)

@app.websocket("/voice-chat")
async def voice_chat_endpoint(websocket: WebSocket):
    """WebSocket endpoint for real-time voice chat"""
    await websocket.accept()
    session_id = f"chat_{int(time.time() * 1000)}"
    
    # Initialize voice chat agent
    agent = VoiceChatAgent()
    
    session = {
        "id": session_id,
        "websocket": websocket,
        "agent": agent,
        "audio_buffer": [],
        "is_listening": False,
        "last_speech": 0,
        "processing": False
    }
    active_connections[session_id] = session
    
    logger.info(f"Voice chat session started: {session_id}")
    
    try:
        await websocket.send_json({
            "type": "config",
            "session_id": session_id,
            "message": "Voice chat ready!",
            "agent_name": agent.personality["name"]
        })
        
        async for message in websocket.iter_json():
            await handle_voice_message(session, message)
            
    except WebSocketDisconnect:
        logger.info(f"Voice chat session ended: {session_id}")
    except Exception as e:
        logger.error(f"Voice chat error: {e}")
        try:
            await websocket.send_json({
                "type": "error",
                "error": str(e)
            })
        except:
            pass
    finally:
        if session_id in active_connections:
            del active_connections[session_id]

async def handle_voice_message(session: Dict, message: Dict[str, Any]):
    """Handle voice chat messages"""
    msg_type = message.get("type")
    
    if msg_type == "start_conversation":
        session["is_listening"] = True
        await session["websocket"].send_json({
            "type": "conversation_started",
            "message": "🎤 Voice chat started! Speak into your microphone."
        })
        
    elif msg_type == "audio" and session["is_listening"] and not session["processing"]:
        try:
            # Decode audio
            audio_data = base64.b64decode(message["data"])
            audio_np = np.frombuffer(audio_data, dtype=np.int16).astype(np.float32) / 32768.0
            
            if len(audio_np) > 0:
                # VAD check
                is_speech, confidence = simple_vad(audio_np, threshold=0.025)
                
                await session["websocket"].send_json({
                    "type": "vad_result",
                    "is_speech": bool(is_speech),
                    "confidence": float(confidence)
                })
                
                # Accumulate speech
                if is_speech:
                    session["audio_buffer"].extend(audio_data)
                    session["last_speech"] = time.time()
                    
                    # Process if we have enough audio or silence detected
                    if len(session["audio_buffer"]) > 32000:  # ~2 seconds of 16kHz audio
                        await process_voice_conversation(session)
                        
                elif (len(session["audio_buffer"]) > 16000 and  # At least 1 second
                      time.time() - session["last_speech"] > 1.0):  # 1 second silence
                    await process_voice_conversation(session)
                    
        except Exception as e:
            await session["websocket"].send_json({
                "type": "error",
                "error": f"Audio processing error: {str(e)}"
            })
            
    elif msg_type == "stop_listening":
        session["is_listening"] = False
        if session["audio_buffer"]:
            await process_voice_conversation(session)

async def process_voice_conversation(session: Dict):
    """Process complete voice conversation turn"""
    if not session["audio_buffer"] or session["processing"]:
        return
    
    session["processing"] = True
    
    try:
        # Convert audio to text
        audio_bytes = bytes(session["audio_buffer"])
        session["audio_buffer"] = []  # Clear buffer
        
        logger.info(f"Processing {len(audio_bytes)} bytes of audio for transcription")
        
        # Run STT in thread to avoid blocking
        def transcribe_audio():
            return audio_to_text(audio_bytes)
        
        # Simple async wrapper for thread
        import concurrent.futures
        with concurrent.futures.ThreadPoolExecutor() as executor:
            future = executor.submit(transcribe_audio)
            transcript = future.result(timeout=10)  # 10 second timeout
        
        if transcript:
            logger.info(f"Transcript: {transcript}")
            
            # Send transcript to user
            await session["websocket"].send_json({
                "type": "transcript",
                "text": transcript
            })
            
            # Generate AI response
            response_text = session["agent"].generate_response(transcript)
            logger.info(f"Agent response: {response_text}")
            
            # Convert response to speech
            def generate_speech():
                return text_to_speech(response_text)
            
            with concurrent.futures.ThreadPoolExecutor() as executor:
                future = executor.submit(generate_speech)
                audio_response = future.result(timeout=15)  # 15 second timeout
            
            # Send response to client
            response_data = {
                "type": "agent_response",
                "text": response_text
            }
            
            if audio_response:
                response_data["audio"] = base64.b64encode(audio_response).decode('utf-8')
            
            await session["websocket"].send_json(response_data)
            
        else:
            logger.info("No transcript generated from audio")
            
    except Exception as e:
        logger.error(f"Voice conversation processing error: {e}")
        await session["websocket"].send_json({
            "type": "error", 
            "error": f"Conversation processing error: {str(e)}"
        })
    finally:
        session["processing"] = False
        await session["websocket"].send_json({
            "type": "processing_complete"
        })

if __name__ == "__main__":
    print("🎙️ LiveTalker Real-time Voice Chat")
    print("=" * 50)
    
    # Create SSL certificates
    cert_path, key_path = create_ssl_certificate()
    if not cert_path or not key_path:
        print("❌ Failed to create SSL certificates")
        exit(1)
    
    print("✅ SSL certificate ready")
    print("✅ Speech recognition ready")
    print("✅ Text-to-speech ready")
    print("✅ AI agent ready")
    
    # Get local IP
    import socket
    hostname = socket.gethostname()
    local_ip = socket.gethostbyname(hostname)
    
    print("\n🌐 HTTPS URLs:")
    print(f"   Local:   https://localhost:8000")
    print(f"   Network: https://{local_ip}:8000")
    print("\n🔧 Features:")
    print("   ✅ Real-time voice conversation")
    print("   ✅ Speech-to-text transcription")
    print("   ✅ AI agent responses")
    print("   ✅ Text-to-speech synthesis")
    print("   ✅ SSL/TLS encryption")
    print("\n⚠️  You may see browser security warnings for the self-signed certificate.")
    print("   Click 'Advanced' → 'Continue to site' to proceed.")
    
    # Configure SSL
    ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
    ssl_context.load_cert_chain(cert_path, key_path)
    
    # Start server
    uvicorn.run(app, host="0.0.0.0", port=8000, ssl=ssl_context)