import { useState, useRef, useEffect } from "react"; import { PanelRightClose, PanelRightOpen, MessageSquarePlus, } from "lucide-react"; import { motion } from "framer-motion"; // import { ThemeToggle } from "./ThemeToggle"; import { ChatMessage } from "./ChatMessage"; import { ChatInput } from "./ChatInput"; import { Sidebar } from "./Sidebar"; import type { Chat, Message } from "./types"; import { useTheme } from "../ThemeProvider"; import { Footer } from "../SearchChat/Footer"; import { tauriFetch } from "../../api/tauriFetchClient"; import { useWebSocket } from "../../hooks/useWebSocket"; interface ChatAIProps { changeMode: (isChatMode: boolean) => void; } export default function ChatAI({ changeMode }: ChatAIProps) { const [chats, setChats] = useState([]); const [activeChat, setActiveChat] = useState(); const [isSidebarOpen, setIsSidebarOpen] = useState(false); const [isTyping, setIsTyping] = useState(false); const messagesEndRef = useRef(null); const { theme } = useTheme(); const [websocketId, setWebsocketId] = useState(""); const [curMessage, setCurMessage] = useState(""); const [curChatEnd, setCurChatEnd] = useState(true); const { messages, setMessages } = useWebSocket( "ws://localhost:2900/ws", (msg) => { if (msg.includes("websocket_session_id")) { const array = msg.split(" "); setWebsocketId(array[2]); } if (msg.includes("PRIVATE")) { if (msg.includes("assistant finished output")) { setCurChatEnd(true); } else { const cleanedData = msg.replace(/^PRIVATE /, ""); try { const chunkData = JSON.parse(cleanedData); setCurMessage((prev) => prev + chunkData.message_chunk); return chunkData.message_chunk; } catch (error) { console.error("JSON Parse error:", error); } return ""; } } return ""; } ); // websocket useEffect(() => { if (messages.length === 0 || !activeChat?._id) return; const simulateAssistantResponse = () => { console.log("messages", messages); const assistantMessage: Message = { _id: activeChat._id, _source: { type: "assistant", message: messages, }, }; const updatedChat = { ...activeChat, messages: [...(activeChat.messages || []), assistantMessage], }; setMessages(""); setCurMessage(""); setActiveChat(updatedChat); setTimeout(() => setIsTyping(false), 1000); }; if (curChatEnd) { simulateAssistantResponse(); } }, [messages, isTyping, curChatEnd]); // getChatHistory useEffect(() => { getChatHistory(); }, []); const getChatHistory = async () => { try { const response = await tauriFetch({ url: "/chat/_history", method: "GET", }); console.log("_history", response); const hits = response.data?.hits?.hits || []; setChats(hits); if (hits[0]) { onSelectChat(hits[0]); } else { createNewChat(); } } catch (error) { console.error("Failed to fetch user data:", error); } }; const scrollToBottom = () => { messagesEndRef.current?.scrollIntoView({ behavior: "smooth", block: "end", }); }; useEffect(() => { scrollToBottom(); }, [activeChat?.messages, isTyping, curMessage]); const createNewChat = async () => { try { const response = await tauriFetch({ url: "/chat/_new", method: "POST", }); console.log("_new", response); const newChat: Chat = response.data; setChats((prev) => [newChat, ...prev]); setActiveChat(newChat); setIsSidebarOpen(false); } catch (error) { console.error("Failed to fetch user data:", error); } }; const deleteChat = (chatId: string) => { setChats((prev) => prev.filter((chat) => chat._id !== chatId)); if (activeChat?._id === chatId) { const remainingChats = chats.filter((chat) => chat._id !== chatId); if (remainingChats.length > 0) { setActiveChat(remainingChats[0]); } else { createNewChat(); } } }; const handleSendMessage = async (content: string) => { if (!activeChat?._id) return; try { const response = await tauriFetch({ url: `/chat/${activeChat?._id}/_send`, method: "POST", headers: { WEBSOCKET_SESSION_ID: websocketId, }, body: JSON.stringify({ message: content }), }); console.log("_send", response, websocketId); const updatedChat: Chat = { ...activeChat, messages: [...(activeChat?.messages || []), ...(response.data || [])], }; setActiveChat(updatedChat); setIsTyping(true); setCurChatEnd(false); } catch (error) { console.error("Failed to fetch user data:", error); } }; const chatHistory = async (chat: Chat) => { try { const response = await tauriFetch({ url: `/chat/${chat._id}/_history`, method: "GET", }); console.log("id_history", response); const hits = response.data?.hits?.hits || []; const updatedChat: Chat = { ...chat, messages: hits, }; setActiveChat(updatedChat); } catch (error) { console.error("Failed to fetch user data:", error); } }; const chatClose = async () => { if (!activeChat?._id) return; try { const response = await tauriFetch({ url: `/chat/${activeChat._id}/_close`, method: "POST", }); console.log("_close", response); } catch (error) { console.error("Failed to fetch user data:", error); } }; const onSelectChat = async (chat: any) => { chatClose(); try { const response = await tauriFetch({ url: `/chat/${chat._id}/_open`, method: "POST", }); console.log("_open", response); chatHistory(response.data); setIsSidebarOpen(false); } catch (error) { console.error("Failed to fetch user data:", error); } }; return (
{/* Sidebar */} {isSidebarOpen ? (
{activeChat ? ( ) : null}
) : null} {/* Main content */}
{/* */}
{/* Chat messages */} {activeChat?.messages?.map((message, index) => ( ))} {!curChatEnd && activeChat?._id ? ( ) : null} {/* Loading */} {isTyping && (
)}
{/* Input area */}