Download frontend/components/ChatWindow.jsx from ruslanmv/HomePilot: direct link, hf CLI and curl.
- Browser
- Download file 4.13 kB
-
https://huggingface.co/spaces/ruslanmv/HomePilot/resolve/main/frontend/components/ChatWindow.jsx
- Command line
-
hf download hf://spaces/ruslanmv/HomePilot/frontend/components/ChatWindow.jsx
-
curl -L -o ChatWindow.jsx https://huggingface.co/spaces/ruslanmv/HomePilot/resolve/main/frontend/components/ChatWindow.jsx
4.13 kB
| "use client"; | |
| import { useEffect, useRef, useState } from "react"; | |
| import MessageList from "./MessageList"; | |
| import Composer from "./Composer"; | |
| function ExpertActivity({ stage }) { | |
| if (stage === "idle") | |
| return null; | |
| const isParsing = stage === "parsing"; | |
| return (<div style={{ | |
| background: "#080808", | |
| borderRadius: 16, | |
| padding: "16px 18px", | |
| marginBottom: 14, | |
| border: "1px solid rgba(60,60,70,0.35)", | |
| color: "#ddd", | |
| }}> | |
| <style>{` | |
| @keyframes hpDotBounce { | |
| 0%, 80%, 100% { transform: translateY(0); opacity: 0.7; } | |
| 40% { transform: translateY(-6px); opacity: 1; } | |
| } | |
| @keyframes hpGrokPulse { | |
| 0% { background: #222; transform: scale(1); opacity: .75; box-shadow: 0 0 2px rgba(255,255,255,.1); } | |
| 8% { background: #fff; transform: scale(1.55); opacity: 1; box-shadow: 0 0 8px rgba(255,255,255,.9), 0 0 14px rgba(180,220,255,.6); } | |
| 18% { background: #aaa; transform: scale(1.15); opacity: .9; box-shadow: 0 0 4px rgba(255,255,255,.4); } | |
| 28%, 100% { background: #222; transform: scale(1); opacity: .75; box-shadow: 0 0 2px rgba(255,255,255,.08); } | |
| } | |
| `}</style> | |
| <div style={{ display: "flex", alignItems: "center", gap: 14, marginBottom: 10 }}> | |
| {isParsing ? (<div style={{ display: "grid", gridTemplateColumns: "repeat(3, 5px)", gridTemplateRows: "repeat(3, 5px)", gap: 7 }}> | |
| {Array.from({ length: 9 }).map((_, i) => (<span key={i} style={{ | |
| width: 5, | |
| height: 5, | |
| borderRadius: "50%", | |
| animation: "hpGrokPulse 2.4s infinite ease-in-out", | |
| animationDelay: `${i * 0.2}s`, | |
| }}/>))} | |
| </div>) : (<div style={{ display: "flex", alignItems: "center", gap: 5 }}> | |
| {[0, 1, 2].map((i) => (<span key={i} style={{ | |
| width: 6, | |
| height: 6, | |
| borderRadius: "50%", | |
| background: "#888", | |
| animation: "hpDotBounce 1.3s infinite ease-in-out", | |
| animationDelay: `${i * 0.15}s`, | |
| }}/>))} | |
| </div>)} | |
| <div style={{ color: "#7aaae0", fontSize: 15 }}> | |
| {isParsing ? "Parsing question · sending to backend" : "Thinking"} | |
| </div> | |
| </div> | |
| <div style={{ color: "#8e8e9a", fontSize: 13 }}> | |
| {isParsing | |
| ? "Analyzing query structure and preparing tool context." | |
| : "Processing reasoning step-by-step."} | |
| </div> | |
| </div>); | |
| } | |
| export default function ChatWindow() { | |
| const [messages, setMessages] = useState([]); | |
| const [stage, setStage] = useState("idle"); | |
| const parseTimer = useRef(null); | |
| useEffect(() => { | |
| return () => { | |
| if (parseTimer.current) | |
| clearTimeout(parseTimer.current); | |
| }; | |
| }, []); | |
| async function sendMessage(text) { | |
| setStage("parsing"); | |
| parseTimer.current = setTimeout(() => setStage("thinking"), 1200); | |
| try { | |
| const resp = await fetch("http://localhost:8000/api/chat", { | |
| method: "POST", | |
| headers: { "Content-Type": "application/json" }, | |
| body: JSON.stringify({ session_id: "default", message: text }), | |
| }); | |
| const data = await resp.json(); | |
| if (parseTimer.current) | |
| clearTimeout(parseTimer.current); | |
| setStage("thinking"); | |
| setMessages((prev) => [...prev, `User: ${text}`, `Expert: ${data.answer}`]); | |
| } | |
| catch (err) { | |
| if (parseTimer.current) | |
| clearTimeout(parseTimer.current); | |
| setMessages((prev) => [...prev, `User: ${text}`, `Expert: Failed to get response: ${String(err)}`]); | |
| } | |
| finally { | |
| setStage("idle"); | |
| } | |
| } | |
| return (<div style={{ padding: 24 }}> | |
| <MessageList messages={messages}/> | |
| <ExpertActivity stage={stage}/> | |
| <Composer onSend={sendMessage}/> | |
| </div>); | |
| } | |