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"]}

+ ))} +
+
+ + +
+
+ + ); +} diff --git a/src/pages/ServerComms/ServerComms.css b/src/pages/ServerComms/ServerComms.css deleted file mode 100644 index e69de29..0000000 diff --git a/src/pages/ServerComms/ServerComms.tsx b/src/pages/ServerComms/ServerComms.tsx deleted file mode 100644 index c16ec81..0000000 --- a/src/pages/ServerComms/ServerComms.tsx +++ /dev/null @@ -1,80 +0,0 @@ -import { useState, useEffect } from 'react' -import { Link } from 'react-router' -//import Counter from '../../components/components.tsx' - - -//this is your css file where you can style your buttons and such -//you can still use css parts from App.css, but also overwrite them - -function ServerComms() { - const [message, setMessage] = useState(''); - const [sseMessage, setSseMessage] = useState(''); - const [spoken, setSpoken] = useState(""); - - 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) => { - setSseMessage(event.data); - - try { - const data = JSON.parse(event.data); - if (data.speech) setSpoken(data.speech); - } catch {} - }; - - return () => { - eventSource.close(); - }; - }, []); - - return ( -
-
- setMessage(e.target.value)} - onKeyDown={(e) => e.key === "Enter" && sendMessage().then(() => setMessage(""))} - placeholder="Enter a message" - /> - -
-
-

Message from Server (SSE):

-

{sseMessage}

-
-
-

Spoken text (SSE):

-

{spoken}

-
-
- {/* here you link to the homepage, in App.tsx you can link new pages */} - - -
-
- - - ); -} - -export default ServerComms \ No newline at end of file