jan/web/containers/Providers/DataLoader.tsx
NamH 9e29fcd69e
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>
2024-08-12 19:51:58 +07:00

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