diff --git a/src/App.tsx b/src/App.tsx index acec25d..803b84c 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -2,6 +2,7 @@ import { Routes, Route, Link } from 'react-router' import './App.css' import TemplatePage from './pages/TemplatePage/Template.tsx' import Home from './pages/Home/Home.tsx' +import Robot from './pages/Robot/Robot.tsx'; function App(){ return ( @@ -13,6 +14,7 @@ function App(){ } /> } /> + } /> diff --git a/src/pages/Home/Home.tsx b/src/pages/Home/Home.tsx index 71f6b96..cb70de0 100644 --- a/src/pages/Home/Home.tsx +++ b/src/pages/Home/Home.tsx @@ -11,6 +11,7 @@ function Home() {
+ Robot Interaction → Template →
diff --git a/src/pages/Robot/Robot.tsx b/src/pages/Robot/Robot.tsx new file mode 100644 index 0000000..0038dd9 --- /dev/null +++ b/src/pages/Robot/Robot.tsx @@ -0,0 +1,94 @@ +import { useState, useEffect, useRef } from 'react' + +export default function Robot() { + const [message, setMessage] = useState(''); + + const [listening, setListening] = useState(false); + const [conversation, setConversation] = useState<{"role": "user" | "assistant", "content": string}[]>([]) + const conversationRef = useRef(null); + const [conversationIndex, setConversationIndex] = useState(0); + + const sendMessage = async () => { + try { + const response = await fetch("http://localhost:8000/message", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ message }), + }); + const data = await response.json(); + console.log(data); + } catch (error) { + console.error("Error sending message: ", error); + } + }; + + useEffect(() => { + const eventSource = new EventSource("http://localhost:8000/sse"); + + eventSource.onmessage = (event) => { + try { + const data = JSON.parse(event.data); + if ("voice_active" in data) setListening(data.voice_active); + if ("speech" in data) setConversation(conversation => [...conversation, {"role": "user", "content": data.speech}]); + if ("llm_response" in data) setConversation(conversation => [...conversation, {"role": "assistant", "content": data.llm_response}]); + } catch { + console.log("Unparsable SSE message:", event.data); + } + }; + + return () => { + eventSource.close(); + }; + }, [conversationIndex]); + + useEffect(() => { + if (!conversationRef || !conversationRef.current) return; + conversationRef.current.scrollTop = conversationRef.current.scrollHeight; + }, [conversation]); + + return ( + <> +

Robot interaction

+

Force robot speech

+
+ setMessage(e.target.value)} + onKeyDown={(e) => e.key === "Enter" && sendMessage().then(() => setMessage(""))} + placeholder="Enter a message" + /> + +
+
+

Conversation

+

Listening {listening ? "🟢" : "🔴"}

+
+ {conversation.map((item, i) => ( +

{item["content"]}

+ ))} +
+
+ + +
+
+ + ); +}