feat: run on startup settin for local api server

This commit is contained in:
Faisal Amir 2025-08-20 21:56:53 +07:00
parent b6cf19a33f
commit cfa68c5500
4 changed files with 141 additions and 2 deletions

View File

@ -33,7 +33,7 @@ type LocalApiServerState = {
export const useLocalApiServer = create<LocalApiServerState>()(
persist(
(set) => ({
runOnStartup: true,
runOnStartup: false,
setRunOnStartup: (value) => set({ runOnStartup: value }),
serverHost: '127.0.0.1',
setServerHost: (value) => set({ serverHost: value }),

View File

@ -160,6 +160,9 @@
"serverLogs": "Server Logs",
"serverLogsDesc": "View detailed logs of the local API server.",
"openLogs": "Open Logs",
"startupConfiguration": "Startup Configuration",
"runOnStartup": "Enable by default on startup",
"runOnStartupDesc": "Automatically start the Local API Server when the application launches.",
"serverConfiguration": "Server Configuration",
"serverHost": "Server Host",
"serverHostDesc": "Network address for the server.",

View File

@ -17,10 +17,15 @@ import {
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 { startModel } from '@/services/models'
import { localStorageKey } from '@/constants/localStorage'
export function DataProvider() {
const { setProviders } = useModelProvider()
const { setProviders, selectedModel, selectedProvider, getProviderByName } =
useModelProvider()
const { setMessages } = useMessages()
const { checkForUpdate } = useAppUpdater()
@ -29,6 +34,19 @@ export function DataProvider() {
const { setThreads } = useThreads()
const navigate = useNavigate()
// Local API Server hooks
const {
runOnStartup,
serverHost,
serverPort,
apiPrefix,
apiKey,
trustedHosts,
corsEnabled,
verboseLogs,
} = useLocalApiServer()
const { setServerStatus } = useAppState()
useEffect(() => {
console.log('Initializing DataProvider...')
getProviders().then(setProviders)
@ -78,6 +96,102 @@ export function DataProvider() {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
const getLastUsedModel = (): { provider: string; model: string } | null => {
try {
const stored = localStorage.getItem(localStorageKey.lastUsedModel)
return stored ? JSON.parse(stored) : null
} catch (error) {
console.debug('Failed to get last used model from localStorage:', error)
return null
}
}
// Helper function to determine which model to start
const getModelToStart = () => {
// Use last used model if available
const lastUsedModel = getLastUsedModel()
if (lastUsedModel) {
const provider = getProviderByName(lastUsedModel.provider)
if (
provider &&
provider.models.some((m) => m.id === lastUsedModel.model)
) {
return { model: lastUsedModel.model, provider }
}
}
// Use selected model if available
if (selectedModel && selectedProvider) {
const provider = getProviderByName(selectedProvider)
if (provider) {
return { model: selectedModel.id, provider }
}
}
// Use first model from llamacpp provider
const llamacppProvider = getProviderByName('llamacpp')
if (
llamacppProvider &&
llamacppProvider.models &&
llamacppProvider.models.length > 0
) {
return {
model: llamacppProvider.models[0].id,
provider: llamacppProvider,
}
}
return null
}
// Auto-start Local API Server on app startup if enabled
useEffect(() => {
if (runOnStartup) {
// 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()
// 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
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,
})
})
.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
}, [])
const handleDeepLink = (urls: string[] | null) => {
if (!urls) return
console.log('Received deeplink:', urls)

View File

@ -32,6 +32,8 @@ function LocalAPIServer() {
setCorsEnabled,
verboseLogs,
setVerboseLogs,
runOnStartup,
setRunOnStartup,
serverHost,
serverPort,
apiPrefix,
@ -199,6 +201,26 @@ function LocalAPIServer() {
/>
</Card>
{/* Startup Configuration */}
<Card title={t('settings:localApiServer.startupConfiguration')}>
<CardItem
title={t('settings:localApiServer.runOnStartup')}
description={t('settings:localApiServer.runOnStartupDesc')}
actions={
<Switch
checked={runOnStartup}
onCheckedChange={(checked) => {
if (!apiKey || apiKey.toString().trim().length === 0) {
setShowApiKeyError(true)
return
}
setRunOnStartup(checked)
}}
/>
}
/>
</Card>
{/* Server Configuration */}
<Card title={t('settings:localApiServer.serverConfiguration')}>
<CardItem