import React, { useState, useRef, useEffect } from 'react'; import { modelCompanies, allModels, findModelById } from './models/modelConfig'; import { HuggingFaceService } from './services/huggingfaceService'; import './App.css'; // Import Lucide icons import { createIcons, Brain, Key, Sun, Moon, X, ChevronDown, Cpu, BrainCircuit, Atom, Check, Send, AlertCircle, Sparkles } from 'lucide-react'; function App() { const [messages, setMessages] = useState([]); const [inputValue, setInputValue] = useState(''); const [isLoading, setIsLoading] = useState(false); const [isDarkMode, setIsDarkMode] = useState(false); const [showModelDropdown, setShowModelDropdown] = useState(false); const [selectedModel, setSelectedModel] = useState('deepseek-v3.2-exp'); const [hfToken, setHfToken] = useState(''); const [showAuth, setShowAuth] = useState(true); const [error, setError] = useState(''); const messagesEndRef = useRef(null); const textareaRef = useRef(null); const dropdownRef = useRef(null); const currentMessageRef = useRef(null); // Initialize Lucide icons useEffect(() => { createIcons({ icons: { Brain, Key, Sun, Moon, X, ChevronDown, Cpu, BrainCircuit, Atom, Check, Send, AlertCircle, Sparkles } }); }, []); // Check for stored token useEffect(() => { const storedToken = localStorage.getItem('hf_token'); if (storedToken) { setHfToken(storedToken); setShowAuth(false); } }, []); // Scroll to bottom useEffect(() => { scrollToBottom(); }, [messages]); // Close dropdown when clicking outside useEffect(() => { const handleClickOutside = (event) => { if (dropdownRef.current && !dropdownRef.current.contains(event.target)) { setShowModelDropdown(false); } }; document.addEventListener('mousedown', handleClickOutside); return () => document.removeEventListener('mousedown', handleClickOutside); }, []); // Auto-resize textarea useEffect(() => { if (textareaRef.current) { textareaRef.current.style.height = 'auto'; textareaRef.current.style.height = Math.min(textareaRef.current.scrollHeight, 200) + 'px'; } }, [inputValue]); // Toggle dark mode useEffect(() => { if (isDarkMode) { document.body.classList.add('dark'); } else { document.body.classList.remove('dark'); } }, [isDarkMode]); const scrollToBottom = () => { messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }); }; const handleTokenSubmit = () => { if (!hfToken.trim()) { setError('Please enter your Hugging Face token'); return; } if (!hfToken.startsWith('hf_')) { setError('Please enter a valid Hugging Face token'); return; } localStorage.setItem('hf_token', hfToken.trim()); setShowAuth(false); setError(''); }; const handleClearToken = () => { localStorage.removeItem('hf_token'); setHfToken(''); setShowAuth(true); setMessages([]); }; const handleSendMessage = async () => { if (!inputValue.trim() || isLoading || !hfToken) return; const userMessage = { id: Date.now(), content: inputValue.trim(), role: 'user', timestamp: new Date() }; setMessages(prev => [...prev, userMessage]); setInputValue(''); setIsLoading(true); setError(''); // Create assistant message for streaming const assistantMessageId = Date.now() + 1; const assistantMessage = { id: assistantMessageId, content: '', role: 'assistant', timestamp: new Date() }; setMessages(prev => [...prev, assistantMessage]); currentMessageRef.current = assistantMessageId; try { const currentModelConfig = findModelById(selectedModel); const hfService = new HuggingFaceService(hfToken); const chatMessages = [ ...messages.filter(msg => msg.role !== 'assistant' || msg.content), userMessage ].map(msg => ({ role: msg.role, content: msg.content })); await hfService.streamChatCompletion( chatMessages, currentModelConfig, (chunk) => { setMessages(prev => prev.map(msg => msg.id === assistantMessageId ? { ...msg, content: msg.content + (chunk || '') } : msg )); }, () => { setIsLoading(false); currentMessageRef.current = null; }, (errorMsg) => { setError(`Model error: ${errorMsg}`); setIsLoading(false); currentMessageRef.current = null; setMessages(prev => prev.filter(msg => msg.id !== assistantMessageId)); } ); } catch (err) { console.error('Chat error:', err); setError(`Failed to connect to AI model: ${err.message}`); setIsLoading(false); currentMessageRef.current = null; setMessages(prev => prev.filter(msg => msg.id !== assistantMessageId)); } }; const handleKeyPress = (e) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); handleSendMessage(); } }; const handleModelSelect = (modelId) => { setSelectedModel(modelId); setShowModelDropdown(false); }; const currentModel = findModelById(selectedModel); const groupedModels = modelCompanies; // Auth Modal if (showAuth) { return (
SynapseAI

Welcome to SynapseAI

Enter your Hugging Face token to start chatting with AI models

{error && (
{error}
)}
setHfToken(e.target.value)} onKeyPress={(e) => e.key === 'Enter' && handleTokenSubmit()} />

How to get your Hugging Face token:

  1. Go to huggingface.co
  2. Sign in to your account
  3. Go to Settings → Access Tokens
  4. Create a new token with read permissions
  5. Copy and paste it here
); } return (
{/* Header */}
SynapseAI
Token: {hfToken.substring(0, 10)}...
{/* Chat Messages */}
{messages.length === 0 && (

Welcome to SynapseAI

Start a conversation with AI models. Select your preferred model below.

Current Model: {currentModel?.name} by {currentModel?.company}

)} {messages.map((message) => (
{message.content || (message.role === 'assistant' && isLoading && '...')}
))} {isLoading && !currentMessageRef.current && (
)}
{/* Error Display */} {error && (
{error}
)} {/* Input Area */}
{/* Model Selector */}
{showModelDropdown && (
{groupedModels.map((company) => (
{company.name}
{company.models.map((model) => (
handleModelSelect(model.id)} >
{model.name}
{model.description}
{selectedModel === model.id && }
))}
))}
)}
{/* Chat Input */}