import { useState, useCallback } from "react"; import { Masthead } from "../components/Masthead"; import { useSpeakWebSocket } from "../hooks/useSpeakWebSocket"; export default function SpeakPage() { const [text, setText] = useState(""); const tts = useSpeakWebSocket(); const handleSpeak = useCallback(() => { if (!text.trim()) return; tts.speak(text); }, [text, tts]); const handleCancel = useCallback(() => { tts.cancel(); }, [tts]); const handleKeyDown = useCallback( (e: React.KeyboardEvent) => { // Ctrl/Cmd + Enter to speak if ((e.ctrlKey || e.metaKey) && e.key === "Enter") { e.preventDefault(); handleSpeak(); } }, [handleSpeak] ); const statusLabel = (() => { switch (tts.status) { case "disconnected": return "DISCONNECTED"; case "connecting": return "CONNECTING..."; case "connected": return "CONNECTED"; case "loading_model": return "LOADING TTS MODEL..."; case "speaking": return "SPEAKING"; case "error": return "ERROR"; default: return "IDLE"; } })(); const statusColor = (() => { switch (tts.status) { case "connected": case "speaking": return "border-[#3f6fb3] text-[#75aafc]"; case "error": return "border-red-400/50 text-red-400"; default: return "border-[rgba(117,170,252,0.25)] text-[#9bc3ff]"; } })(); const dotColor = (() => { switch (tts.status) { case "connected": case "speaking": return "bg-[#75aafc]"; case "error": return "bg-red-400"; default: return "bg-[#3f6fb3]"; } })(); return (
{/* Text input area */}