diff --git a/electron/package.json b/electron/package.json index 59761623c..e97ef4e7f 100644 --- a/electron/package.json +++ b/electron/package.json @@ -1,6 +1,6 @@ { "name": "jan", - "version": "0.1.1737985524", + "version": "0.1.1", "main": "./build/main.js", "author": "Jan ", "license": "MIT", diff --git a/extensions/inference-cortex-extension/bin/version.txt b/extensions/inference-cortex-extension/bin/version.txt index 7ee7020b3..566c2869a 100644 --- a/extensions/inference-cortex-extension/bin/version.txt +++ b/extensions/inference-cortex-extension/bin/version.txt @@ -1 +1 @@ -1.0.10 +1.0.11-rc1 diff --git a/web/containers/Loader/Spinner.tsx b/web/containers/Loader/Spinner.tsx index a5803d70f..aeeac155f 100644 --- a/web/containers/Loader/Spinner.tsx +++ b/web/containers/Loader/Spinner.tsx @@ -1,6 +1,6 @@ import { motion } from 'framer-motion' -const Spinner = ({ size = 40, strokeWidth = 4 }) => { +const Spinner = ({ size = 40, strokeWidth = 4, className = '' }) => { const radius = size / 2 - strokeWidth const circumference = 2 * Math.PI * radius @@ -11,6 +11,7 @@ const Spinner = ({ size = 40, strokeWidth = 4 }) => { viewBox={`0 0 ${size} ${size}`} style={{ overflow: 'visible' }} animate={{ rotate: 360 }} + className={className} transition={{ repeat: Infinity, duration: 2, // Adjust for desired speed diff --git a/web/hooks/useEngineManagement.ts b/web/hooks/useEngineManagement.ts index b08004c4e..96fa281e9 100644 --- a/web/hooks/useEngineManagement.ts +++ b/web/hooks/useEngineManagement.ts @@ -1,4 +1,4 @@ -import { useMemo } from 'react' +import { useCallback, useMemo, useState } from 'react' import { ExtensionTypeEnum, @@ -32,6 +32,13 @@ export const releasedEnginesLatestCacheAtom = atomWithStorage<{ timestamp: number } | null>('releasedEnginesLatestCache', null, undefined, { getOnInit: true }) +export interface RemoteModelList { + data?: { + id?: string + name?: string + }[] +} + // fetcher function async function fetchExtensionData( extension: EngineManagementExtension | null, @@ -88,8 +95,12 @@ export function useGetRemoteModels(name: string) { error, mutate, } = useSWR( - extension ? 'remoteModels' : null, - () => fetchExtensionData(extension, (ext) => ext.getRemoteModels(name)), + extension ? `remoteModels_${name}` : null, + () => + fetchExtensionData( + extension, + (ext) => ext.getRemoteModels(name) as Promise + ), { revalidateOnFocus: false, revalidateOnReconnect: true, @@ -456,3 +467,30 @@ export const useGetEngineModelSources = () => { ), } } + +/** + * Refresh model list + * @param engine + * @returns + */ +export const useRefreshModelList = (engine: string) => { + const [refreshingModels, setRefreshingModels] = useState(false) + const { mutate: fetchRemoteModels } = useGetRemoteModels(engine) + + const refreshModels = useCallback(() => { + setRefreshingModels(true) + fetchRemoteModels() + .then((remoteModelList) => + Promise.all( + remoteModelList?.data?.map((model: { id?: string }) => + model?.id + ? addRemoteEngineModel(model.id, engine).catch(() => {}) + : {} + ) ?? [] + ) + ) + .finally(() => setRefreshingModels(false)) + }, [fetchRemoteModels]) + + return { refreshingModels, refreshModels } +} diff --git a/web/package.json b/web/package.json index 63dde8c05..1232b96c1 100644 --- a/web/package.json +++ b/web/package.json @@ -1,6 +1,6 @@ { "name": "@janhq/web", - "version": "0.5.13", + "version": "0.5.15", "private": true, "homepage": "./", "scripts": { diff --git a/web/screens/Hub/ModelPage/index.tsx b/web/screens/Hub/ModelPage/index.tsx index d4c8d6d6a..e0288c687 100644 --- a/web/screens/Hub/ModelPage/index.tsx +++ b/web/screens/Hub/ModelPage/index.tsx @@ -7,13 +7,17 @@ import { ArrowLeftIcon, DownloadIcon, FileJson, + RefreshCwIcon, SettingsIcon, } from 'lucide-react' +import Spinner from '@/containers/Loader/Spinner' import ModelDownloadButton from '@/containers/ModelDownloadButton' import { MainViewState } from '@/constants/screens' +import { useRefreshModelList } from '@/hooks/useEngineManagement' + import { MarkdownTextMessage } from '@/screens/Thread/ThreadCenterPanel/TextMessage/MarkdownTextMessage' import { toGigabytes } from '@/utils/converter' @@ -30,6 +34,8 @@ type Props = { const ModelPage = ({ model, onGoBack }: Props) => { const setSelectedSetting = useSetAtom(selectedSettingAtom) const setMainViewState = useSetAtom(mainViewStateAtom) + const { refreshingModels, refreshModels } = useRefreshModelList(model.id) + return (
@@ -127,7 +133,7 @@ const ModelPage = ({ model, onGoBack }: Props) => { - {model.type !== 'cloud' && ( @@ -140,7 +146,27 @@ const ModelPage = ({ model, onGoBack }: Props) => { )} - + diff --git a/web/screens/Settings/Engines/RemoteEngineSettings.tsx b/web/screens/Settings/Engines/RemoteEngineSettings.tsx index acc3fac69..f9197b157 100644 --- a/web/screens/Settings/Engines/RemoteEngineSettings.tsx +++ b/web/screens/Settings/Engines/RemoteEngineSettings.tsx @@ -15,15 +15,27 @@ interface EngineConfig extends OriginalEngineConfig { [key: string]: any } -import { ScrollArea, Input, TextArea } from '@janhq/joi' +import { ScrollArea, Input, TextArea, Button } from '@janhq/joi' import { useAtomValue, useSetAtom } from 'jotai' import { set } from 'lodash' -import { ChevronDown, ChevronRight, Eye, EyeOff } from 'lucide-react' +import { + ChevronDown, + ChevronRight, + Eye, + EyeOff, + RefreshCwIcon, +} from 'lucide-react' import { twMerge } from 'tailwind-merge' -import { updateEngine, useGetEngines } from '@/hooks/useEngineManagement' +import Spinner from '@/containers/Loader/Spinner' + +import { + updateEngine, + useGetEngines, + useRefreshModelList, +} from '@/hooks/useEngineManagement' import { getTitleByEngine } from '@/utils/modelEngine' @@ -51,6 +63,7 @@ const RemoteEngineSettings = ({ const setSelectedModel = useSetAtom(selectedModelAtom) const customEngineLogo = getLogoEngine(name) const threads = useAtomValue(threadsAtom) + const { refreshingModels, refreshModels } = useRefreshModelList(name) const engine = engines && @@ -214,7 +227,21 @@ const RemoteEngineSettings = ({
Model
- +
+ + +
+ {model.type !== 'cloud' ? 'Version' : 'Models'} + {model.type === 'cloud' && ( + + )} +