import React, { useState, useRef, useEffect, useCallback } from 'react'; import { Search, Map, BrainCircuit, User, Bot, Globe, Send, ExternalLink, Loader } from 'lucide-react'; import { generateText } from '../services/geminiService'; import { ChatMessage, GroundingChunk } from '../types'; const GroundedSearchView: React.FC = () => { const [messages, setMessages] = useState([]); const [input, setInput] = useState(''); const [isLoading, setIsLoading] = useState(false); const [useSearch, setUseSearch] = useState(true); const [useMaps, setUseMaps] = useState(false); const [useThinking, setUseThinking] = useState(false); const messagesEndRef = useRef(null); const scrollToBottom = () => { messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }); }; useEffect(scrollToBottom, [messages]); const handleSend = useCallback(async () => { if (!input.trim()) return; const userMessage: ChatMessage = { role: 'user', parts: [{ text: input }] }; setMessages(prev => [...prev, userMessage]); setInput(''); setIsLoading(true); try { const response = await generateText(input, useSearch, useMaps, useThinking); const modelMessage: ChatMessage = { role: 'model', parts: [{ text: response.text }], groundingChunks: response.candidates?.[0]?.groundingMetadata?.groundingChunks as GroundingChunk[], }; setMessages(prev => [...prev, modelMessage]); } catch (error) { console.error('API Error:', error); const errorMessage: ChatMessage = { role: 'model', parts: [{ text: `An error occurred: ${error instanceof Error ? error.message : String(error)}` }], }; setMessages(prev => [...prev, errorMessage]); } finally { setIsLoading(false); } }, [input, useSearch, useMaps, useThinking]); const Toggle: React.FC<{ icon: React.ReactNode; label: string; enabled: boolean; onChange: (enabled: boolean) => void; }> = ({ icon, label, enabled, onChange }) => ( ); const Message: React.FC<{ message: ChatMessage }> = ({ message }) => { const isModel = message.role === 'model'; return (
{isModel && (
)}

{message.parts[0].text}

{message.groundingChunks && message.groundingChunks.length > 0 && (

Sources:

{message.groundingChunks.map((chunk, i) => { const source = chunk.web || chunk.maps; return source && ( {chunk.web ? : } {source.title} ); })}
)}
{!isModel && (
)}
); }; return (

Grounded Search & Reasoning

Get up-to-date information and handle complex queries using Gemini.

} label="Google Search" enabled={useSearch} onChange={setUseSearch} /> } label="Google Maps" enabled={useMaps} onChange={setUseMaps} /> } label="Thinking Mode" enabled={useThinking} onChange={setUseThinking} />
{messages.map((msg, index) => )} {isLoading && (
)}
setInput(e.target.value)} onKeyPress={(e) => e.key === 'Enter' && handleSend()} placeholder="Ask a complex question or for recent information..." className="flex-1 bg-slate-800 border border-slate-700 rounded-lg px-4 py-3 focus:ring-2 focus:ring-indigo-500 focus:outline-none" disabled={isLoading} />
); }; export default GroundedSearchView;