From 66a710dc95dcb4e8807d7df8a45d05843d9cdac6 Mon Sep 17 00:00:00 2001 From: lone-cloud Date: Fri, 29 Aug 2025 16:32:22 -0700 Subject: [PATCH] less verbone frontend error handling, better process killing for windows, better loading behaviour for available backends --- src/App.tsx | 64 ++++--------- src/components/UpdateAvailableModal.tsx | 12 +-- src/components/screens/Download.tsx | 14 +-- .../screens/Interface/TerminalTab.tsx | 6 +- src/components/screens/Launch/AdvancedTab.tsx | 31 +++--- .../Launch/GeneralTab/BackendSelector.tsx | 28 +++--- src/components/screens/Launch/index.tsx | 62 +++++------- src/components/settings/GeneralTab.tsx | 95 ++++++++----------- src/components/settings/VersionsTab.tsx | 51 ++++------ src/constants/index.ts | 5 + src/main/ipc.ts | 47 ++++----- src/main/managers/KoboldCppManager.ts | 49 +++++++++- src/main/managers/LogManager.ts | 4 +- src/main/managers/SillyTavernManager.ts | 87 +++++++++-------- src/main/managers/WindowManager.ts | 2 +- src/main/services/HardwareService.ts | 5 +- src/utils/logger.ts | 56 +++++++++++ src/utils/process.ts | 78 +++++++++++---- 18 files changed, 376 insertions(+), 320 deletions(-) create mode 100644 src/utils/logger.ts diff --git a/src/App.tsx b/src/App.tsx index 89385bc..38d4dda 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -12,6 +12,7 @@ import { AppHeader } from '@/components/AppHeader'; import { useUpdateChecker } from '@/hooks/useUpdateChecker'; import { useKoboldVersions } from '@/hooks/useKoboldVersions'; import { UI } from '@/constants'; +import { Logger } from '@/utils/logger'; import type { DownloadItem } from '@/types/electron'; import type { InterfaceTab, FrontendPreference, Screen } from '@/types'; @@ -45,7 +46,7 @@ export const App = () => { useEffect(() => { const checkInstallation = async () => { - try { + await Logger.safeExecute(async () => { const [versions, currentBinaryPath, hasSeenWelcome, preference] = await Promise.all([ window.electronAPI.kobold.getInstalledVersions(), @@ -81,20 +82,14 @@ export const App = () => { setCurrentScreenWithTransition('download'); } - setHasInitialized(true); - if (versions.length > 0) { setTimeout(() => { checkForUpdates(); }, 2000); } - } catch (error) { - window.electronAPI.logs.logError( - 'Error checking installation:', - error as Error - ); - setHasInitialized(true); - } + }, 'Error checking installation:'); + + setHasInitialized(true); }; checkInstallation(); @@ -102,7 +97,7 @@ export const App = () => { }, []); const handleBinaryUpdate = async (download: DownloadItem) => { - try { + await Logger.safeExecute(async () => { const success = await sharedHandleDownload({ type: 'asset', item: download, @@ -113,16 +108,11 @@ export const App = () => { if (success) { dismissUpdate(); } - } catch (error) { - window.electronAPI.logs.logError( - 'Failed to update binary:', - error as Error - ); - } + }, 'Failed to update binary:'); }; const handleDownloadComplete = async () => { - try { + await Logger.safeExecute(async () => { const [versions, currentBinaryPath] = await Promise.all([ window.electronAPI.kobold.getInstalledVersions(), window.electronAPI.config.get('currentKoboldBinary') as Promise, @@ -143,12 +133,7 @@ export const App = () => { } } } - } catch (error) { - window.electronAPI.logs.logError( - 'Error refreshing versions after download:', - error as Error - ); - } + }, 'Error refreshing versions after download:'); setTimeout(() => { setCurrentScreenWithTransition('launch'); @@ -176,16 +161,8 @@ export const App = () => { } }; - const performEject = async () => { - try { - await window.electronAPI.kobold.stopKoboldCpp(); - } catch (error) { - window.electronAPI.logs.logError( - 'Error stopping KoboldCpp:', - error as Error - ); - } - + const performEject = () => { + window.electronAPI.kobold.stopKoboldCpp(); handleBackToLaunch(); }; @@ -302,17 +279,14 @@ export const App = () => { opened={settingsOpened} onClose={async () => { setSettingsOpened(false); - try { - const preference = (await window.electronAPI.config.get( - 'frontendPreference' - )) as FrontendPreference; - setFrontendPreference(preference || 'koboldcpp'); - } catch (error) { - window.electronAPI.logs.logError( - 'Failed to load frontend preference:', - error as Error - ); - } + const preference = await Logger.safeExecute( + () => + window.electronAPI.config.get( + 'frontendPreference' + ) as Promise, + 'Failed to load frontend preference:' + ); + setFrontendPreference(preference || 'koboldcpp'); }} currentScreen={currentScreen || undefined} /> diff --git a/src/components/UpdateAvailableModal.tsx b/src/components/UpdateAvailableModal.tsx index 4095d55..4726997 100644 --- a/src/components/UpdateAvailableModal.tsx +++ b/src/components/UpdateAvailableModal.tsx @@ -14,6 +14,7 @@ import { useState } from 'react'; import type { InstalledVersion, DownloadItem } from '@/types/electron'; import { getDisplayNameFromPath } from '@/utils/version'; import { GITHUB_API } from '@/constants'; +import { Logger } from '@/utils/logger'; interface UpdateAvailableModalProps { opened: boolean; @@ -37,15 +38,12 @@ export const UpdateAvailableModal = ({ const [isUpdating, setIsUpdating] = useState(false); const handleUpdate = async () => { - try { - setIsUpdating(true); + setIsUpdating(true); + await Logger.safeExecute(async () => { await onUpdate(availableUpdate); onClose(); - } catch (error) { - window.electronAPI.logs.logError('Failed to update:', error as Error); - } finally { - setIsUpdating(false); - } + }, 'Failed to update:'); + setIsUpdating(false); }; return ( diff --git a/src/components/screens/Download.tsx b/src/components/screens/Download.tsx index 4834504..66ef526 100644 --- a/src/components/screens/Download.tsx +++ b/src/components/screens/Download.tsx @@ -5,6 +5,7 @@ import { getPlatformDisplayName } from '@/utils/platform'; import { formatDownloadSize } from '@/utils/download'; import { getAssetDescription, sortDownloadsByType } from '@/utils/assets'; import { useKoboldVersions } from '@/hooks/useKoboldVersions'; +import { Logger } from '@/utils/logger'; import type { DownloadItem } from '@/types/electron'; interface DownloadScreenProps { @@ -33,7 +34,7 @@ export const DownloadScreen = ({ onDownloadComplete }: DownloadScreenProps) => { async (download: DownloadItem) => { setDownloadingAsset(download.name); - try { + await Logger.safeExecute(async () => { const success = await sharedHandleDownload({ type: 'asset', item: download, @@ -48,14 +49,9 @@ export const DownloadScreen = ({ onDownloadComplete }: DownloadScreenProps) => { setDownloadingAsset(null); }, 200); } - } catch (error) { - window.electronAPI.logs.logError( - `Failed to download ${download.name}:`, - error as Error - ); - } finally { - setDownloadingAsset(null); - } + }, `Failed to download ${download.name}:`); + + setDownloadingAsset(null); }, [sharedHandleDownload, onDownloadComplete] ); diff --git a/src/components/screens/Interface/TerminalTab.tsx b/src/components/screens/Interface/TerminalTab.tsx index db3334a..6e33b03 100644 --- a/src/components/screens/Interface/TerminalTab.tsx +++ b/src/components/screens/Interface/TerminalTab.tsx @@ -8,7 +8,7 @@ import { } from '@mantine/core'; import { ChevronDown } from 'lucide-react'; import styles from '@/styles/layout.module.css'; -import { UI } from '@/constants'; +import { UI, SERVER_READY_SIGNALS } from '@/constants'; import { handleTerminalOutput, processTerminalContent } from '@/utils/terminal'; import { useLaunchConfigStore } from '@/stores/launchConfigStore'; import type { FrontendPreference } from '@/types'; @@ -69,14 +69,14 @@ export const TerminalTab = ({ const serverPort = port || 5001; if (frontendPreference === 'sillytavern') { - if (newData.includes('SillyTavern is listening on')) { + if (newData.includes(SERVER_READY_SIGNALS.SILLYTAVERN)) { setTimeout( () => onServerReady(`http://${serverHost}:${serverPort}`), 1500 ); } } else { - if (newData.includes('Please connect to custom endpoint at')) { + if (newData.includes(SERVER_READY_SIGNALS.KOBOLDCPP)) { setTimeout( () => onServerReady(`http://${serverHost}:${serverPort}`), 1500 diff --git a/src/components/screens/Launch/AdvancedTab.tsx b/src/components/screens/Launch/AdvancedTab.tsx index 0ab71a6..0dba01e 100644 --- a/src/components/screens/Launch/AdvancedTab.tsx +++ b/src/components/screens/Launch/AdvancedTab.tsx @@ -3,6 +3,7 @@ import { useState, useEffect } from 'react'; import { InfoTooltip } from '@/components/InfoTooltip'; import { CheckboxWithTooltip } from '@/components/CheckboxWithTooltip'; import { useLaunchConfig } from '@/hooks/useLaunchConfig'; +import { Logger } from '@/utils/logger'; export const AdvancedTab = () => { const { @@ -34,25 +35,21 @@ export const AdvancedTab = () => { useEffect(() => { const detectBackendSupport = async () => { - try { - const support = await window.electronAPI.kobold.detectBackendSupport(); - if (support) { - setBackendSupport({ - noavx2: support.noavx2, - failsafe: support.failsafe, - }); - } else { - setBackendSupport({ noavx2: false, failsafe: false }); - } - } catch (error) { - window.electronAPI.logs.logError( - 'Failed to detect backend support:', - error as Error - ); + const support = await Logger.safeExecute( + () => window.electronAPI.kobold.detectBackendSupport(), + 'Failed to detect backend support:' + ); + + if (support) { + setBackendSupport({ + noavx2: support.noavx2, + failsafe: support.failsafe, + }); + } else { setBackendSupport({ noavx2: false, failsafe: false }); - } finally { - setIsLoading(false); } + + setIsLoading(false); }; void detectBackendSupport(); diff --git a/src/components/screens/Launch/GeneralTab/BackendSelector.tsx b/src/components/screens/Launch/GeneralTab/BackendSelector.tsx index c9f1ae2..8bf357c 100644 --- a/src/components/screens/Launch/GeneralTab/BackendSelector.tsx +++ b/src/components/screens/Launch/GeneralTab/BackendSelector.tsx @@ -4,6 +4,7 @@ import { InfoTooltip } from '@/components/InfoTooltip'; import { BackendSelectItem } from '@/components/screens/Launch/GeneralTab/BackendSelectItem'; import { GpuDeviceSelector } from '@/components/screens/Launch/GeneralTab/GpuDeviceSelector'; import { useLaunchConfig } from '@/hooks/useLaunchConfig'; +import { Logger } from '@/utils/logger'; import type { BackendOption } from '@/types'; export const BackendSelector = () => { @@ -19,22 +20,19 @@ export const BackendSelector = () => { const [availableBackends, setAvailableBackends] = useState( [] ); + const [isLoadingBackends, setIsLoadingBackends] = useState(false); const hasInitialized = useRef(false); useEffect(() => { const loadBackends = async () => { - try { - const backends = - await window.electronAPI.kobold.getAvailableBackends(true); - setAvailableBackends(backends); - hasInitialized.current = true; - } catch (error) { - window.electronAPI.logs.logError( - 'Failed to detect available backends:', - error as Error - ); - setAvailableBackends([]); - } + setIsLoadingBackends(true); + const backends = await Logger.safeExecute( + () => window.electronAPI.kobold.getAvailableBackends(true), + 'Failed to detect available backends:' + ); + setAvailableBackends(backends || []); + setIsLoadingBackends(false); + hasInitialized.current = true; }; if (!hasInitialized.current) { @@ -60,7 +58,9 @@ export const BackendSelector = () => {