From 39df7b22b9521c6153cf01a3f0a57e0b8ffa7579 Mon Sep 17 00:00:00 2001 From: Faisal Amir Date: Wed, 20 Aug 2025 22:37:45 +0700 Subject: [PATCH] chore: rename key runOnStartup from hooks useLocalApiServer --- .../hooks/__tests__/useLocalApiServer.test.ts | 18 ++-- web-app/src/hooks/useLocalApiServer.ts | 8 +- web-app/src/providers/DataProvider.tsx | 4 +- .../src/routes/settings/local-api-server.tsx | 99 ++++++++++++++++--- 4 files changed, 98 insertions(+), 31 deletions(-) diff --git a/web-app/src/hooks/__tests__/useLocalApiServer.test.ts b/web-app/src/hooks/__tests__/useLocalApiServer.test.ts index 4cc15ef39..e347d2307 100644 --- a/web-app/src/hooks/__tests__/useLocalApiServer.test.ts +++ b/web-app/src/hooks/__tests__/useLocalApiServer.test.ts @@ -24,7 +24,7 @@ describe('useLocalApiServer', () => { vi.clearAllMocks() // Reset store state to defaults const store = useLocalApiServer.getState() - store.setRunOnStartup(true) + store.setEnableOnStartup(true) store.setServerHost('127.0.0.1') store.setServerPort(1337) store.setApiPrefix('/v1') @@ -37,7 +37,7 @@ describe('useLocalApiServer', () => { it('should initialize with default values', () => { const { result } = renderHook(() => useLocalApiServer()) - expect(result.current.runOnStartup).toBe(true) + expect(result.current.enableOnStartup).toBe(true) expect(result.current.serverHost).toBe('127.0.0.1') expect(result.current.serverPort).toBe(1337) expect(result.current.apiPrefix).toBe('/v1') @@ -47,21 +47,21 @@ describe('useLocalApiServer', () => { expect(result.current.apiKey).toBe('') }) - describe('runOnStartup', () => { + describe('enableOnStartup', () => { it('should set run on startup', () => { const { result } = renderHook(() => useLocalApiServer()) act(() => { - result.current.setRunOnStartup(false) + result.current.setEnableOnStartup(false) }) - expect(result.current.runOnStartup).toBe(false) + expect(result.current.enableOnStartup).toBe(false) act(() => { - result.current.setRunOnStartup(true) + result.current.setEnableOnStartup(true) }) - expect(result.current.runOnStartup).toBe(true) + expect(result.current.enableOnStartup).toBe(true) }) }) @@ -323,7 +323,7 @@ describe('useLocalApiServer', () => { const { result: result2 } = renderHook(() => useLocalApiServer()) act(() => { - result1.current.setRunOnStartup(false) + result1.current.setEnableOnStartup(false) result1.current.setServerHost('0.0.0.0') result1.current.setServerPort(8080) result1.current.setApiPrefix('/api') @@ -333,7 +333,7 @@ describe('useLocalApiServer', () => { result1.current.addTrustedHost('example.com') }) - expect(result2.current.runOnStartup).toBe(false) + expect(result2.current.enableOnStartup).toBe(false) expect(result2.current.serverHost).toBe('0.0.0.0') expect(result2.current.serverPort).toBe(8080) expect(result2.current.apiPrefix).toBe('/api') diff --git a/web-app/src/hooks/useLocalApiServer.ts b/web-app/src/hooks/useLocalApiServer.ts index 7e89bffb8..a353df75c 100644 --- a/web-app/src/hooks/useLocalApiServer.ts +++ b/web-app/src/hooks/useLocalApiServer.ts @@ -4,8 +4,8 @@ import { localStorageKey } from '@/constants/localStorage' type LocalApiServerState = { // Run local API server once app opens - runOnStartup: boolean - setRunOnStartup: (value: boolean) => void + enableOnStartup: boolean + setEnableOnStartup: (value: boolean) => void // Server host option (127.0.0.1 or 0.0.0.0) serverHost: '127.0.0.1' | '0.0.0.0' setServerHost: (value: '127.0.0.1' | '0.0.0.0') => void @@ -33,8 +33,8 @@ type LocalApiServerState = { export const useLocalApiServer = create()( persist( (set) => ({ - runOnStartup: false, - setRunOnStartup: (value) => set({ runOnStartup: value }), + enableOnStartup: false, + setEnableOnStartup: (value) => set({ enableOnStartup: value }), serverHost: '127.0.0.1', setServerHost: (value) => set({ serverHost: value }), serverPort: 1337, diff --git a/web-app/src/providers/DataProvider.tsx b/web-app/src/providers/DataProvider.tsx index cb20a21ce..baca6e213 100644 --- a/web-app/src/providers/DataProvider.tsx +++ b/web-app/src/providers/DataProvider.tsx @@ -36,7 +36,7 @@ export function DataProvider() { // Local API Server hooks const { - runOnStartup, + enableOnStartup, serverHost, serverPort, apiPrefix, @@ -146,7 +146,7 @@ export function DataProvider() { // Auto-start Local API Server on app startup if enabled useEffect(() => { - if (runOnStartup) { + 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') diff --git a/web-app/src/routes/settings/local-api-server.tsx b/web-app/src/routes/settings/local-api-server.tsx index 7de00f355..8b426ddf2 100644 --- a/web-app/src/routes/settings/local-api-server.tsx +++ b/web-app/src/routes/settings/local-api-server.tsx @@ -13,6 +13,9 @@ import { TrustedHostsInput } from '@/containers/TrustedHostsInput' import { useLocalApiServer } from '@/hooks/useLocalApiServer' import { WebviewWindow } from '@tauri-apps/api/webviewWindow' import { useAppState } from '@/hooks/useAppState' +import { useModelProvider } from '@/hooks/useModelProvider' +import { startModel } from '@/services/models' +import { localStorageKey } from '@/constants/localStorage' import { windowKey } from '@/constants/windows' import { IconLogs } from '@tabler/icons-react' import { cn } from '@/lib/utils' @@ -32,8 +35,8 @@ function LocalAPIServer() { setCorsEnabled, verboseLogs, setVerboseLogs, - runOnStartup, - setRunOnStartup, + enableOnStartup, + setEnableOnStartup, serverHost, serverPort, apiPrefix, @@ -42,6 +45,7 @@ function LocalAPIServer() { } = useLocalApiServer() const { serverStatus, setServerStatus } = useAppState() + const { selectedModel, selectedProvider, getProviderByName } = useModelProvider() const [showApiKeyError, setShowApiKeyError] = useState(false) const [isApiKeyEmpty, setIsApiKeyEmpty] = useState( !apiKey || apiKey.toString().trim().length === 0 @@ -62,6 +66,54 @@ function LocalAPIServer() { setIsApiKeyEmpty(!isValid) } + 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 + } + const toggleAPIServer = async () => { // Validate API key before starting server if (serverStatus === 'stopped') { @@ -70,19 +122,33 @@ function LocalAPIServer() { return } setShowApiKeyError(false) - } - setServerStatus('pending') - if (serverStatus === 'stopped') { - window.core?.api - ?.startServer({ - host: serverHost, - port: serverPort, - prefix: apiPrefix, - apiKey, - trustedHosts, - isCorsEnabled: corsEnabled, - isVerboseEnabled: verboseLogs, + 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') @@ -92,6 +158,7 @@ function LocalAPIServer() { setServerStatus('stopped') }) } else { + setServerStatus('pending') window.core?.api ?.stopServer() .then(() => { @@ -208,13 +275,13 @@ function LocalAPIServer() { description={t('settings:localApiServer.runOnStartupDesc')} actions={ { if (!apiKey || apiKey.toString().trim().length === 0) { setShowApiKeyError(true) return } - setRunOnStartup(checked) + setEnableOnStartup(checked) }} /> }