fix: update ui version_backend, mem usage hardware (#5932)

* fix: update ui version_backend, mem usage hardware

* chore: hidden gpu from system monitor on mac

* chore: fix gpus vram
This commit is contained in:
Faisal Amir 2025-07-26 18:36:18 +07:00 committed by GitHub
parent 8ec4a36826
commit b89d9d090f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 120 additions and 64 deletions

View File

@ -0,0 +1,54 @@
import { useEffect } from 'react'
import { events } from '@janhq/core'
import { useModelProvider } from '@/hooks/useModelProvider'
import { getProviders } from '@/services/providers'
/**
* GlobalEventHandler handles global events that should be processed across all screens
* This provider should be mounted at the root level to ensure all screens can benefit from global event handling
*/
export function GlobalEventHandler() {
const { setProviders } = useModelProvider()
// Handle settingsChanged event globally
useEffect(() => {
const handleSettingsChanged = async (event: {
key: string
value: string
}) => {
console.log('Global settingsChanged event:', event)
// Handle version_backend changes specifically
if (event.key === 'version_backend') {
try {
// Refresh providers to get updated settings from the extension
const updatedProviders = await getProviders()
setProviders(updatedProviders)
console.log('Providers refreshed after version_backend change')
} catch (error) {
console.error(
'Failed to refresh providers after settingsChanged:',
error
)
}
}
// Add more global event handlers here as needed
// For example:
// if (event.key === 'some_other_setting') {
// // Handle other setting changes
// }
}
// Subscribe to the settingsChanged event
events.on('settingsChanged', handleSettingsChanged)
// Cleanup subscription on unmount
return () => {
events.off('settingsChanged', handleSettingsChanged)
}
}, [setProviders])
// This component doesn't render anything
return null
}

View File

@ -29,6 +29,7 @@ import {
} from '@/components/ui/resizable'
import { useCallback } from 'react'
import GlobalError from '@/containers/GlobalError'
import { GlobalEventHandler } from '@/providers/GlobalEventHandler'
export const Route = createRootRoute({
component: RootLayout,
@ -162,6 +163,7 @@ function RootLayout() {
<TranslationProvider>
<ExtensionProvider>
<DataProvider />
<GlobalEventHandler />
</ExtensionProvider>
{isLocalAPIServerLogsRoute ? <LogsLayout /> : <AppLayout />}
{/* <TanStackRouterDevtools position="bottom-right" /> */}

View File

@ -38,6 +38,9 @@ function Hardware() {
const llamacpp = providers.find((p) => p.provider === 'llamacpp')
// Llamacpp devices hook
const llamacppDevicesResult = useLlamacppDevices()
// Use default values on macOS since llamacpp devices are not relevant
const {
devices: llamacppDevices,
loading: llamacppDevicesLoading,
@ -45,7 +48,16 @@ function Hardware() {
activatedDevices,
toggleDevice,
fetchDevices,
} = useLlamacppDevices()
} = IS_MACOS
? {
devices: [],
loading: false,
error: null,
activatedDevices: new Set(),
toggleDevice: () => {},
fetchDevices: () => {},
}
: llamacppDevicesResult
// Fetch llamacpp devices when component mounts
useEffect(() => {
@ -296,8 +308,7 @@ function Hardware() {
<Progress
value={
toNumber(
(hardwareData.total_memory -
systemUsage.used_memory) /
systemUsage.used_memory /
hardwareData.total_memory
) * 100
}
@ -306,8 +317,7 @@ function Hardware() {
<span className="text-main-view-fg/80">
{(
toNumber(
(hardwareData.total_memory -
systemUsage.used_memory) /
systemUsage.used_memory /
hardwareData.total_memory
) * 100
).toFixed(2)}
@ -365,9 +375,9 @@ function Hardware() {
title={t('settings:hardware.vram')}
actions={
<span className="text-main-view-fg/80">
{formatMegaBytes(device.mem)}{' '}
{formatMegaBytes(device.free)}{' '}
{t('settings:hardware.freeOf')}{' '}
{formatMegaBytes(device.free)}
{formatMegaBytes(device.mem)}
</span>
}
/>

View File

@ -37,7 +37,6 @@ import { IconFolderPlus, IconLoader, IconRefresh } from '@tabler/icons-react'
import { getProviders } from '@/services/providers'
import { toast } from 'sonner'
import { useEffect, useState } from 'react'
import { events } from '@janhq/core'
import { predefinedProviders } from '@/consts/providers'
import { useModelLoad } from '@/hooks/useModelLoad'
import { useLlamacppDevices } from '@/hooks/useLlamacppDevices'
@ -131,18 +130,8 @@ function ProviderDetail() {
}
}, [provider, needsBackendConfig])
// Listen for settingsChanged event and refresh backend list if version_backend changes
useEffect(() => {
const handler = (event: { key: string; value: string }) => {
if (event.key === 'version_backend') {
refreshSettings()
}
}
events.on('settingsChanged', handler)
return () => {
events.off('settingsChanged', handler)
}
}, [provider])
// Note: settingsChanged event is now handled globally in GlobalEventHandler
// This ensures all screens receive the event intermediately
// Auto-refresh models for non-predefined providers
useEffect(() => {

View File

@ -95,10 +95,7 @@ function SystemMonitor() {
// Calculate RAM usage percentage
const ramUsagePercentage =
toNumber(
(hardwareData.total_memory - systemUsage.used_memory) /
hardwareData.total_memory
) * 100
toNumber(systemUsage.used_memory / hardwareData.total_memory) * 100
return (
<div className="flex flex-col h-full bg-main-view overflow-y-auto p-6">
@ -197,49 +194,53 @@ function SystemMonitor() {
</div>
{/* GPU Usage Card */}
<div className="bg-main-view-fg/2 rounded-lg p-6 shadow-sm">
<h2 className="text-base font-semibold text-main-view-fg mb-4">
{t('system-monitor:activeGpus')}
</h2>
<div className="flex flex-col gap-2">
{llamacppDevices.length > 0 ? (
llamacppDevices.map((device) => (
<div key={device.id} className="flex flex-col gap-1">
<div className="flex justify-between items-center">
<span className="text-main-view-fg/70">{device.name}</span>
<span
className={`text-sm px-2 py-1 rounded-md ${
activatedDevices.has(device.id)
? 'bg-green-500/20 text-green-600 dark:text-green-400'
: 'hidden'
}`}
>
{activatedDevices.has(device.id)
? t('system-monitor:active')
: 'Inactive'}
</span>
</div>
<div className="flex justify-between items-center text-sm">
<span className="text-main-view-fg/70">VRAM:</span>
<span className="text-main-view-fg">
{formatMegaBytes(device.mem)}
</span>
</div>
<div className="flex justify-between items-center text-sm">
<span className="text-main-view-fg/70">Free:</span>
<span className="text-main-view-fg">
{formatMegaBytes(device.free)}
</span>
{!IS_MACOS && (
<div className="bg-main-view-fg/2 rounded-lg p-6 shadow-sm">
<h2 className="text-base font-semibold text-main-view-fg mb-4">
{t('system-monitor:activeGpus')}
</h2>
<div className="flex flex-col gap-2">
{llamacppDevices.length > 0 ? (
llamacppDevices.map((device) => (
<div key={device.id} className="flex flex-col gap-1">
<div className="flex justify-between items-center">
<span className="text-main-view-fg/70">
{device.name}
</span>
<span
className={`text-sm px-2 py-1 rounded-md ${
activatedDevices.has(device.id)
? 'bg-green-500/20 text-green-600 dark:text-green-400'
: 'hidden'
}`}
>
{activatedDevices.has(device.id)
? t('system-monitor:active')
: 'Inactive'}
</span>
</div>
<div className="flex justify-between items-center text-sm">
<span className="text-main-view-fg/70">VRAM:</span>
<span className="text-main-view-fg">
{formatMegaBytes(device.mem)}
</span>
</div>
<div className="flex justify-between items-center text-sm">
<span className="text-main-view-fg/70">Free:</span>
<span className="text-main-view-fg">
{formatMegaBytes(device.free)}
</span>
</div>
</div>
))
) : (
<div className="text-main-view-fg/70 text-center py-4">
{t('system-monitor:noGpus')}
</div>
))
) : (
<div className="text-main-view-fg/70 text-center py-4">
{t('system-monitor:noGpus')}
</div>
)}
)}
</div>
</div>
</div>
)}
</div>
</div>
)