import React, { Fragment, useState } from 'react' import Image from 'next/image' import { InferenceEngine } from '@janhq/core' import { Button, Input, Progress, ScrollArea } from '@janhq/joi' import { useClickOutside } from '@janhq/joi' import { useAtomValue, useSetAtom } from 'jotai' import { SearchIcon, DownloadCloudIcon } from 'lucide-react' import { twMerge } from 'tailwind-merge' import LogoMark from '@/containers/Brand/Logo/Mark' import CenterPanelContainer from '@/containers/CenterPanelContainer' import ProgressCircle from '@/containers/Loader/ProgressCircle' import ModelLabel from '@/containers/ModelLabel' import { MainViewState } from '@/constants/screens' import useDownloadModel from '@/hooks/useDownloadModel' import { modelDownloadStateAtom } from '@/hooks/useDownloadState' import { useGetEngines } from '@/hooks/useEngineManagement' import { useGetModelSources } from '@/hooks/useModelSource' import { formatDownloadPercentage, toGigabytes } from '@/utils/converter' import { manualRecommendationModel } from '@/utils/model' import { getLogoEngine, getTitleByEngine, isLocalEngine, } from '@/utils/modelEngine' import { extractModelName } from '@/utils/modelSource' import { mainViewStateAtom } from '@/helpers/atoms/App.atom' import { configuredModelsAtom, getDownloadingModelAtom, } from '@/helpers/atoms/Model.atom' import { selectedSettingAtom } from '@/helpers/atoms/Setting.atom' type Props = { isShowStarterScreen?: boolean } const OnDeviceStarterScreen = ({ isShowStarterScreen }: Props) => { const [searchValue, setSearchValue] = useState('') const [isOpen, setIsOpen] = useState(Boolean(searchValue.length)) const downloadingModels = useAtomValue(getDownloadingModelAtom) const { downloadModel } = useDownloadModel() const downloadStates = useAtomValue(modelDownloadStateAtom) const setSelectedSetting = useSetAtom(selectedSettingAtom) const { engines } = useGetEngines() const configuredModels = useAtomValue(configuredModelsAtom) const { sources } = useGetModelSources() const setMainViewState = useSetAtom(mainViewStateAtom) const featuredModels = sources?.filter((x) => manualRecommendationModel.includes(x.id) ) const remoteModel = configuredModels.filter( (x) => !isLocalEngine(engines, x.engine) ) const remoteModelEngine = remoteModel.map((x) => x.engine) const groupByEngine = remoteModelEngine.filter(function (item, index) { if (remoteModelEngine.indexOf(item) === index) return item }) const itemsPerRow = 5 const getRows = (array: string[], itemsPerRow: number) => { const rows = [] for (let i = 0; i < array.length; i += itemsPerRow) { rows.push(array.slice(i, i + itemsPerRow)) } return rows } const rows = getRows( groupByEngine.sort((a, b) => a.localeCompare(b)), itemsPerRow ) const refDropdown = useClickOutside(() => setIsOpen(false)) const [visibleRows, setVisibleRows] = useState(1) return (

Select a model to start

setIsOpen(true)} onChange={(e) => { setSearchValue(e.target.value) }} placeholder="Search..." prefixIcon={} />
{!featuredModels?.length ? (

No Result Found

) : ( sources?.map((model) => { const isDownloading = downloadingModels.some( (md) => md === (model.models[0]?.id ?? model.id) ) return (

{extractModelName(model.id)}

{toGigabytes(model.models[0]?.size)} {!isDownloading ? ( downloadModel( model.models[0]?.id ?? model.id ) } /> ) : ( Object.values(downloadStates) .filter( (x) => x.modelId === model.models[0]?.id ) .map((item) => ( )) )}
) }) )}

On-device Models

{ setMainViewState(MainViewState.Hub) }} > See All

{featuredModels?.map((featModel) => { const isDownloading = downloadingModels.some( (md) => md === (featModel.models[0]?.id ?? featModel.id) ) return (
{extractModelName(featModel.id)}
{isDownloading ? (
{Object.values(downloadStates) .filter( (x) => x.modelId === featModel.models[0]?.id ) .map((item, i) => (
{formatDownloadPercentage(item?.percent)}
))} {toGigabytes(featModel.models[0]?.size)}
) : (
{toGigabytes(featModel.models[0]?.size)}
)}
) })}

Cloud Models

{rows.slice(0, visibleRows).map((row, rowIndex) => { return (
{row .filter( (e) => engines?.[e as InferenceEngine]?.[0]?.type === 'remote' ) .map((remoteEngine) => { const engineLogo = getLogoEngine( remoteEngine as InferenceEngine ) return (
{ setMainViewState(MainViewState.Settings) setSelectedSetting( remoteEngine as InferenceEngine ) }} > {engineLogo && ( Engine logo )}

{getTitleByEngine( remoteEngine as InferenceEngine )}

) })}
) })}
{visibleRows < rows.length && ( )}
) } export default OnDeviceStarterScreen