import { useState, useEffect } from "react"; import { motion, AnimatePresence } from "framer-motion"; import { Search, Download, Trash2, RefreshCw, Check, HardDrive, Cpu, AlertCircle, X } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { ScrollArea } from "@/components/ui/scroll-area"; import { Progress } from "@/components/ui/progress"; import { Badge } from "@/components/ui/badge"; import { useOllama } from "@/hooks/useOllama"; import { cn } from "@/lib/utils"; interface ModelStoreProps { ollamaUrl: string; onModelSelect?: (model: string) => void; selectedModel?: string; } export function ModelStore({ ollamaUrl, onModelSelect, selectedModel }: ModelStoreProps) { const [search, setSearch] = useState(""); const [view, setView] = useState<"library" | "installed">("library"); const { installedModels, isConnected, isLoading, downloadProgress, error, checkConnection, refreshModels, pullModel, deleteModel, getLibraryModels, } = useOllama(ollamaUrl); useEffect(() => { checkConnection(); }, [checkConnection]); const libraryModels = getLibraryModels(); const filteredLibrary = libraryModels.filter((m) => m.name.toLowerCase().includes(search.toLowerCase()) || m.description.toLowerCase().includes(search.toLowerCase()) || m.tags.some((t) => t.toLowerCase().includes(search.toLowerCase())) ); const filteredInstalled = installedModels.filter((m) => m.name.toLowerCase().includes(search.toLowerCase()) ); const formatSize = (bytes: number) => { const gb = bytes / (1024 * 1024 * 1024); if (gb >= 1) return `${gb.toFixed(1)} GB`; return `${(bytes / (1024 * 1024)).toFixed(0)} MB`; }; return (
{error}
{model.description}
No models installed
Browse the library to download models