Mehdi commited on
Commit
5266d92
·
verified ·
1 Parent(s): 9e5629a

Upload components/ModelSelector.jsx with huggingface_hub

Browse files
Files changed (1) hide show
  1. components/ModelSelector.jsx +270 -0
components/ModelSelector.jsx ADDED
@@ -0,0 +1,270 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { useState, useEffect } from 'react'
2
+ import { FiDownload, FiTrash2, FiInfo, FiSearch, FiFilter } from 'react-icons/fi'
3
+ import axios from 'axios'
4
+
5
+ export default function ModelSelector() {
6
+ const [models, setModels] = useState([])
7
+ const [selectedModel, setSelectedModel] = useState(null)
8
+ const [isLoading, setIsLoading] = useState(false)
9
+ const [downloadedModels, setDownloadedModels] = useState([])
10
+ const [searchTerm, setSearchTerm] = useState('')
11
+ const [filterType, setFilterType] = useState('all')
12
+ const [showDetails, setShowDetails] = useState(false)
13
+
14
+ useEffect(() => {
15
+ fetchModels()
16
+ const saved = localStorage.getItem('downloadedModels')
17
+ if (saved) {
18
+ setDownloadedModels(JSON.parse(saved))
19
+ }
20
+ }, [])
21
+
22
+ const fetchModels = async () => {
23
+ try {
24
+ setIsLoading(true)
25
+ const response = await axios.get('/api/models')
26
+ setModels(response.data)
27
+ } catch (error) {
28
+ console.error('Error fetching models:', error)
29
+ } finally {
30
+ setIsLoading(false)
31
+ }
32
+ }
33
+
34
+ const handleDownload = async (model) => {
35
+ setIsLoading(true)
36
+ setSelectedModel(model)
37
+
38
+ try {
39
+ // Simulate download process
40
+ await new Promise(resolve => setTimeout(resolve, 1500))
41
+
42
+ const updatedModels = [...downloadedModels, model]
43
+ setDownloadedModels(updatedModels)
44
+ localStorage.setItem('downloadedModels', JSON.stringify(updatedModels))
45
+ } catch (error) {
46
+ console.error('Download failed:', error)
47
+ } finally {
48
+ setIsLoading(false)
49
+ }
50
+ }
51
+
52
+ const handleRemove = (modelId) => {
53
+ const updatedModels = downloadedModels.filter(m => m.id !== modelId)
54
+ setDownloadedModels(updatedModels)
55
+ localStorage.setItem('downloadedModels', JSON.stringify(updatedModels))
56
+ }
57
+
58
+ const filteredModels = models.filter(model => {
59
+ const matchesSearch = model.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
60
+ model.description.toLowerCase().includes(searchTerm.toLowerCase())
61
+ const matchesFilter = filterType === 'all' || model.type === filterType
62
+ return matchesSearch && matchesFilter
63
+ })
64
+
65
+ const getModelStatus = (modelId) => {
66
+ return downloadedModels.some(m => m.id === modelId) ? 'downloaded' : 'available'
67
+ }
68
+
69
+ return (
70
+ <div className="space-y-6">
71
+ <div className="flex flex-wrap justify-between items-center gap-4">
72
+ <h2 className="text-2xl font-bold text-gray-800">AI Model Hub</h2>
73
+ <div className="flex items-center space-x-4">
74
+ <div className="relative">
75
+ <FiSearch className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400" />
76
+ <input
77
+ type="text"
78
+ placeholder="Search models..."
79
+ value={searchTerm}
80
+ onChange={(e) => setSearchTerm(e.target.value)}
81
+ className="pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-transparent"
82
+ />
83
+ </div>
84
+ <select
85
+ value={filterType}
86
+ onChange={(e) => setFilterType(e.target.value)}
87
+ className="px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-transparent"
88
+ >
89
+ <option value="all">All Types</option>
90
+ <option value="offline">Offline</option>
91
+ <option value="online">Online</option>
92
+ </select>
93
+ </div>
94
+ </div>
95
+
96
+ {isLoading && (
97
+ <div className="flex justify-center items-center py-8">
98
+ <div className="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-primary"></div>
99
+ </div>
100
+ )}
101
+
102
+ <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
103
+ {filteredModels.map((model) => (
104
+ <div key={model.id} className="bg-white rounded-lg shadow-md overflow-hidden hover:shadow-lg transition-shadow">
105
+ <div className="p-4">
106
+ <div className="flex justify-between items-start mb-3">
107
+ <h3 className="font-bold text-lg">{model.name}</h3>
108
+ <span className={`px-2 py-1 rounded-full text-xs ${model.type === 'offline' ? 'bg-green-100 text-green-800' : 'bg-blue-100 text-blue-800'}`}>
109
+ {model.type}
110
+ </span>
111
+ </div>
112
+ <p className="text-gray-600 text-sm mb-4">{model.description}</p>
113
+ <div className="flex justify-between items-center text-sm text-gray-500 mb-4">
114
+ <span>Size: {model.size}</span>
115
+ <span>Version: {model.version || '1.0'}</span>
116
+ </div>
117
+ <div className="space-y-2">
118
+ {getModelStatus(model.id) === 'downloaded' ? (
119
+ <>
120
+ <button
121
+ onClick={() => setSelectedModel(model)}
122
+ className="w-full py-2 bg-success hover:bg-green-600 text-white rounded-lg flex items-center justify-center space-x-2 transition-colors"
123
+ >
124
+ <FiInfo />
125
+ <span>View Details</span>
126
+ </button>
127
+ <button
128
+ onClick={() => handleRemove(model.id)}
129
+ className="w-full py-2 bg-danger hover:bg-red-600 text-white rounded-lg flex items-center justify-center space-x-2 transition-colors"
130
+ >
131
+ <FiTrash2 />
132
+ <span>Remove</span>
133
+ </button>
134
+ </>
135
+ ) : (
136
+ <button
137
+ onClick={() => handleDownload(model)}
138
+ disabled={isLoading}
139
+ className={`w-full py-2 rounded-lg flex items-center justify-center space-x-2 transition-colors ${isLoading ? 'bg-gray-400' : 'bg-primary hover:bg-blue-600 text-white'}`}
140
+ >
141
+ {isLoading && selectedModel?.id === model.id ? (
142
+ <>
143
+ <span className="animate-spin rounded-full h-4 w-4 border-t-2 border-b-2 border-white"></span>
144
+ <span>Downloading...</span>
145
+ </>
146
+ ) : (
147
+ <>
148
+ <FiDownload />
149
+ <span>Download</span>
150
+ </>
151
+ )}
152
+ </button>
153
+ )}
154
+ </div>
155
+ </div>
156
+ </div>
157
+ ))}
158
+ </div>
159
+
160
+ {selectedModel && (
161
+ <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center p-4 z-50">
162
+ <div className="bg-white rounded-lg p-6 max-w-2xl w-full max-h-[80vh] overflow-y-auto">
163
+ <div className="flex justify-between items-center mb-4">
164
+ <h3 className="text-xl font-bold">{selectedModel.name}</h3>
165
+ <button
166
+ onClick={() => setSelectedModel(null)}
167
+ className="text-gray-400 hover:text-gray-600 text-2xl"
168
+ >
169
+ ×
170
+ </button>
171
+ </div>
172
+
173
+ <div className="space-y-4">
174
+ <div>
175
+ <h4 className="font-medium text-gray-700 mb-1">Description</h4>
176
+ <p className="text-gray-600">{selectedModel.description}</p>
177
+ </div>
178
+
179
+ <div className="grid grid-cols-2 gap-4">
180
+ <div>
181
+ <h4 className="font-medium text-gray-700 mb-1">Type</h4>
182
+ <p className="text-gray-600">{selectedModel.type}</p>
183
+ </div>
184
+ <div>
185
+ <h4 className="font-medium text-gray-700 mb-1">Size</h4>
186
+ <p className="text-gray-600">{selectedModel.size}</p>
187
+ </div>
188
+ <div>
189
+ <h4 className="font-medium text-gray-700 mb-1">Version</h4>
190
+ <p className="text-gray-600">{selectedModel.version || '1.0'}</p>
191
+ </div>
192
+ <div>
193
+ <h4 className="font-medium text-gray-700 mb-1">Last Updated</h4>
194
+ <p className="text-gray-600">{selectedModel.updatedAt || 'N/A'}</p>
195
+ </div>
196
+ </div>
197
+
198
+ <div>
199
+ <h4 className="font-medium text-gray-700 mb-2">Features</h4>
200
+ <ul className="list-disc list-inside text-gray-600 space-y-1">
201
+ <li>Code completion and suggestions</li>
202
+ <li>Multi-language support</li>
203
+ <li>Offline functionality</li>
204
+ <li>Customizable parameters</li>
205
+ <li>Real-time analysis</li>
206
+ </ul>
207
+ </div>
208
+
209
+ <div>
210
+ <h4 className="font-medium text-gray-700 mb-2">Usage Example</h4>
211
+ <div className="bg-gray-100 p-3 rounded-lg font-mono text-sm">
212
+ <pre>
213
+ {`// Import the model
214
+ const model = require('${selectedModel.name.toLowerCase().replace(/\s+/g, '-')}')
215
+
216
+ // Initialize with your parameters
217
+ const instance = new model({
218
+ temperature: 0.7,
219
+ maxTokens: 100
220
+ })
221
+
222
+ // Use the model
223
+ const result = instance.generate('Write a function to calculate factorial')`}
224
+ </pre>
225
+ </div>
226
+ </div>
227
+
228
+ <div className="flex space-x-2">
229
+ <button
230
+ onClick={() => setSelectedModel(null)}
231
+ className="flex-1 py-2 bg-gray-200 hover:bg-gray-300 text-gray-800 rounded-lg transition-colors"
232
+ >
233
+ Close
234
+ </button>
235
+ <button className="flex-1 py-2 bg-primary hover:bg-blue-600 text-white rounded-lg transition-colors">
236
+ Documentation
237
+ </button>
238
+ </div>
239
+ </div>
240
+ </div>
241
+ </div>
242
+ )}
243
+
244
+ {downloadedModels.length > 0 && (
245
+ <div className="mt-8 p-4 bg-gray-50 rounded-lg">
246
+ <h3 className="font-bold text-gray-800 mb-4">Your Downloaded Models ({downloadedModels.length})</h3>
247
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
248
+ {downloadedModels.map((model) => (
249
+ <div key={model.id} className="bg-white rounded-lg p-4 shadow-sm">
250
+ <div className="flex justify-between items-start">
251
+ <div>
252
+ <h4 className="font-medium text-gray-800">{model.name}</h4>
253
+ <p className="text-sm text-gray-500">{model.size}</p>
254
+ </div>
255
+ <button
256
+ onClick={() => handleRemove(model.id)}
257
+ className="text-red-500 hover:text-red-700"
258
+ title="Remove model"
259
+ >
260
+ <FiTrash2 />
261
+ </button>
262
+ </div>
263
+ </div>
264
+ ))}
265
+ </div>
266
+ </div>
267
+ )}
268
+ </div>
269
+ )
270
+ }