import { useCallback, useState } from 'react' import { Model } from '@janhq/core' import { Badge, Button, Tooltip, TooltipArrow, TooltipContent, TooltipPortal, TooltipTrigger, } from '@janhq/uikit' import { useAtomValue, useSetAtom } from 'jotai' import { ChevronDownIcon } from 'lucide-react' import { twMerge } from 'tailwind-merge' import ModalCancelDownload from '@/containers/ModalCancelDownload' import ModelLabel from '@/containers/ModelLabel' import { toaster } from '@/containers/Toast' import { MainViewState } from '@/constants/screens' import { useCreateNewThread } from '@/hooks/useCreateNewThread' import useDownloadModel from '@/hooks/useDownloadModel' import { useSettings } from '@/hooks/useSettings' import { toGibibytes } from '@/utils/converter' import { mainViewStateAtom } from '@/helpers/atoms/App.atom' import { assistantsAtom } from '@/helpers/atoms/Assistant.atom' import { serverEnabledAtom } from '@/helpers/atoms/LocalServer.atom' import { downloadedModelsAtom, getDownloadingModelAtom, } from '@/helpers/atoms/Model.atom' import { nvidiaTotalVramAtom, totalRamAtom, } from '@/helpers/atoms/SystemBar.atom' type Props = { model: Model onClick: () => void open: string } const ExploreModelItemHeader: React.FC = ({ model, onClick, open }) => { const { downloadModel } = useDownloadModel() const downloadingModels = useAtomValue(getDownloadingModelAtom) const downloadedModels = useAtomValue(downloadedModelsAtom) const { requestCreateNewThread } = useCreateNewThread() const totalRam = useAtomValue(totalRamAtom) const { settings } = useSettings() const [imageLoaded, setImageLoaded] = useState(true) const nvidiaTotalVram = useAtomValue(nvidiaTotalVramAtom) const setMainViewState = useSetAtom(mainViewStateAtom) // Default nvidia returns vram in MB, need to convert to bytes to match the unit of totalRamW let ram = nvidiaTotalVram * 1024 * 1024 if (ram === 0 || settings?.run_mode === 'cpu') { ram = totalRam } const serverEnabled = useAtomValue(serverEnabledAtom) const assistants = useAtomValue(assistantsAtom) const onDownloadClick = useCallback(() => { downloadModel(model) }, [model, downloadModel]) const isDownloaded = downloadedModels.find((md) => md.id === model.id) != null let downloadButton = ( ) const isDownloading = downloadingModels.some((md) => md.id === model.id) const onUseModelClick = useCallback(async () => { if (assistants.length === 0) { toaster({ title: 'No assistant available.', description: `Could not use Model ${model.name} as no assistant is available.`, type: 'error', }) return } await requestCreateNewThread(assistants[0], model) setMainViewState(MainViewState.Thread) }, [assistants, model, requestCreateNewThread, setMainViewState]) if (isDownloaded) { downloadButton = ( {serverEnabled && ( Threads are disabled while the server is running )} ) } else if (isDownloading) { downloadButton = } return (
{model.metadata.cover && imageLoaded && (
setImageLoaded(false)} src={model.metadata.cover} className="h-[250px] w-full object-cover" alt={`Cover - ${model.id}`} />
)}
{model.name}
{toGibibytes(model.metadata.size)} {} {downloadButton}
) } type EngineBadgeProps = { engine: string } const EngineBadge: React.FC = ({ engine }) => { const title = 'TensorRT-LLM' switch (engine) { case 'nitro-tensorrt-llm': return ( {title} ) default: return null } } export default ExploreModelItemHeader