* 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>
178 lines
5.5 KiB
TypeScript
178 lines
5.5 KiB
TypeScript
'use client'
|
|
|
|
import { useEffect, useMemo } from 'react'
|
|
|
|
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'
|
|
import useModelQuery from '@/hooks/useModelQuery'
|
|
import useThreadCreateMutation from '@/hooks/useThreadCreateMutation'
|
|
import useThreadQuery from '@/hooks/useThreadQuery'
|
|
|
|
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
|
|
if (assistants.length === 0 && assistantCreateMutation.isIdle) {
|
|
// empty assistant. create new one
|
|
console.debug('Empty assistants received. Create Jan Assistant...')
|
|
assistantCreateMutation.mutate(janAssistant)
|
|
}
|
|
}, [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
|
|
const shouldCreateNewThread = isAnyRemoteModelConfigured || isAnyModelReady
|
|
|
|
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: modelToBeUsed.model,
|
|
assistant: assistant,
|
|
})
|
|
}
|
|
}, [
|
|
assistants,
|
|
models,
|
|
isFetchingThread,
|
|
threads,
|
|
createThreadMutation,
|
|
allThreads,
|
|
selectedModel,
|
|
isAnyModelReady,
|
|
isAnyRemoteModelConfigured,
|
|
engineData,
|
|
modelHubData,
|
|
setSelectedModel,
|
|
createModel,
|
|
])
|
|
|
|
useLoadTheme()
|
|
|
|
return null
|
|
}
|
|
|
|
export default DataLoader
|