kaiiddo commited on
Commit
863f653
·
verified ·
1 Parent(s): b43de4d

Update src/App.js

Browse files
Files changed (1) hide show
  1. src/App.js +219 -17
src/App.js CHANGED
@@ -1,25 +1,227 @@
1
- import logo from './logo.svg';
2
  import './App.css';
3
 
4
  function App() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  return (
6
- <div className="App">
7
- <header className="App-header">
8
- <img src={logo} className="App-logo" alt="logo" />
9
- <p>
10
- Edit <code>src/App.js</code> and save to reload.
11
- </p>
12
- <a
13
- className="App-link"
14
- href="https://reactjs.org"
15
- target="_blank"
16
- rel="noopener noreferrer"
17
- >
18
- Learn React
19
- </a>
20
- </header>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  </div>
22
  );
23
  }
24
 
25
- export default App;
 
1
+ import React, { useState, useRef, useEffect } from 'react';
2
  import './App.css';
3
 
4
  function App() {
5
+ const [messages, setMessages] = useState([]);
6
+ const [inputValue, setInputValue] = useState('');
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 = () => {
24
+ messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
25
+ };
26
+
27
+ useEffect(() => {
28
+ scrollToBottom();
29
+ }, [messages]);
30
+
31
+ // Close dropdown when clicking outside
32
+ useEffect(() => {
33
+ const handleClickOutside = (event) => {
34
+ if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
35
+ setShowModelDropdown(false);
36
+ }
37
+ };
38
+
39
+ document.addEventListener('mousedown', handleClickOutside);
40
+ return () => document.removeEventListener('mousedown', handleClickOutside);
41
+ }, []);
42
+
43
+ // Auto-resize textarea
44
+ useEffect(() => {
45
+ if (textareaRef.current) {
46
+ textareaRef.current.style.height = '150px';
47
+ textareaRef.current.style.height = Math.min(textareaRef.current.scrollHeight, 200) + 'px';
48
+ }
49
+ }, [inputValue]);
50
+
51
+ // Toggle dark mode
52
+ useEffect(() => {
53
+ if (isDarkMode) {
54
+ document.body.classList.add('dark');
55
+ } else {
56
+ document.body.classList.remove('dark');
57
+ }
58
+ }, [isDarkMode]);
59
+
60
+ const handleSendMessage = async () => {
61
+ if (!inputValue.trim() || isLoading) return;
62
+
63
+ const userMessage = {
64
+ id: Date.now(),
65
+ content: inputValue.trim(),
66
+ role: 'user',
67
+ timestamp: new Date()
68
+ };
69
+
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) => {
88
+ if (e.key === 'Enter' && !e.shiftKey) {
89
+ e.preventDefault();
90
+ handleSendMessage();
91
+ }
92
+ };
93
+
94
+ const handleModelSelect = (modelId) => {
95
+ setSelectedModel(modelId);
96
+ setShowModelDropdown(false);
97
+ };
98
+
99
+ const currentModel = availableModels.find(model => model.id === selectedModel);
100
+
101
  return (
102
+ <div className={`App ${isDarkMode ? 'dark' : ''}`}>
103
+ <div className="chat-container">
104
+ {/* Header */}
105
+ <header className="header">
106
+ <div className="logo">
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 */}
119
+ <div className="chat-messages">
120
+ {messages.length === 0 && (
121
+ <div className="welcome-message">
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>
130
+ )}
131
+
132
+ {messages.map((message) => (
133
+ <div key={message.id} className={`message ${message.role}`}>
134
+ <div className="message-content">
135
+ {message.content}
136
+ </div>
137
+ </div>
138
+ ))}
139
+
140
+ {isLoading && (
141
+ <div className="message assistant">
142
+ <div className="typing-indicator">
143
+ <div className="typing-dot"></div>
144
+ <div className="typing-dot"></div>
145
+ <div className="typing-dot"></div>
146
+ </div>
147
+ </div>
148
+ )}
149
+
150
+ <div ref={messagesEndRef} />
151
+ </div>
152
+
153
+ {/* Input Area */}
154
+ <div className="input-container">
155
+ <div className="chat-input-wrapper">
156
+ {/* Model Selector */}
157
+ <div className="dropdown" ref={dropdownRef}>
158
+ <button
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>
186
+ )}
187
+ </div>
188
+
189
+ {/* Chat Input */}
190
+ <textarea
191
+ ref={textareaRef}
192
+ className="input chat-input"
193
+ placeholder="Message SynapseAI..."
194
+ value={inputValue}
195
+ onChange={(e) => setInputValue(e.target.value)}
196
+ onKeyPress={handleKeyPress}
197
+ disabled={isLoading}
198
+ rows={1}
199
+ />
200
+
201
+ {/* Send Button */}
202
+ <button
203
+ className="send-button"
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>
211
+ </div>
212
+
213
+ {/* Initialize Lucide Icons */}
214
+ <script
215
+ dangerouslySetInnerHTML={{
216
+ __html: `
217
+ if (window.lucide) {
218
+ window.lucide.createIcons();
219
+ }
220
+ `
221
+ }}
222
+ />
223
  </div>
224
  );
225
  }
226
 
227
+ export default App;