fix: empty model page not shown when delete all threads and models (#3343)

* fix: empty model page not shown when delete all threads and models

* fix: blank state when delete jan data folder content (#3345)

* test template name

---------

Co-authored-by: Van Pham <64197333+Van-QA@users.noreply.github.com>
This commit is contained in:
NamH 2024-08-12 19:51:58 +07:00 committed by GitHub
parent fdab8af057
commit 9e29fcd69e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 239 additions and 101 deletions

View File

@ -1,5 +1,5 @@
---
name: Bug report
name: _Bug report
about: Create a report to help us improve Jan
title: 'bug: [DESCRIPTION]'
labels: 'type: bug'

View File

@ -1,11 +1,21 @@
'use client'
import { useEffect } from 'react'
import { useEffect, useMemo } from 'react'
import { useAtomValue } from 'jotai'
import { Engine } from '@cortexso/cortex.js/resources'
import {
EngineStatus,
LocalEngine,
LocalEngines,
Model,
RemoteEngine,
RemoteEngines,
} from '@janhq/core'
import { useAtomValue, useSetAtom } from 'jotai'
import useAssistantCreate, { janAssistant } from '@/hooks/useAssistantCreate'
import useAssistantQuery from '@/hooks/useAssistantQuery'
import useCortex from '@/hooks/useCortex'
import useEngineQuery from '@/hooks/useEngineQuery'
import { useLoadTheme } from '@/hooks/useLoadTheme'
import useModelHub from '@/hooks/useModelHub'
@ -13,17 +23,24 @@ import useModelQuery from '@/hooks/useModelQuery'
import useThreadCreateMutation from '@/hooks/useThreadCreateMutation'
import useThreadQuery from '@/hooks/useThreadQuery'
import { getSelectedModelAtom } from '@/helpers/atoms/Model.atom'
import {
getSelectedModelAtom,
updateSelectedModelAtom,
} from '@/helpers/atoms/Model.atom'
import { threadsAtom } from '@/helpers/atoms/Thread.atom'
const DataLoader: React.FC = () => {
const selectedModel = useAtomValue(getSelectedModelAtom)
const setSelectedModel = useSetAtom(updateSelectedModelAtom)
const allThreads = useAtomValue(threadsAtom)
const { data: assistants } = useAssistantQuery()
const { data: models } = useModelQuery()
const { data: threads, isLoading: isFetchingThread } = useThreadQuery()
const { data: engineData } = useEngineQuery()
const { data: modelHubData } = useModelHub()
const createThreadMutation = useThreadCreateMutation()
const assistantCreateMutation = useAssistantCreate()
const { createModel } = useCortex()
useEffect(() => {
if (!assistants) return
@ -34,19 +51,105 @@ const DataLoader: React.FC = () => {
}
}, [assistants, assistantCreateMutation])
const isAnyRemoteModelConfigured = useMemo(() => {
if (!engineData) return false
let result = false
for (const engine of engineData) {
if (RemoteEngines.includes(engine.name as RemoteEngine)) {
if (engine.status === EngineStatus.Ready) {
result = true
}
}
}
return result
}, [engineData])
const isAnyModelReady = useMemo(() => {
if (!models) return false
return models.length > 0
}, [models])
// automatically create new thread if thread list is empty
useEffect(() => {
if (isFetchingThread) return
if (allThreads.length > 0) return
if (!assistants || assistants.length === 0) return
if (!models || models.length === 0) return
if (allThreads.length === 0 && !createThreadMutation.isPending) {
const model = selectedModel ?? models[0]
const assistant = assistants[0]
const shouldCreateNewThread = isAnyRemoteModelConfigured || isAnyModelReady
console.log('Create new thread because user have no thread')
if (shouldCreateNewThread && !createThreadMutation.isPending) {
// if we already have selected model then can safely proceed
if (selectedModel) {
const assistant = assistants[0]
console.debug(
'Create new thread because user have no thread, with selected model',
selectedModel.model
)
createThreadMutation.mutate({
modelId: selectedModel.model,
assistant: assistant,
})
return
}
let modelToBeUsed: Model | undefined = undefined
// if we have a model registered already, try to use it and prioritize local model
if (models && models.length > 0) {
for (const model of models) {
if (!model.engine) continue
if (LocalEngines.includes(model.engine as LocalEngine)) {
modelToBeUsed = model
}
}
// if we don't have it, then just take the first one
if (!modelToBeUsed) {
modelToBeUsed = models[0]
}
} else {
if (!engineData) return
// we don't have nay registered model, so will need to check the remote engine
const remoteEngineReadyList: Engine[] = []
for (const engine of engineData) {
if (RemoteEngines.includes(engine.name as RemoteEngine)) {
if (engine.status === EngineStatus.Ready) {
remoteEngineReadyList.push(engine)
}
}
}
if (remoteEngineReadyList.length === 0) {
console.debug("No remote engine ready, can't create thread")
return
}
// find the model from hub that using the engine
if (!modelHubData) return
const remoteEngineReadyNames = remoteEngineReadyList.map((e) => e.name)
console.log('remoteEngineReady:', remoteEngineReadyNames)
// loop through the modelHubData.modelCategories to find the model that using the engine
for (const [key, value] of modelHubData.modelCategories) {
if (remoteEngineReadyNames.includes(key) && value.length > 0) {
modelToBeUsed = value[0].model
if (modelToBeUsed) break
}
}
}
if (!modelToBeUsed) {
console.debug('No model to be used')
return
}
console.log(
'Create new thread because user have no thread, model to be used:',
modelToBeUsed.model
)
createModel(modelToBeUsed)
setSelectedModel(modelToBeUsed)
const assistant = assistants[0]
createThreadMutation.mutate({
modelId: model.id,
modelId: modelToBeUsed.model,
assistant: assistant,
})
}
@ -58,11 +161,15 @@ const DataLoader: React.FC = () => {
createThreadMutation,
allThreads,
selectedModel,
isAnyModelReady,
isAnyRemoteModelConfigured,
engineData,
modelHubData,
setSelectedModel,
createModel,
])
useModelHub()
useLoadTheme()
useEngineQuery()
return null
}

View File

@ -2,11 +2,12 @@ import { useCallback, useEffect, useRef } from 'react'
import { DownloadState2 } from '@janhq/core'
import { fetchEventSource } from '@microsoft/fetch-event-source'
import { useQueryClient } from '@tanstack/react-query'
import { useAtomValue, useSetAtom } from 'jotai'
import { downloadStateListAtom } from '@/hooks/useDownloadState'
import useModels from '@/hooks/useModels'
import { modelQueryKey } from '@/hooks/useModelQuery'
import { waitingForCortexAtom } from '@/helpers/atoms/App.atom'
import { hostAtom } from '@/helpers/atoms/AppConfig.atom'
@ -21,12 +22,12 @@ const DownloadEventListener: React.FC = () => {
const abortController = useRef(new AbortController())
const setDownloadStateList = useSetAtom(downloadStateListAtom)
const setWaitingForCortex = useSetAtom(waitingForCortexAtom)
const { getModels } = useModels()
const updateImportingModelProgress = useSetAtom(
updateImportingModelProgressAtom
)
const setImportingModelSuccess = useSetAtom(setImportingModelSuccessAtom)
const queryClient = useQueryClient()
const handleLocalImportModels = useCallback(
(events: DownloadState2[]) => {
@ -38,9 +39,10 @@ const DownloadEventListener: React.FC = () => {
updateImportingModelProgress(event.id, event.progress)
}
}
getModels()
queryClient.invalidateQueries({ queryKey: modelQueryKey })
},
[setImportingModelSuccess, updateImportingModelProgress, getModels]
[setImportingModelSuccess, updateImportingModelProgress, queryClient]
)
const subscribeDownloadEvent = useCallback(async () => {
@ -54,7 +56,6 @@ const DownloadEventListener: React.FC = () => {
const localImportEvents: DownloadState2[] = []
// filter out the import local events
for (const event of downloadEvents) {
console.debug('Receiving event', event)
if (
isAbsolutePath(event.id) &&
event.type === 'model' &&

View File

@ -2,6 +2,7 @@ import React, { Fragment, useCallback, useMemo, useState } from 'react'
import { Button, Modal, Badge } from '@janhq/joi'
import { useQueryClient } from '@tanstack/react-query'
import { atom, useAtom, useSetAtom } from 'jotai'
import { AlertTriangleIcon } from 'lucide-react'
@ -11,7 +12,7 @@ import Spinner from '@/containers/Loader/Spinner'
import useMigratingData from '@/hooks/useMigratingData'
import useModels from '@/hooks/useModels'
import { modelQueryKey } from '@/hooks/useModelQuery'
import { didShowMigrationWarningAtom } from '@/helpers/atoms/AppConfig.atom'
@ -31,7 +32,7 @@ const ModalMigrations = () => {
useState<MigrationState>('idle')
const [modelMigrationState, setModelMigrationState] =
useState<MigrationState>('idle')
const { getModels } = useModels()
const queryClient = useQueryClient()
const getStepTitle = () => {
switch (step) {
@ -74,8 +75,8 @@ const ModalMigrations = () => {
setStep(2)
await migratingModels()
await migrationThreadsAndMessages()
getModels()
}, [migratingModels, migrationThreadsAndMessages, getModels])
queryClient.invalidateQueries({ queryKey: modelQueryKey })
}, [migratingModels, migrationThreadsAndMessages, queryClient])
const onDismiss = useCallback(() => {
setStep(1)

View File

@ -7,10 +7,11 @@ import {
StatusAndEvent,
} from '@janhq/core'
import { fetchEventSource } from '@microsoft/fetch-event-source'
import { useQueryClient } from '@tanstack/react-query'
import { useAtomValue, useSetAtom } from 'jotai'
import { removeDownloadSuccessItemAtom } from '@/hooks/useDownloadState'
import useModels from '@/hooks/useModels'
import { modelQueryKey } from '@/hooks/useModelQuery'
import { toaster } from '../Toast'
@ -25,7 +26,7 @@ function ModelEventListener() {
const removeDownloadSuccessItem = useSetAtom(removeDownloadSuccessItemAtom)
const setIsLoadingModel = useSetAtom(isLoadingModelAtom)
const { getModels } = useModels()
const queryClient = useQueryClient()
const handleModelEvent = useCallback(
(modelEvent: ModelEvent) => {
@ -64,11 +65,11 @@ function ModelEventListener() {
case 'model-downloaded':
removeDownloadSuccessItem(modelEvent.model)
getModels()
queryClient.invalidateQueries({ queryKey: modelQueryKey })
break
case 'model-deleted':
getModels()
queryClient.invalidateQueries({ queryKey: modelQueryKey })
break
case 'stopping-failed':
@ -84,7 +85,7 @@ function ModelEventListener() {
break
}
},
[getModels, removeDownloadSuccessItem, setIsLoadingModel]
[removeDownloadSuccessItem, setIsLoadingModel, queryClient]
)
const subscribeModelEvent = useCallback(async () => {

View File

@ -1,14 +1,8 @@
import { RemoteEngine } from '@janhq/core'
import { atom } from 'jotai'
import { atomWithStorage } from 'jotai/utils'
export type SetupRemoteModelStage = 'NONE' | 'SETUP_INTRO' | 'SETUP_API_KEY'
const IS_ANY_REMOTE_MODEL_CONFIGURED = 'isAnyRemoteModelConfigured'
export const isAnyRemoteModelConfiguredAtom = atomWithStorage(
IS_ANY_REMOTE_MODEL_CONFIGURED,
false
)
const remoteModelSetUpStageAtom = atom<SetupRemoteModelStage>('NONE')
const engineBeingSetUpAtom = atom<RemoteEngine | undefined>(undefined)
const remoteEngineBeingSetUpMetadataAtom = atom<

View File

@ -168,11 +168,14 @@ const useModelHub = () => {
results[1].data.forEach((modelEntry) => {
const engine = modelEntry.engine
if (modelEntry.remoteModel === true && engine) {
// @ts-expect-error ignore
data.modelCategories[engine] = data.modelCategories[engine]
? // @ts-expect-error ignore
[...data.modelCategories[engine], modelEntry]
: [modelEntry]
if (data.modelCategories.has(engine)) {
data.modelCategories.set(
engine,
data.modelCategories.get(engine)!.concat(modelEntry)
)
} else {
data.modelCategories.set(engine, [modelEntry])
}
}
})
}

View File

@ -6,27 +6,12 @@ import { toaster } from '@/containers/Toast'
import useCortex from './useCortex'
import {
downloadedModelsAtom,
removeDownloadedModelAtom,
} from '@/helpers/atoms/Model.atom'
import { removeDownloadedModelAtom } from '@/helpers/atoms/Model.atom'
const useModels = () => {
const setDownloadedModels = useSetAtom(downloadedModelsAtom)
const removeDownloadedModel = useSetAtom(removeDownloadedModelAtom)
const {
fetchModels,
deleteModel: cortexDeleteModel,
updateModel: cortexUpdateModel,
} = useCortex()
const getModels = useCallback(() => {
const getDownloadedModels = async () => {
const models = await fetchModels()
setDownloadedModels(models)
}
getDownloadedModels()
}, [setDownloadedModels, fetchModels])
const { deleteModel: cortexDeleteModel, updateModel: cortexUpdateModel } =
useCortex()
const deleteModel = useCallback(
async (modelId: string) => {
@ -48,7 +33,7 @@ const useModels = () => {
[cortexUpdateModel]
)
return { getModels, deleteModel, updateModel }
return { deleteModel, updateModel }
}
export default useModels

View File

@ -3,6 +3,7 @@ import React, { useCallback, useMemo } from 'react'
import { EngineStatus, LocalEngines, RemoteEngine } from '@janhq/core'
import { Button } from '@janhq/joi'
import { useQueryClient } from '@tanstack/react-query'
import { useAtomValue, useSetAtom } from 'jotai'
import { CloudDownload } from 'lucide-react'
@ -14,7 +15,7 @@ import useAssistantQuery from '@/hooks/useAssistantQuery'
import useCortex from '@/hooks/useCortex'
import useEngineQuery from '@/hooks/useEngineQuery'
import useModels from '@/hooks/useModels'
import { modelQueryKey } from '@/hooks/useModelQuery'
import useThreads from '@/hooks/useThreads'
import { HfModelEntry } from '@/utils/huggingface'
@ -32,6 +33,7 @@ const HubModelCard: React.FC<HfModelEntry> = ({ name, downloads, model }) => {
const downloadedModels = useAtomValue(downloadedModelsAtom)
const { data: assistants } = useAssistantQuery()
const { data: engineData } = useEngineQuery()
const queryClient = useQueryClient()
const setUpRemoteModelStage = useSetAtom(setUpRemoteModelStageAtom)
const setLocalModelModalStage = useSetAtom(localModelModalStageAtom)
@ -39,7 +41,6 @@ const HubModelCard: React.FC<HfModelEntry> = ({ name, downloads, model }) => {
const { createThread } = useThreads()
const setMainViewState = useSetAtom(mainViewStateAtom)
const { createModel } = useCortex()
const { getModels } = useModels()
const isLocalModel = useMemo(
() =>
@ -131,13 +132,12 @@ const HubModelCard: React.FC<HfModelEntry> = ({ name, downloads, model }) => {
if (isApiKeyAdded) {
createModel(model).then(() => {
getModels()
queryClient.invalidateQueries({ queryKey: modelQueryKey })
})
return
}
}
}, [
getModels,
createModel,
createThread,
setMainViewState,
@ -149,6 +149,7 @@ const HubModelCard: React.FC<HfModelEntry> = ({ name, downloads, model }) => {
isLocalModel,
downloadedModels,
assistants,
queryClient,
])
const owner = model?.metadata?.owned_by ?? ''

View File

@ -1,6 +1,8 @@
import React, { useCallback } from 'react'
import { EngineStatus, RemoteEngine } from '@janhq/core'
import { useQueryClient } from '@tanstack/react-query'
import { useAtomValue, useSetAtom } from 'jotai'
import { toaster } from '@/containers/Toast'
@ -10,7 +12,7 @@ import useAssistantQuery from '@/hooks/useAssistantQuery'
import useCortex from '@/hooks/useCortex'
import useEngineQuery from '@/hooks/useEngineQuery'
import useModels from '@/hooks/useModels'
import { modelQueryKey } from '@/hooks/useModelQuery'
import useThreads from '@/hooks/useThreads'
import { HfModelEntry } from '@/utils/huggingface'
@ -23,12 +25,11 @@ const RemoteModelCard: React.FC<HfModelEntry> = ({ name, model }) => {
const { createThread } = useThreads()
const setMainViewState = useSetAtom(mainViewStateAtom)
const setUpRemoteModelStage = useSetAtom(setUpRemoteModelStageAtom)
const queryClient = useQueryClient()
const { createModel } = useCortex()
const { getModels } = useModels()
const downloadedModels = useAtomValue(downloadedModelsAtom)
const { data: assistants } = useAssistantQuery()
const { data: engineData } = useEngineQuery()
const modelDisplayName = model?.name ?? name
@ -85,7 +86,7 @@ const RemoteModelCard: React.FC<HfModelEntry> = ({ name, model }) => {
if (isApiKeyAdded) {
// TODO: useMutation reactQuery?
await createModel(model)
getModels()
queryClient.invalidateQueries({ queryKey: modelQueryKey })
if (!assistants || assistants.length === 0) {
toaster({
title: 'No assistant available.',
@ -109,11 +110,11 @@ const RemoteModelCard: React.FC<HfModelEntry> = ({ name, model }) => {
createModel,
createThread,
downloadedModels,
getModels,
model,
setMainViewState,
setUpRemoteModelStage,
modelDisplayName,
queryClient,
])
return (

View File

@ -4,7 +4,7 @@ import Image from 'next/image'
import { EngineStatus } from '@janhq/core'
import { Button, Input, Modal } from '@janhq/joi'
import { useAtom, useSetAtom } from 'jotai'
import { useAtom } from 'jotai'
import { ArrowUpRight } from 'lucide-react'
import useEngineMutation from '@/hooks/useEngineMutation'
@ -12,13 +12,10 @@ import useEngineQuery from '@/hooks/useEngineQuery'
import { getTitleByCategory } from '@/utils/model-engine'
import { isAnyRemoteModelConfiguredAtom } from '@/helpers/atoms/SetupRemoteModel.atom'
import { setUpRemoteModelStageAtom } from '@/helpers/atoms/SetupRemoteModel.atom'
const SetUpApiKeyModal: React.FC = () => {
const updateEngineConfig = useEngineMutation()
const isAnyRemoteModelConfigured = useSetAtom(isAnyRemoteModelConfiguredAtom)
const { data: engineData } = useEngineQuery()
const [{ stage, remoteEngine, metadata }, setUpRemoteModelStage] = useAtom(
@ -50,8 +47,7 @@ const SetUpApiKeyModal: React.FC = () => {
value: apiKey,
},
})
isAnyRemoteModelConfigured(true)
}, [remoteEngine, updateEngineConfig, apiKey, isAnyRemoteModelConfigured])
}, [remoteEngine, updateEngineConfig, apiKey])
const onDismiss = useCallback(() => {
setUpRemoteModelStage('NONE', undefined)

View File

@ -44,11 +44,11 @@ const HubScreen2: React.FC = () => {
if (!data) return <div>Failed to fetch models</div>
const engineModelMap = new Map<typeof RemoteEngines, HfModelEntry[]>()
Object.entries(data.modelCategories).forEach(([key, value]) => {
for (const [key, value] of data.modelCategories) {
if (key !== 'HuggingFace' && key !== 'BuiltInModels') {
engineModelMap.set(key as unknown as typeof RemoteEngines, value)
}
})
}
if (detailCategory) {
return (

View File

@ -21,6 +21,7 @@ import { twMerge } from 'tailwind-merge'
import { toaster } from '@/containers/Toast'
import useAssistantQuery from '@/hooks/useAssistantQuery'
import useEngineInit from '@/hooks/useEngineInit'
import useEngineQuery from '@/hooks/useEngineQuery'
import useModelStart from '@/hooks/useModelStart'
import useModelStop from '@/hooks/useModelStop'
@ -54,6 +55,7 @@ const ModelItem: React.FC<Props> = ({ model }) => {
const isEngineReady =
engineData?.find((e) => e.name === model.engine)?.status ===
EngineStatus.Ready
const initializeEngine = useEngineInit()
const [menu, setMenu] = useState<HTMLDivElement | null>(null)
const [toggle, setToggle] = useState<HTMLDivElement | null>(null)
@ -74,6 +76,46 @@ const ModelItem: React.FC<Props> = ({ model }) => {
stopModel.mutate(modelId)
return
}
const modelEngine = model.engine
if (!modelEngine) {
toaster({
title: 'Failed to start model',
description: `Engine for model ${model.model} is undefined`,
type: 'error',
})
return
}
if (!engineData) {
toaster({
title: 'Failed to start model',
description: `Engine data is not available. Please try again!`,
type: 'error',
})
return
}
const engineStatus = engineData.find((e) => e.name === modelEngine)
if (!engineStatus) {
toaster({
title: 'Failed to start model',
description: `Engine ${modelEngine} is not available`,
type: 'error',
})
console.error(`Engine ${modelEngine} is not available`)
return
}
if (
LocalEngines.find((e) => e === modelEngine) != null &&
engineStatus.status === 'not_initialized'
) {
toaster({
title: 'Please wait for engine to initialize',
description: `Please retry after engine ${engineStatus.name} is installed.`,
type: 'default',
})
initializeEngine.mutate(modelEngine)
return
}
if (activeModels.length >= concurrentModelWarningThreshold) {
// if max concurrent models reached, stop the first model
@ -88,6 +130,9 @@ const ModelItem: React.FC<Props> = ({ model }) => {
stopModel,
activeModels.length,
setShowWarningMultipleModelModal,
engineData,
initializeEngine,
model,
]
)

View File

@ -53,11 +53,11 @@ const OnDeviceStarterScreen = () => {
data.modelCategories.get('HuggingFace') || []
const engineModelMap = new Map<typeof RemoteEngines, HfModelEntry[]>()
Object.entries(data.modelCategories).forEach(([key, value]) => {
for (const [key, value] of data.modelCategories) {
if (key !== 'HuggingFace' && key !== 'BuiltInModels') {
engineModelMap.set(key as unknown as typeof RemoteEngines, value)
}
})
}
const models: HfModelEntry[] = builtInModels.concat(huggingFaceModels)

View File

@ -1,10 +1,14 @@
import { Fragment, useEffect } from 'react'
import { Fragment, useMemo } from 'react'
import { Model } from '@janhq/core'
import { useAtom, useAtomValue } from 'jotai'
import {
EngineStatus,
LlmEngine,
RemoteEngine,
RemoteEngines,
} from '@janhq/core'
import { useAtomValue } from 'jotai'
import useCortex from '@/hooks/useCortex'
import useModels from '@/hooks/useModels'
import useEngineQuery from '@/hooks/useEngineQuery'
import ThreadLeftPanel from '@/screens/Thread/ThreadLeftPanel'
@ -14,43 +18,44 @@ import ThreadRightPanel from './ThreadRightPanel'
import { waitingForCortexAtom } from '@/helpers/atoms/App.atom'
import { downloadedModelsAtom } from '@/helpers/atoms/Model.atom'
import {
isAnyRemoteModelConfiguredAtom,
setUpRemoteModelStageAtom,
} from '@/helpers/atoms/SetupRemoteModel.atom'
const ThreadScreen = () => {
const downloadedModels = useAtomValue(downloadedModelsAtom)
const waitingForCortex = useAtomValue(waitingForCortexAtom)
const isAnyRemoteModelConfigured = useAtomValue(
isAnyRemoteModelConfiguredAtom
)
const { createModel } = useCortex()
const { getModels } = useModels()
const { data: engineData } = useEngineQuery()
const [{ metadata }] = useAtom(setUpRemoteModelStageAtom)
const isAnyRemoteModelConfigured = useMemo(() => {
if (!engineData) return false
useEffect(() => {
if (isAnyRemoteModelConfigured) {
createModel(metadata?.model as Model)
getModels()
let result = false
for (const engine of engineData) {
if (RemoteEngines.includes(engine.name as RemoteEngine)) {
if (engine.status === EngineStatus.Ready) {
result = true
}
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isAnyRemoteModelConfigured])
return result
}, [engineData])
const shouldShowEmptyModel = useMemo(
() => !downloadedModels.length && !isAnyRemoteModelConfigured,
[downloadedModels, isAnyRemoteModelConfigured]
)
if (waitingForCortex) return null
return (
<div className="relative flex h-full w-full flex-1 overflow-x-hidden">
{!downloadedModels.length && !isAnyRemoteModelConfigured ? (
{shouldShowEmptyModel ? (
<EmptyModel />
) : (
<Fragment>
<ThreadLeftPanel />
<ThreadCenterPanel />
<ThreadRightPanel />
</Fragment>
)}
<ThreadRightPanel />
</div>
)
}

View File

@ -106,7 +106,6 @@ export const fetchCortexHubModels = async (): Promise<HfModelEntry[]> => {
}
}
}
return modelEntries
}
@ -333,9 +332,8 @@ export const fetchHuggingFaceRepoData = async (
return data
}
// TODO: move this to somewhere else
export interface HfModelEntry extends ModelEntry {
model?: Model // TODO: deprecated this
model?: Model
remoteModel?: boolean
engine?: LlmEngine
}