186 lines
5.3 KiB
TypeScript
186 lines
5.3 KiB
TypeScript
import { useModelProvider } from '@/hooks/useModelProvider'
|
|
|
|
import { useAppUpdater } from '@/hooks/useAppUpdater'
|
|
import { useServiceHub } from '@/hooks/useServiceHub'
|
|
import { useEffect } from 'react'
|
|
import { useMCPServers } from '@/hooks/useMCPServers'
|
|
import { useAssistant } from '@/hooks/useAssistant'
|
|
import { useNavigate } from '@tanstack/react-router'
|
|
import { route } from '@/constants/routes'
|
|
import { useThreads } from '@/hooks/useThreads'
|
|
import { useLocalApiServer } from '@/hooks/useLocalApiServer'
|
|
import { useAppState } from '@/hooks/useAppState'
|
|
import { AppEvent, events } from '@janhq/core'
|
|
import { SystemEvent } from '@/types/events'
|
|
import { getModelToStart } from '@/utils/getModelToStart'
|
|
|
|
export function DataProvider() {
|
|
const { setProviders, selectedModel, selectedProvider, getProviderByName } =
|
|
useModelProvider()
|
|
|
|
const { checkForUpdate } = useAppUpdater()
|
|
const { setServers } = useMCPServers()
|
|
const { setAssistants, initializeWithLastUsed } = useAssistant()
|
|
const { setThreads } = useThreads()
|
|
const navigate = useNavigate()
|
|
const serviceHub = useServiceHub()
|
|
|
|
// Local API Server hooks
|
|
const {
|
|
enableOnStartup,
|
|
serverHost,
|
|
serverPort,
|
|
apiPrefix,
|
|
apiKey,
|
|
trustedHosts,
|
|
corsEnabled,
|
|
verboseLogs,
|
|
proxyTimeout,
|
|
} = useLocalApiServer()
|
|
const setServerStatus = useAppState((state) => state.setServerStatus)
|
|
|
|
useEffect(() => {
|
|
console.log('Initializing DataProvider...')
|
|
serviceHub.providers().getProviders().then(setProviders)
|
|
serviceHub
|
|
.mcp()
|
|
.getMCPConfig()
|
|
.then((data) => setServers(data.mcpServers ?? {}))
|
|
serviceHub
|
|
.assistants()
|
|
.getAssistants()
|
|
.then((data) => {
|
|
// Only update assistants if we have valid data
|
|
if (data && Array.isArray(data) && data.length > 0) {
|
|
setAssistants(data as unknown as Assistant[])
|
|
initializeWithLastUsed()
|
|
}
|
|
})
|
|
.catch((error) => {
|
|
console.warn('Failed to load assistants, keeping default:', error)
|
|
})
|
|
serviceHub.deeplink().getCurrent().then(handleDeepLink)
|
|
serviceHub.deeplink().onOpenUrl(handleDeepLink)
|
|
|
|
// Listen for deep link events
|
|
let unsubscribe = () => {}
|
|
serviceHub
|
|
.events()
|
|
.listen(SystemEvent.DEEP_LINK, (event) => {
|
|
const deep_link = event.payload as string
|
|
handleDeepLink([deep_link])
|
|
})
|
|
.then((unsub) => {
|
|
unsubscribe = unsub
|
|
})
|
|
return () => {
|
|
unsubscribe()
|
|
}
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [serviceHub])
|
|
|
|
useEffect(() => {
|
|
serviceHub
|
|
.threads()
|
|
.fetchThreads()
|
|
.then((threads) => {
|
|
setThreads(threads)
|
|
})
|
|
}, [serviceHub, setThreads])
|
|
|
|
// Check for app updates
|
|
useEffect(() => {
|
|
// Only check for updates if the auto updater is not disabled
|
|
// App might be distributed via other package managers
|
|
// or methods that handle updates differently
|
|
if (!AUTO_UPDATER_DISABLED) {
|
|
checkForUpdate()
|
|
}
|
|
}, [checkForUpdate])
|
|
|
|
useEffect(() => {
|
|
events.on(AppEvent.onModelImported, () => {
|
|
serviceHub.providers().getProviders().then(setProviders)
|
|
})
|
|
}, [serviceHub, setProviders])
|
|
|
|
// Auto-start Local API Server on app startup if enabled
|
|
useEffect(() => {
|
|
if (enableOnStartup) {
|
|
// Validate API key before starting
|
|
if (!apiKey || apiKey.toString().trim().length === 0) {
|
|
console.warn('Cannot start Local API Server: API key is required')
|
|
return
|
|
}
|
|
|
|
const modelToStart = getModelToStart({
|
|
selectedModel,
|
|
selectedProvider,
|
|
getProviderByName,
|
|
})
|
|
|
|
// Only start server if we have a model to load
|
|
if (!modelToStart) {
|
|
console.warn(
|
|
'Cannot start Local API Server: No model available to load'
|
|
)
|
|
return
|
|
}
|
|
|
|
setServerStatus('pending')
|
|
|
|
// Start the model first
|
|
serviceHub
|
|
.models()
|
|
.startModel(modelToStart.provider, modelToStart.model)
|
|
.then(() => {
|
|
console.log(`Model ${modelToStart.model} started successfully`)
|
|
|
|
// Then start the server
|
|
return window.core?.api?.startServer({
|
|
host: serverHost,
|
|
port: serverPort,
|
|
prefix: apiPrefix,
|
|
apiKey,
|
|
trustedHosts,
|
|
isCorsEnabled: corsEnabled,
|
|
isVerboseEnabled: verboseLogs,
|
|
proxyTimeout: proxyTimeout,
|
|
})
|
|
})
|
|
.then(() => {
|
|
setServerStatus('running')
|
|
})
|
|
.catch((error: unknown) => {
|
|
console.error('Failed to start Local API Server on startup:', error)
|
|
setServerStatus('stopped')
|
|
})
|
|
}
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [serviceHub])
|
|
|
|
const handleDeepLink = (urls: string[] | null) => {
|
|
if (!urls) return
|
|
console.log('Received deeplink:', urls)
|
|
const deeplink = urls[0]
|
|
if (deeplink) {
|
|
const url = new URL(deeplink)
|
|
const params = url.pathname.split('/').filter((str) => str.length > 0)
|
|
|
|
if (params.length < 3) return undefined
|
|
// const action = params[0]
|
|
// const provider = params[1]
|
|
const resource = params.slice(1).join('/')
|
|
// return { action, provider, resource }
|
|
navigate({
|
|
to: route.hub.model,
|
|
search: {
|
|
repo: resource,
|
|
},
|
|
})
|
|
}
|
|
}
|
|
|
|
return null
|
|
}
|