"use client"; import { useEffect, useRef, useState } from "react"; import { motion } from "framer-motion"; interface VoiceChatProps { onTranscript?: (text: string) => void; } export default function VoiceChat({ onTranscript }: VoiceChatProps) { const [isListening, setIsListening] = useState(false); const [transcript, setTranscript] = useState(""); const [response, setResponse] = useState(""); const [isProcessing, setIsProcessing] = useState(false); const [speechSupported, setSpeechSupported] = useState(true); const recognitionRef = useRef(null); const messagesEndRef = useRef(null); useEffect(() => { const SpeechRecognition = (window as any).SpeechRecognition || (window as any).webkitSpeechRecognition; if (!SpeechRecognition) { setSpeechSupported(false); return; } const recognition = new SpeechRecognition(); recognition.lang = "es-ES"; recognition.interimResults = true; recognition.continuous = false; recognition.onresult = (event: any) => { const result = Array.from(event.results) .map((res: any) => res[0]?.transcript ?? "") .join(""); setTranscript(result); }; recognition.onend = () => { setIsListening(false); if (transcript.trim()) { handleSend(transcript); } }; recognition.onerror = (event: any) => { console.error("Speech recognition error:", event.error); setIsListening(false); }; recognitionRef.current = recognition; return () => { if (recognitionRef.current) { recognitionRef.current.abort(); } }; }, []); const toggleListening = () => { if (isListening) { recognitionRef.current?.stop(); setIsListening(false); } else { setTranscript(""); recognitionRef.current?.start(); setIsListening(true); } }; const handleSend = async (text: string) => { if (!text.trim() || isProcessing) return; setIsProcessing(true); const userMessage = text; setTranscript(""); // Simulate AI response (replace with actual API call) const responses: Record = { "hola": "¡Hola! Soy Horus. ¿En qué puedo ayudarte hoy?", "hello": "Hi! I'm Horus. How can I help you today?", "qué tareas": "Tienes varias tareas pendientes en Mission Control. La más crítica es conseguir tu primer cliente pagado.", "what tasks": "You have several pending tasks in Mission Control. The most critical is closing your first paying client.", "estado": "Todo funciona bien. El servidor está en puerto 1284, el firewall configurado, y los briefings están programados para las 6am.", "status": "Everything is running fine. Server on port 1284, firewall configured, briefings scheduled for 6am.", }; // Simple keyword matching let botResponse = "Entendido. Puedo ayudarte con Mission Control, los proyectos SiteMente, o configurar el sistema."; const lower = userMessage.toLowerCase(); for (const [key, value] of Object.entries(responses)) { if (lower.includes(key)) { botResponse = value; break; } } // Simulate delay await new Promise(resolve => setTimeout(resolve, 800)); setResponse(botResponse); setIsProcessing(false); // Speak the response speak(botResponse); if (onTranscript) { onTranscript(userMessage); } }; const speak = (text: string) => { const utterance = new SpeechSynthesisUtterance(text); utterance.lang = "es-ES"; speechSynthesis.speak(utterance); }; const handleKeyPress = (e: React.KeyboardEvent) => { if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); handleSend(transcript); } }; if (!speechSupported) { return (

Voice not supported in this browser

); } return (
{/* Header */}
🎤 Voice Chat
{/* Messages */}
{response && (
👁️

{response}

)} {isProcessing && (
Processing...
)}
{/* Input */}
setTranscript(e.target.value)} onKeyPress={handleKeyPress} placeholder="Or type a message..." className="flex-1 bg-white/10 border border-white/20 rounded-lg px-3 py-2 text-sm text-white placeholder:text-white/40 focus:outline-none focus:border-brand-pink" />
); }