File size: 6,058 Bytes
e7ba29d ad5cef3 e7ba29d 6ebf2fd ad5cef3 117cfaa 6ebf2fd 4d810fa 6ebf2fd 63dbafb 6ebf2fd ad5cef3 93d1827 ad5cef3 de6e73e 93d1827 ad5cef3 e7ba29d ad5cef3 93d1827 ad5cef3 e7ba29d f3b30b4 ad5cef3 93d1827 ad5cef3 de6e73e 93d1827 ad5cef3 93d1827 ad5cef3 de6e73e 93d1827 ad5cef3 93d1827 ad5cef3 6ebf2fd 4d810fa ad5cef3 6ebf2fd 93d1827 6ebf2fd f3b30b4 6ebf2fd 5541427 63dbafb f3b30b4 6ebf2fd 93d1827 6ebf2fd f3b30b4 6ebf2fd f3b30b4 6ebf2fd 93d1827 f3b30b4 6ebf2fd f3b30b4 6ebf2fd f3b30b4 93d1827 f3b30b4 6ebf2fd f3b30b4 6ebf2fd f3b30b4 93d1827 6ebf2fd f3b30b4 93d1827 6ebf2fd f3b30b4 6ebf2fd 117cfaa 6ebf2fd 117cfaa 6ebf2fd ad5cef3 6ebf2fd 63dbafb 93d1827 63dbafb 6ebf2fd |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
import {
Bot,
Heart,
Download,
Cpu,
DatabaseIcon,
CheckCircle,
XCircle,
ExternalLink
} from 'lucide-react'
import { getModelSize } from '../lib/huggingface'
import { useModel } from '../contexts/ModelContext'
import ModelLoader from './ModelLoader'
import Tooltip from './Tooltip'
const ModelInfo = () => {
const formatNumber = (num: number) => {
if (num >= 1000000000) {
return (num / 1000000000).toFixed(1) + 'B'
} else if (num >= 1000000) {
return (num / 1000000).toFixed(1) + 'M'
} else if (num >= 1000) {
return (num / 1000).toFixed(1) + 'K'
}
return num.toString()
}
const {
models,
status,
modelInfo,
selectedQuantization,
isFetching,
errorText
} = useModel()
const ModelInfoSkeleton = () => (
<div className="bg-gradient-to-r from-secondary to-accent px-3 py-3 rounded-lg border border-border space-y-3 animate-pulse w-4/5">
<div className="flex items-center space-x-2">
<Bot className="w-4 h-4 text-green-500" />
<div className="h-4 bg-muted rounded-sm flex-1"></div>
<div className="w-4 h-4 bg-muted rounded-full"></div>
</div>
<div className="flex items-center space-x-2 ml-6">
<div className="h-3 bg-muted/80 rounded-sm w-32"></div>
</div>
<div className="grid grid-cols-2 gap-2 text-xs">
<div className="flex items-center space-x-1">
<Heart className="w-3 h-3 text-destructive/60" />
<div className="h-3 bg-muted/80 rounded-sm w-8"></div>
</div>
<div className="flex items-center space-x-1">
<Download className="w-3 h-3 text-purple-500" />
<div className="h-3 bg-muted/80 rounded-sm w-8"></div>
</div>
<div className="flex items-center space-x-1">
<Cpu className="w-3 h-3 text-chart-4/60" />
<div className="h-3 bg-muted/80 rounded-sm w-8"></div>
</div>
<div className="flex items-center space-x-1">
<DatabaseIcon className="w-3 h-3 text-purple-500" />
<div className="h-3 bg-muted/80 rounded-sm w-12"></div>
</div>
</div>
<hr className="border-border" />
<div className="h-8 bg-muted/80 rounded-sm w-full"></div>
</div>
)
if (!modelInfo || isFetching || models.length === 0) {
return <ModelInfoSkeleton />
}
return (
<div className="relative bg-gradient-to-r from-secondary to-accent px-3 py-3 rounded-lg border border-border space-y-3 h-full w-4/5">
{/* Model Name Row */}
<div className="flex justify-center items-center space-x-2">
{/* Compatibility Status */}
{typeof modelInfo.isCompatible === 'boolean' && (
<div className="shrink-0 ">
{modelInfo.isCompatible && status !== 'error' ? (
<CheckCircle className="w-4 h-4 text-green-500" />
) : (
<XCircle className="w-4 h-4 text-destructive" />
)}
</div>
)}
<div className="flex-1 min-w-0">
<a
href={`https://huggingface.co/${modelInfo.name}`}
target="_blank"
rel="noopener noreferrer"
className="text-sm font-medium text-foreground/80 hover:underline block truncate"
title={modelInfo.name}
>
<ExternalLink className="w-3 h-3 inline-block mr-1" />
{modelInfo.name}
</a>
{/* Base Model Link */}
{modelInfo.baseId && modelInfo.baseId !== modelInfo.id && (
<a
href={`https://huggingface.co/${modelInfo.baseId}`}
target="_blank"
rel="noopener noreferrer"
className="text-xs text-muted-foreground hover:underline block truncate mt-1"
title={`Base model: ${modelInfo.baseId}`}
>
<ExternalLink className="w-3 h-3 inline-block mr-1" />(
{modelInfo.baseId})
</a>
)}
</div>
</div>
{/* Stats Grid */}
<div className="grid grid-cols-2 gap-2 text-xs text-muted-foreground">
{modelInfo.likes > 0 && (
<div className="flex items-center space-x-1">
<Heart className="w-3 h-3 text-destructive" />
<span>{formatNumber(modelInfo.likes)}</span>
</div>
)}
{modelInfo.downloads > 0 && (
<div className="flex items-center space-x-1">
<Download className="w-3 h-3 text-green-500" />
<span>{formatNumber(modelInfo.downloads)}</span>
</div>
)}
<Tooltip content="Model parameters according to Hugging Face API">
<div className="flex items-center space-x-1 cursor-default">
<Cpu className="w-3 h-3 text-purple-500" />
{modelInfo.parameters ? (
<span>{formatNumber(modelInfo.parameters)}</span>
) : (
<span>?</span>
)}
</div>
</Tooltip>
<Tooltip
content={`Estimated size with ${selectedQuantization} quantization`}
>
<div className="flex items-center space-x-1 cursor-default">
<DatabaseIcon className="w-3 h-3 text-purple-500" />
{modelInfo.parameters ? (
<span>
{`~${getModelSize(
modelInfo.parameters,
selectedQuantization
).toFixed(1)}MB`}
</span>
) : (
<span>?</span>
)}
</div>
</Tooltip>
</div>
<ModelLoader />
{/* Incompatibility Message */}
{((modelInfo.isCompatible === false && modelInfo.incompatibilityReason) ||
errorText) && (
<div className="bg-destructive/10 border border-destructive/20 rounded-md px-2 py-2">
<p className="text-xs text-destructive whitespace-break-spaces">
{errorText ? errorText : modelInfo.incompatibilityReason}
</p>
</div>
)}
</div>
)
}
export default ModelInfo
|