kaiiddo commited on
Commit
1395cc4
·
verified ·
1 Parent(s): f5bf77a

Update src/App.js

Browse files
Files changed (1) hide show
  1. src/App.js +196 -38
src/App.js CHANGED
@@ -1,4 +1,5 @@
1
  import React, { useState, useRef, useEffect } from 'react';
 
2
  import './App.css';
3
 
4
  function App() {
@@ -7,17 +8,23 @@ function App() {
7
  const [isLoading, setIsLoading] = useState(false);
8
  const [isDarkMode, setIsDarkMode] = useState(false);
9
  const [showModelDropdown, setShowModelDropdown] = useState(false);
10
- const [selectedModel, setSelectedModel] = useState('synapse-7b');
11
-
 
 
 
12
  const messagesEndRef = useRef(null);
13
  const textareaRef = useRef(null);
14
  const dropdownRef = useRef(null);
15
 
16
- const availableModels = [
17
- { id: 'synapse-7b', name: 'Synapse-7B', description: 'Fast and efficient model for general tasks' },
18
- { id: 'synapse-13b', name: 'Synapse-13B', description: 'Advanced model for complex reasoning' },
19
- { id: 'synapse-70b', name: 'Synapse-70B', description: 'Most powerful model for expert tasks' }
20
- ];
 
 
 
21
 
22
  // Scroll to bottom of messages
23
  const scrollToBottom = () => {
@@ -57,8 +64,32 @@ function App() {
57
  }
58
  }, [isDarkMode]);
59
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  const handleSendMessage = async () => {
61
- if (!inputValue.trim() || isLoading) return;
62
 
63
  const userMessage = {
64
  id: Date.now(),
@@ -70,18 +101,45 @@ function App() {
70
  setMessages(prev => [...prev, userMessage]);
71
  setInputValue('');
72
  setIsLoading(true);
 
73
 
74
- // Simulate AI response
75
- setTimeout(() => {
 
 
 
 
76
  const aiMessage = {
77
  id: Date.now() + 1,
78
- content: `This is a simulated response from ${selectedModel}. In a real implementation, this would connect to your Hugging Face model endpoint.`,
79
  role: 'assistant',
80
  timestamp: new Date()
81
  };
82
  setMessages(prev => [...prev, aiMessage]);
 
 
 
 
83
  setIsLoading(false);
84
- }, 2000);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
  };
86
 
87
  const handleKeyPress = (e) => {
@@ -96,7 +154,76 @@ function App() {
96
  setShowModelDropdown(false);
97
  };
98
 
99
- const currentModel = availableModels.find(model => model.id === selectedModel);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
 
101
  return (
102
  <div className={`App ${isDarkMode ? 'dark' : ''}`}>
@@ -107,12 +234,23 @@ function App() {
107
  <i data-lucide="brain" width="28" height="28"></i>
108
  <span>SynapseAI</span>
109
  </div>
110
- <button
111
- className="btn ghost theme-toggle"
112
- onClick={() => setIsDarkMode(!isDarkMode)}
113
- >
114
- <i data-lucide={isDarkMode ? "sun" : "moon"} width="20" height="20"></i>
115
- </button>
 
 
 
 
 
 
 
 
 
 
 
116
  </header>
117
 
118
  {/* Chat Messages */}
@@ -122,8 +260,11 @@ function App() {
122
  <div className="card" style={{ maxWidth: '600px', margin: '0 auto' }}>
123
  <i data-lucide="sparkles" width="48" height="48" style={{ marginBottom: '16px', color: '#71717a' }}></i>
124
  <h2 style={{ marginBottom: '8px', fontSize: '24px', fontWeight: '600' }}>Welcome to SynapseAI</h2>
125
- <p style={{ color: '#71717a', lineHeight: '1.5' }}>
126
- Start a conversation with our AI assistant. Choose your preferred model and begin chatting!
 
 
 
127
  </p>
128
  </div>
129
  </div>
@@ -150,6 +291,14 @@ function App() {
150
  <div ref={messagesEndRef} />
151
  </div>
152
 
 
 
 
 
 
 
 
 
153
  {/* Input Area */}
154
  <div className="input-container">
155
  <div className="chat-input-wrapper">
@@ -159,27 +308,36 @@ function App() {
159
  className="btn model-selector"
160
  onClick={() => setShowModelDropdown(!showModelDropdown)}
161
  >
162
- <i data-lucide="cpu" width="16" height="16"></i>
163
- <span style={{ marginLeft: '8px' }}>{currentModel.name}</span>
164
- <i data-lucide="chevron-down" width="16" height="16" style={{ marginLeft: '4px' }}></i>
165
  </button>
166
 
167
  {showModelDropdown && (
168
  <div className="dropdown-content">
169
- {availableModels.map((model) => (
170
- <div
171
- key={model.id}
172
- className={`dropdown-item ${selectedModel === model.id ? 'active' : ''}`}
173
- onClick={() => handleModelSelect(model.id)}
174
- >
175
- <i data-lucide="cpu" width="16" height="16"></i>
176
- <div style={{ flex: 1 }}>
177
- <div style={{ fontWeight: '500' }}>{model.name}</div>
178
- <div style={{ fontSize: '12px', opacity: '0.7' }}>{model.description}</div>
179
  </div>
180
- {selectedModel === model.id && (
181
- <i data-lucide="check" width="16" height="16"></i>
182
- )}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
183
  </div>
184
  ))}
185
  </div>
@@ -204,7 +362,7 @@ function App() {
204
  onClick={handleSendMessage}
205
  disabled={!inputValue.trim() || isLoading}
206
  >
207
- <i data-lucide="send" width="20" height="20"></i>
208
  </button>
209
  </div>
210
  </div>
 
1
  import React, { useState, useRef, useEffect } from 'react';
2
+ import { modelCompanies, allModels, findModelById } from './models/modelConfig';
3
  import './App.css';
4
 
5
  function App() {
 
8
  const [isLoading, setIsLoading] = useState(false);
9
  const [isDarkMode, setIsDarkMode] = useState(false);
10
  const [showModelDropdown, setShowModelDropdown] = useState(false);
11
+ const [selectedModel, setSelectedModel] = useState('deepseek-v3.2-exp');
12
+ const [hfToken, setHfToken] = useState('');
13
+ const [showAuth, setShowAuth] = useState(true);
14
+ const [error, setError] = useState('');
15
+
16
  const messagesEndRef = useRef(null);
17
  const textareaRef = useRef(null);
18
  const dropdownRef = useRef(null);
19
 
20
+ // Check for stored token on component mount
21
+ useEffect(() => {
22
+ const storedToken = localStorage.getItem('hf_token');
23
+ if (storedToken) {
24
+ setHfToken(storedToken);
25
+ setShowAuth(false);
26
+ }
27
+ }, []);
28
 
29
  // Scroll to bottom of messages
30
  const scrollToBottom = () => {
 
64
  }
65
  }, [isDarkMode]);
66
 
67
+ const handleTokenSubmit = () => {
68
+ if (!hfToken.trim()) {
69
+ setError('Please enter your Hugging Face token');
70
+ return;
71
+ }
72
+
73
+ // Basic token validation (HF tokens typically start with "hf_")
74
+ if (!hfToken.startsWith('hf_')) {
75
+ setError('Please enter a valid Hugging Face token');
76
+ return;
77
+ }
78
+
79
+ localStorage.setItem('hf_token', hfToken.trim());
80
+ setShowAuth(false);
81
+ setError('');
82
+ };
83
+
84
+ const handleClearToken = () => {
85
+ localStorage.removeItem('hf_token');
86
+ setHfToken('');
87
+ setShowAuth(true);
88
+ setMessages([]);
89
+ };
90
+
91
  const handleSendMessage = async () => {
92
+ if (!inputValue.trim() || isLoading || !hfToken) return;
93
 
94
  const userMessage = {
95
  id: Date.now(),
 
101
  setMessages(prev => [...prev, userMessage]);
102
  setInputValue('');
103
  setIsLoading(true);
104
+ setError('');
105
 
106
+ try {
107
+ const currentModelConfig = findModelById(selectedModel);
108
+
109
+ // Simulate API call - Replace this with actual Hugging Face Inference API call
110
+ const response = await simulateHuggingFaceCall(inputValue.trim(), currentModelConfig, hfToken);
111
+
112
  const aiMessage = {
113
  id: Date.now() + 1,
114
+ content: response,
115
  role: 'assistant',
116
  timestamp: new Date()
117
  };
118
  setMessages(prev => [...prev, aiMessage]);
119
+ } catch (err) {
120
+ setError('Failed to get response from AI model. Please check your token and try again.');
121
+ console.error('API Error:', err);
122
+ } finally {
123
  setIsLoading(false);
124
+ }
125
+ };
126
+
127
+ // Simulate Hugging Face API call - Replace with actual implementation
128
+ const simulateHuggingFaceCall = async (message, modelConfig, token) => {
129
+ // This is a simulation - replace with actual Hugging Face Inference API
130
+ return new Promise((resolve) => {
131
+ setTimeout(() => {
132
+ resolve(`This is a simulated response from ${modelConfig.name} (${modelConfig.company}).
133
+
134
+ In a real implementation, this would connect to the Hugging Face Inference API using:
135
+
136
+ Model: ${modelConfig.endpoint}
137
+ Provider: ${modelConfig.provider}
138
+ Token: ${token.substring(0, 10)}...
139
+
140
+ Your message: "${message}"`);
141
+ }, 2000);
142
+ });
143
  };
144
 
145
  const handleKeyPress = (e) => {
 
154
  setShowModelDropdown(false);
155
  };
156
 
157
+ const currentModel = findModelById(selectedModel);
158
+
159
+ // Group models by company for dropdown
160
+ const groupedModels = modelCompanies;
161
+
162
+ if (showAuth) {
163
+ return (
164
+ <div className={`App ${isDarkMode ? 'dark' : ''}`}>
165
+ <div className="auth-modal">
166
+ <div className="auth-content">
167
+ <div className="logo" style={{ justifyContent: 'center', marginBottom: '24px' }}>
168
+ <i data-lucide="brain" width="32" height="32"></i>
169
+ <span style={{ fontSize: '28px' }}>SynapseAI</span>
170
+ </div>
171
+
172
+ <h2 className="auth-title">Welcome to SynapseAI</h2>
173
+ <p className="auth-description">
174
+ Enter your Hugging Face token to start chatting with AI models
175
+ </p>
176
+
177
+ {error && (
178
+ <div className="error-message">
179
+ <i data-lucide="alert-circle" width="16" height="16" style={{ marginRight: '8px' }}></i>
180
+ {error}
181
+ </div>
182
+ )}
183
+
184
+ <div className="auth-input">
185
+ <input
186
+ type="password"
187
+ className="input"
188
+ placeholder="Enter your Hugging Face token (hf_...)"
189
+ value={hfToken}
190
+ onChange={(e) => setHfToken(e.target.value)}
191
+ onKeyPress={(e) => e.key === 'Enter' && handleTokenSubmit()}
192
+ />
193
+ </div>
194
+
195
+ <div className="auth-actions">
196
+ <button className="btn primary" onClick={handleTokenSubmit}>
197
+ <i data-lucide="key" width="16" height="16"></i>
198
+ Start Chatting
199
+ </button>
200
+ </div>
201
+
202
+ <div className="token-info">
203
+ <h4>How to get your Hugging Face token:</h4>
204
+ <ol>
205
+ <li>Go to <a href="https://huggingface.co" target="_blank" rel="noopener noreferrer">huggingface.co</a></li>
206
+ <li>Sign in to your account</li>
207
+ <li>Go to Settings → Access Tokens</li>
208
+ <li>Create a new token with read permissions</li>
209
+ <li>Copy and paste it here</li>
210
+ </ol>
211
+ </div>
212
+ </div>
213
+ </div>
214
+
215
+ <script
216
+ dangerouslySetInnerHTML={{
217
+ __html: `
218
+ if (window.lucide) {
219
+ window.lucide.createIcons();
220
+ }
221
+ `
222
+ }}
223
+ />
224
+ </div>
225
+ );
226
+ }
227
 
228
  return (
229
  <div className={`App ${isDarkMode ? 'dark' : ''}`}>
 
234
  <i data-lucide="brain" width="28" height="28"></i>
235
  <span>SynapseAI</span>
236
  </div>
237
+
238
+ <div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>
239
+ <div className="token-display">
240
+ <i data-lucide="key" width="14" height="14"></i>
241
+ <span className="token-text">Token: {hfToken.substring(0, 10)}...</span>
242
+ <div className="clear-token" onClick={handleClearToken} title="Clear token">
243
+ <i data-lucide="x" width="14" height="14"></i>
244
+ </div>
245
+ </div>
246
+
247
+ <button
248
+ className="btn ghost theme-toggle"
249
+ onClick={() => setIsDarkMode(!isDarkMode)}
250
+ >
251
+ <i data-lucide={isDarkMode ? "sun" : "moon"} width="20" height="20"></i>
252
+ </button>
253
+ </div>
254
  </header>
255
 
256
  {/* Chat Messages */}
 
260
  <div className="card" style={{ maxWidth: '600px', margin: '0 auto' }}>
261
  <i data-lucide="sparkles" width="48" height="48" style={{ marginBottom: '16px', color: '#71717a' }}></i>
262
  <h2 style={{ marginBottom: '8px', fontSize: '24px', fontWeight: '600' }}>Welcome to SynapseAI</h2>
263
+ <p style={{ color: '#71717a', lineHeight: '1.5', marginBottom: '16px' }}>
264
+ Start a conversation with our AI models. Select your preferred model from the dropdown below.
265
+ </p>
266
+ <p style={{ fontSize: '14px', color: '#a1a1aa' }}>
267
+ Current Model: <strong>{currentModel?.name}</strong> by {currentModel?.company}
268
  </p>
269
  </div>
270
  </div>
 
291
  <div ref={messagesEndRef} />
292
  </div>
293
 
294
+ {/* Error Display */}
295
+ {error && (
296
+ <div className="error-message">
297
+ <i data-lucide="alert-circle" width="16" height="16" style={{ marginRight: '8px' }}></i>
298
+ {error}
299
+ </div>
300
+ )}
301
+
302
  {/* Input Area */}
303
  <div className="input-container">
304
  <div className="chat-input-wrapper">
 
308
  className="btn model-selector"
309
  onClick={() => setShowModelDropdown(!showModelDropdown)}
310
  >
311
+ <i data-lucide={currentModel?.companyLogo || "cpu"} width="16" height="16"></i>
312
+ <span style={{ flex: 1, textAlign: 'left' }}>{currentModel?.name}</span>
313
+ <i data-lucide="chevron-down" width="16" height="16"></i>
314
  </button>
315
 
316
  {showModelDropdown && (
317
  <div className="dropdown-content">
318
+ {groupedModels.map((company) => (
319
+ <div key={company.id} className="company-section">
320
+ <div className="company-header">
321
+ <i data-lucide={company.logo} width="16" height="16"></i>
322
+ {company.name}
 
 
 
 
 
323
  </div>
324
+ {company.models.map((model) => (
325
+ <div
326
+ key={model.id}
327
+ className={`dropdown-item ${selectedModel === model.id ? 'active' : ''}`}
328
+ onClick={() => handleModelSelect(model.id)}
329
+ >
330
+ <div className="model-info">
331
+ <div className="model-name">{model.name}</div>
332
+ <div className="model-description">{model.description}</div>
333
+ </div>
334
+ <div className="model-check">
335
+ {selectedModel === model.id && (
336
+ <i data-lucide="check" width="16" height="16"></i>
337
+ )}
338
+ </div>
339
+ </div>
340
+ ))}
341
  </div>
342
  ))}
343
  </div>
 
362
  onClick={handleSendMessage}
363
  disabled={!inputValue.trim() || isLoading}
364
  >
365
+ <i data-lucide="send" width="18" height="18"></i>
366
  </button>
367
  </div>
368
  </div>