import { createFileRoute, Link, useNavigate } from '@tanstack/react-router' import { route } from '@/constants/routes' import { useModelSources } from '@/hooks/useModelSources' import { cn, fuzzySearch, toGigabytes } from '@/lib/utils' import { useState, useMemo, useEffect, ChangeEvent, useCallback } from 'react' import { Button } from '@/components/ui/button' import { useModelProvider } from '@/hooks/useModelProvider' import { Card, CardItem } from '@/containers/Card' import { RenderMarkdown } from '@/containers/RenderMarkdown' import { extractModelName, extractDescription } from '@/lib/models' import { IconDownload, IconFileCode, IconSearch } from '@tabler/icons-react' import { Switch } from '@/components/ui/switch' import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from '@/components/ui/dropdown-menu' import { downloadModel } from '@/services/models' import { useDownloadStore } from '@/hooks/useDownloadStore' import { Progress } from '@/components/ui/progress' import HeaderPage from '@/containers/HeaderPage' type ModelProps = { model: { id: string models: { id: string }[] } } // eslint-disable-next-line @typescript-eslint/no-explicit-any export const Route = createFileRoute(route.hub as any)({ component: Hub, }) const sortOptions = [ { value: 'newest', name: 'Newest' }, { value: 'most-downloaded', name: 'Most downloaded' }, ] function Hub() { const { sources, fetchSources, loading } = useModelSources() const [searchValue, setSearchValue] = useState('') const [sortSelected, setSortSelected] = useState('newest') const [expandedModels, setExpandedModels] = useState>( {} ) const toggleModelExpansion = (modelId: string) => { setExpandedModels((prev) => ({ ...prev, [modelId]: !prev[modelId], })) } // Sorting functionality const sortedModels = useMemo(() => { return [...sources].sort((a, b) => { if (sortSelected === 'most-downloaded') { return (b.metadata?.downloads || 0) - (a.metadata?.downloads || 0) } else { return ( new Date(b.metadata?.createdAt || 0).getTime() - new Date(a.metadata?.createdAt || 0).getTime() ) } }) }, [sortSelected, sources]) // Filtered models const filteredModels = useMemo(() => { // Apply additional filters here if needed return searchValue.length ? sortedModels?.filter((e) => fuzzySearch( searchValue.replace(/\s+/g, '').toLowerCase(), e.id.toLowerCase() ) ) : sortedModels }, [searchValue, sortedModels]) useEffect(() => { fetchSources() }, [fetchSources]) const handleSearchChange = (e: ChangeEvent) => { setSearchValue(e.target.value) } const { downloads } = useDownloadStore() const downloadProcesses = useMemo( () => Object.values(downloads).map((download) => ({ id: download.name, name: download.name, progress: download.progress, current: download.current, total: download.total, })), [downloads] ) const { getProviderByName } = useModelProvider() const llamaProvider = getProviderByName('llama.cpp') const navigate = useNavigate() const handleUseModel = useCallback( (modelId: string) => { navigate({ to: route.home, params: {}, search: { model: { id: modelId, provider: 'llama.cpp', }, }, }) }, [navigate] ) const DownloadButtonPlaceholder = useMemo(() => { return ({ model }: ModelProps) => { const modelId = model.models[0]?.id const isDownloading = downloadProcesses.some((e) => e.id === modelId) const downloadProgress = downloadProcesses.find((e) => e.id === modelId)?.progress || 0 const isDownloaded = llamaProvider?.models.some( (m: { id: string }) => m.id === modelId ) return ( <> {isDownloading ? (
{Math.round(downloadProgress * 100)}%
) : isDownloaded ? ( ) : ( )} ) } }, [downloadProcesses, llamaProvider?.models, handleUseModel]) return (
{ sortOptions.find((option) => option.value === sortSelected) ?.name } {sortOptions.map((option) => ( setSortSelected(option.value)} > {option.name} ))}
{loading ? (
Loading models...
) : filteredModels.length === 0 ? (
No models found
) : (
{filteredModels.map((model) => (

{extractModelName(model.id) || ''}

{toGigabytes(model.models?.[0]?.size)}
} >
By {model?.author}
{model.metadata?.downloads || 0}
{model.models?.length || 0}
{model.models.length > 1 && (
toggleModelExpansion(model.id) } />

Show variants

)}
{expandedModels[model.id] && model.models.length > 0 && (
{model.models.map((variant) => ( {/* {defaultVariant && <>test} */}

{toGigabytes(variant.size)}

{(() => { const isDownloading = downloadProcesses.some( (e) => e.id === variant.id ) const downloadProgress = downloadProcesses.find( (e) => e.id === variant.id )?.progress || 0 const isDownloaded = llamaProvider?.models.some( (m: { id: string }) => m.id === variant.id ) if (isDownloading) { return ( <>
{Math.round( downloadProgress * 100 )} %
) } if (isDownloaded) { return (
) } return (
downloadModel(variant.id) } >
) })()}
} /> ))}
)}
))}
)}
) }