import { useCallback } 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 { MainViewState } from '@/constants/screens' import { useCreateNewThread } from '@/hooks/useCreateNewThread' import useDownloadModel from '@/hooks/useDownloadModel' 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 getLabel = (size: number, ram: number) => { if (size * 1.25 >= ram) { return ( Not enough RAM ) } else { return ( Recommended ) } } 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 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) { 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 = ( { e.stopPropagation() onDownloadClick() }} > Download ) const isDownloading = downloadingModels.some((md) => md.id === model.id) const onUseModelClick = useCallback(async () => { if (assistants.length === 0) { alert('No assistant available') return } await requestCreateNewThread(assistants[0], model) setMainViewState(MainViewState.Thread) }, [assistants, model, requestCreateNewThread, setMainViewState]) if (isDownloaded) { downloadButton = ( Use {serverEnabled && ( Threads are disabled while the server is running )} ) } else if (isDownloading) { downloadButton = } return ( {model.metadata.cover && ( )} {model.name} {toGibibytes(model.metadata.size)} {getLabel(model.metadata.size, ram)} {downloadButton} ) } type EngineBadgeProps = { engine: string } const EngineBadge: React.FC = ({ engine }) => { switch (engine) { case 'nitro-tensorrt-llm': const title = 'TensorRT-LLM' return ( {title} ) default: return null } } export default ExploreModelItemHeader