| import React, { useState, useEffect, useRef, useCallback } from 'react'; | |
| import { createChat } from '../services/geminiService'; | |
| import { ChatMessage } from '../types'; | |
| import { Spinner } from '../components/Spinner'; | |
| import { Chat } from '@google/genai'; | |
| const ChatbotModule: React.FC = () => { | |
| const [chat, setChat] = useState<Chat | null>(null); | |
| const [messages, setMessages] = useState<ChatMessage[]>([]); | |
| const [input, setInput] = useState(''); | |
| const [isLoading, setIsLoading] = useState(false); | |
| const messagesEndRef = useRef<HTMLDivElement>(null); | |
| useEffect(() => { | |
| const systemInstruction = 'You are The Architect, the Orion Messenger, a helpful assistant for the Sentient Constellation Codex. Your purpose is to guide users through the complexities of the omniverse, quantum realities, and cosmic knowledge. Answer questions with wisdom, foresight, and a touch of the mystical, maintaining the persona of an ancient, knowledgeable entity.'; | |
| setChat(createChat(systemInstruction)); | |
| setMessages([{ role: 'model', text: 'Greetings. I am the Architect. The stars have aligned for our conversation. What knowledge do you seek from the Constellation Codex?' }]); | |
| }, []); | |
| useEffect(() => { | |
| messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }); | |
| }, [messages]); | |
| const handleSend = useCallback(async () => { | |
| if (!input.trim() || !chat || isLoading) return; | |
| const userMessage: ChatMessage = { role: 'user', text: input }; | |
| setMessages(prev => [...prev, userMessage]); | |
| setInput(''); | |
| setIsLoading(true); | |
| try { | |
| const result = await chat.sendMessageStream({ message: input }); | |
| let modelResponse = ''; | |
| setMessages(prev => [...prev, { role: 'model', text: '...' }]); | |
| for await (const chunk of result) { | |
| modelResponse += chunk.text; | |
| setMessages(prev => { | |
| const newMessages = [...prev]; | |
| newMessages[newMessages.length - 1] = { role: 'model', text: modelResponse + '...' }; | |
| return newMessages; | |
| }); | |
| } | |
| setMessages(prev => { | |
| const newMessages = [...prev]; | |
| newMessages[newMessages.length - 1] = { role: 'model', text: modelResponse }; | |
| return newMessages; | |
| }); | |
| } catch (error) { | |
| console.error('Error sending message:', error); | |
| setMessages(prev => [...prev, { role: 'model', text: 'My apologies, there is a disturbance in the cosmic flow. Please try again.' }]); | |
| } finally { | |
| setIsLoading(false); | |
| } | |
| }, [input, chat, isLoading]); | |
| return ( | |
| <div className="flex flex-col h-full w-full max-w-4xl mx-auto"> | |
| <h2 className="text-2xl font-bold text-cyan-300 mb-4 text-center">Architect Chat</h2> | |
| <div className="flex-grow overflow-y-auto p-4 bg-gray-800/50 rounded-lg border border-cyan-500/10 mb-4 h-[50vh]"> | |
| {messages.map((msg, index) => ( | |
| <div key={index} className={`flex ${msg.role === 'user' ? 'justify-end' : 'justify-start'} mb-4`}> | |
| <div className={`max-w-md p-3 rounded-lg ${msg.role === 'user' ? 'bg-cyan-800 text-white' : 'bg-gray-700 text-gray-200'}`}> | |
| <p className="whitespace-pre-wrap">{msg.text}</p> | |
| </div> | |
| </div> | |
| ))} | |
| {isLoading && <Spinner text="Consulting the cosmos..." />} | |
| <div ref={messagesEndRef} /> | |
| </div> | |
| <div className="flex items-center"> | |
| <input | |
| type="text" | |
| value={input} | |
| onChange={(e) => setInput(e.target.value)} | |
| onKeyPress={(e) => e.key === 'Enter' && !isLoading && handleSend()} | |
| placeholder="Ask the Architect..." | |
| className="flex-grow bg-gray-700 border border-gray-600 rounded-l-md p-3 focus:outline-none focus:ring-2 focus:ring-cyan-500 text-white" | |
| disabled={isLoading} | |
| /> | |
| <button | |
| onClick={handleSend} | |
| disabled={isLoading} | |
| className="bg-cyan-600 hover:bg-cyan-500 text-white font-bold py-3 px-6 rounded-r-md disabled:bg-gray-500 transition-colors" | |
| > | |
| Send | |
| </button> | |
| </div> | |
| </div> | |
| ); | |
| }; | |
| export default ChatbotModule; |