anycoder-f86f051e / components /ModelSelector.jsx
Mehdi
Upload components/ModelSelector.jsx with huggingface_hub
2deb820 verified
Raw
History Blame Contribute Delete
10.9 kB
import { useState, useEffect } from 'react'
import { FiDownload, FiTrash2, FiInfo, FiSearch, FiFilter, FiCpu, FiDatabase, FiCloud, FiCheckCircle, FiXCircle } from 'react-icons/fi'
import axios from 'axios'
export default function ModelSelector() {
const [models, setModels] = useState([])
const [selectedModel, setSelectedModel] = useState(null)
const [isLoading, setIsLoading] = useState(false)
const [downloadedModels, setDownloadedModels] = useState([])
const [searchTerm, setSearchTerm] = useState('')
const [filterType, setFilterType] = useState('all')
const [showDetails, setShowDetails] = useState(false)
useEffect(() => {
fetchModels()
const saved = localStorage.getItem('downloadedModels')
if (saved) {
setDownloadedModels(JSON.parse(saved))
}
}, [])
const fetchModels = async () => {
try {
setIsLoading(true)
const response = await axios.get('/api/models')
setModels(response.data)
} catch (error) {
console.error('Error fetching models:', error)
} finally {
setIsLoading(false)
}
}
const handleDownload = async (model) => {
setIsLoading(true)
setSelectedModel(model)
try {
await new Promise(resolve => setTimeout(resolve, 1500))
const updatedModels = [...downloadedModels, model]
setDownloadedModels(updatedModels)
localStorage.setItem('downloadedModels', JSON.stringify(updatedModels))
} catch (error) {
console.error('Download failed:', error)
} finally {
setIsLoading(false)
}
}
const handleRemove = (modelId) => {
const updatedModels = downloadedModels.filter(m => m.id !== modelId)
setDownloadedModels(updatedModels)
localStorage.setItem('downloadedModels', JSON.stringify(updatedModels))
}
const filteredModels = models.filter(model => {
const matchesSearch = model.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
model.description.toLowerCase().includes(searchTerm.toLowerCase())
const matchesFilter = filterType === 'all' || model.type === filterType
return matchesSearch && matchesFilter
})
const getModelStatus = (modelId) => {
return downloadedModels.some(m => m.id === modelId) ? 'downloaded' : 'available'
}
return (
<div className="space-y-6">
<div className="flex flex-wrap justify-between items-center gap-4">
<h2 className="text-2xl font-bold text-gray-800">AI Model Hub</h2>
<div className="flex items-center space-x-4">
<div className="relative">
<FiSearch className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400" />
<input
type="text"
placeholder="Search models..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-transparent"
/>
</div>
<select
value={filterType}
onChange={(e) => setFilterType(e.target.value)}
className="px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-transparent"
>
<option value="all">All Types</option>
<option value="offline">Offline</option>
<option value="online">Online</option>
</select>
</div>
</div>
{isLoading && (
<div className="flex justify-center items-center py-8">
<div className="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-primary"></div>
</div>
)}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{filteredModels.map((model) => (
<div key={model.id} className="bg-white rounded-lg shadow-md overflow-hidden hover:shadow-lg transition-shadow">
<div className="p-4">
<div className="flex justify-between items-start mb-3">
<h3 className="font-bold text-lg">{model.name}</h3>
<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'}`}>
{model.type}
</span>
</div>
<p className="text-gray-600 text-sm mb-4">{model.description}</p>
<div className="flex justify-between items-center text-sm text-gray-500 mb-4">
<span>Size: {model.size}</span>
<span>Version: {model.version || '1.0'}</span>
</div>
<div className="space-y-2">
{getModelStatus(model.id) === 'downloaded' ? (
<>
<button
onClick={() => setSelectedModel(model)}
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"
>
<FiInfo />
<span>View Details</span>
</button>
<button
onClick={() => handleRemove(model.id)}
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"
>
<FiTrash2 />
<span>Remove</span>
</button>
</>
) : (
<button
onClick={() => handleDownload(model)}
disabled={isLoading}
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'}`}
>
{isLoading && selectedModel?.id === model.id ? (
<>
<span className="animate-spin rounded-full h-4 w-4 border-t-2 border-b-2 border-white"></span>
<span>Downloading...</span>
</>
) : (
<>
<FiDownload />
<span>Download</span>
</>
)}
</button>
)}
</div>
</div>
</div>
))}
</div>
{selectedModel && (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center p-4 z-50">
<div className="bg-white rounded-lg p-6 max-w-2xl w-full max-h-[80vh] overflow-y-auto">
<div className="flex justify-between items-center mb-4">
<h3 className="text-xl font-bold">{selectedModel.name}</h3>
<button
onClick={() => setSelectedModel(null)}
className="text-gray-400 hover:text-gray-600 text-2xl"
>
×
</button>
</div>
<div className="space-y-4">
<div>
<h4 className="font-medium text-gray-700 mb-1">Description</h4>
<p className="text-gray-600">{selectedModel.description}</p>
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<h4 className="font-medium text-gray-700 mb-1">Type</h4>
<p className="text-gray-600">{selectedModel.type}</p>
</div>
<div>
<h4 className="font-medium text-gray-700 mb-1">Size</h4>
<p className="text-gray-600">{selectedModel.size}</p>
</div>
<div>
<h4 className="font-medium text-gray-700 mb-1">Version</h4>
<p className="text-gray-600">{selectedModel.version || '1.0'}</p>
</div>
<div>
<h4 className="font-medium text-gray-700 mb-1">Last Updated</h4>
<p className="text-gray-600">{selectedModel.updatedAt || 'N/A'}</p>
</div>
</div>
<div>
<h4 className="font-medium text-gray-700 mb-2">Features</h4>
<ul className="list-disc list-inside text-gray-600 space-y-1">
<li>Code completion and suggestions</li>
<li>Multi-language support</li>
<li>Offline functionality</li>
<li>Customizable parameters</li>
<li>Real-time analysis</li>
</ul>
</div>
<div>
<h4 className="font-medium text-gray-700 mb-2">Usage Example</h4>
<div className="bg-gray-100 p-3 rounded-lg font-mono text-sm">
<pre>
{`// Import the model
const model = require('${selectedModel.name.toLowerCase().replace(/\s+/g, '-')}')
// Initialize with your parameters
const instance = new model({
temperature: 0.7,
maxTokens: 100
})
// Use the model
const result = instance.generate('Write a function to calculate factorial')`}
</pre>
</div>
</div>
<div className="flex space-x-2">
<button
onClick={() => setSelectedModel(null)}
className="flex-1 py-2 bg-gray-200 hover:bg-gray-300 text-gray-800 rounded-lg transition-colors"
>
Close
</button>
<button className="flex-1 py-2 bg-primary hover:bg-blue-600 text-white rounded-lg transition-colors">
Documentation
</button>
</div>
</div>
</div>
</div>
)}
{downloadedModels.length > 0 && (
<div className="mt-8 p-4 bg-gray-50 rounded-lg">
<h3 className="font-bold text-gray-800 mb-4">Your Downloaded Models ({downloadedModels.length})</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
{downloadedModels.map((model) => (
<div key={model.id} className="bg-white rounded-lg p-4 shadow-sm">
<div className="flex justify-between items-start">
<div>
<h4 className="font-medium text-gray-800">{model.name}</h4>
<p className="text-sm text-gray-500">{model.size}</p>
</div>
<button
onClick={() => handleRemove(model.id)}
className="text-red-500 hover:text-red-700"
title="Remove model"
>
<FiTrash2 />
</button>
</div>
</div>
))}
</div>
</div>
)}
</div>
)
}