diff --git a/web/containers/Layout/BottomBar/index.tsx b/web/containers/Layout/BottomBar/index.tsx index d34173ecb..d6a7c05d2 100644 --- a/web/containers/Layout/BottomBar/index.tsx +++ b/web/containers/Layout/BottomBar/index.tsx @@ -1,3 +1,5 @@ +import { useEffect } from 'react' + import { Badge, Button, @@ -31,6 +33,11 @@ import { useMainViewState } from '@/hooks/useMainViewState' import { serverEnabledAtom } from '@/helpers/atoms/LocalServer.atom' import { downloadedModelsAtom } from '@/helpers/atoms/Model.atom' +import { + cpuUsageAtom, + gpusAtom, + ramUtilitizedAtom, +} from '@/helpers/atoms/SystemBar.atom' const menuLinks = [ { @@ -47,9 +54,12 @@ const menuLinks = [ const BottomBar = () => { const { activeModel, stateModel } = useActiveModel() - const { ram, cpu, gpus } = useGetSystemResources() + const { watch, stopWatching } = useGetSystemResources() const progress = useAtomValue(appDownloadProgress) const downloadedModels = useAtomValue(downloadedModelsAtom) + const gpus = useAtomValue(gpusAtom) + const cpu = useAtomValue(cpuUsageAtom) + const ramUtilitized = useAtomValue(ramUtilitizedAtom) const { setMainViewState } = useMainViewState() const downloadStates = useAtomValue(modelDownloadStateAtom) @@ -67,6 +77,16 @@ const BottomBar = () => { return sum } + useEffect(() => { + // Watch for resource update + watch() + + return () => { + stopWatching() + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []) + return (
@@ -127,7 +147,7 @@ const BottomBar = () => {
- +
{gpus.length > 0 && ( diff --git a/web/containers/Providers/DataLoader.tsx b/web/containers/Providers/DataLoader.tsx index 2b6675d98..d7b630043 100644 --- a/web/containers/Providers/DataLoader.tsx +++ b/web/containers/Providers/DataLoader.tsx @@ -3,6 +3,7 @@ import { Fragment, ReactNode } from 'react' import useAssistants from '@/hooks/useAssistants' +import useGetSystemResources from '@/hooks/useGetSystemResources' import useModels from '@/hooks/useModels' import useThreads from '@/hooks/useThreads' @@ -14,6 +15,8 @@ const DataLoader: React.FC = ({ children }) => { useModels() useThreads() useAssistants() + useGetSystemResources() + console.debug('Load Data...') return {children} } diff --git a/web/containers/Providers/EventHandler.tsx b/web/containers/Providers/EventHandler.tsx index 2369e41bd..f871331b9 100644 --- a/web/containers/Providers/EventHandler.tsx +++ b/web/containers/Providers/EventHandler.tsx @@ -282,11 +282,9 @@ export default function EventHandler({ children }: { children: ReactNode }) { } useEffect(() => { - console.log('Registering events') if (window.core?.events) { events.on(MessageEvent.OnMessageResponse, onNewMessageResponse) events.on(MessageEvent.OnMessageUpdate, onMessageResponseUpdate) - events.on(ModelEvent.OnModelReady, onModelReady) events.on(ModelEvent.OnModelFail, onModelInitFailed) events.on(ModelEvent.OnModelStopped, onModelStopped) diff --git a/web/containers/Providers/EventListener.tsx b/web/containers/Providers/EventListener.tsx index 100805e17..938db69c0 100644 --- a/web/containers/Providers/EventListener.tsx +++ b/web/containers/Providers/EventListener.tsx @@ -41,14 +41,14 @@ const EventListenerWrapper = ({ children }: PropsWithChildren) => { ) useEffect(() => { - console.log('EventListenerWrapper: registering event listeners...') + console.debug('EventListenerWrapper: registering event listeners...') events.on(DownloadEvent.onFileDownloadUpdate, onFileDownloadUpdate) events.on(DownloadEvent.onFileDownloadError, onFileDownloadError) events.on(DownloadEvent.onFileDownloadSuccess, onFileDownloadSuccess) return () => { - console.log('EventListenerWrapper: unregistering event listeners...') + console.debug('EventListenerWrapper: unregistering event listeners...') events.off(DownloadEvent.onFileDownloadUpdate, onFileDownloadUpdate) events.off(DownloadEvent.onFileDownloadError, onFileDownloadError) events.off(DownloadEvent.onFileDownloadSuccess, onFileDownloadSuccess) diff --git a/web/helpers/atoms/SystemBar.atom.ts b/web/helpers/atoms/SystemBar.atom.ts index 22a7573ec..3c9a48f79 100644 --- a/web/helpers/atoms/SystemBar.atom.ts +++ b/web/helpers/atoms/SystemBar.atom.ts @@ -2,8 +2,10 @@ import { atom } from 'jotai' export const totalRamAtom = atom(0) export const usedRamAtom = atom(0) -export const availableRamAtom = atom(0) export const cpuUsageAtom = atom(0) +export const ramUtilitizedAtom = atom(0) + +export const gpusAtom = atom[]>([]) export const nvidiaTotalVramAtom = atom(0) diff --git a/web/hooks/useGetSystemResources.ts b/web/hooks/useGetSystemResources.ts index 3f71040d7..ef2f30a61 100644 --- a/web/hooks/useGetSystemResources.ts +++ b/web/hooks/useGetSystemResources.ts @@ -1,4 +1,4 @@ -import { useEffect, useState } from 'react' +import { useCallback, useEffect, useState } from 'react' import { ExtensionTypeEnum, MonitoringExtension } from '@janhq/core' @@ -6,25 +6,27 @@ import { useSetAtom } from 'jotai' import { extensionManager } from '@/extension/ExtensionManager' import { - availableRamAtom, cpuUsageAtom, totalRamAtom, usedRamAtom, nvidiaTotalVramAtom, + gpusAtom, + ramUtilitizedAtom, } from '@/helpers/atoms/SystemBar.atom' export default function useGetSystemResources() { - const [ram, setRam] = useState(0) - const [cpu, setCPU] = useState(0) + const [intervalId, setIntervalId] = useState< + NodeJS.Timeout | number | undefined + >(undefined) - const [gpus, setGPUs] = useState[]>([]) const setTotalRam = useSetAtom(totalRamAtom) + const setGpus = useSetAtom(gpusAtom) const setUsedRam = useSetAtom(usedRamAtom) - const setAvailableRam = useSetAtom(availableRamAtom) const setCpuUsage = useSetAtom(cpuUsageAtom) const setTotalNvidiaVram = useSetAtom(nvidiaTotalVramAtom) + const setRamUtilitized = useSetAtom(ramUtilitizedAtom) - const getSystemResources = async () => { + const getSystemResources = useCallback(async () => { if ( !extensionManager.get( ExtensionTypeEnum.SystemMonitoring @@ -38,23 +40,20 @@ export default function useGetSystemResources() { const resourceInfor = await monitoring?.getResourcesInfo() const currentLoadInfor = await monitoring?.getCurrentLoad() - const ram = - (resourceInfor?.mem?.usedMemory ?? 0) / - (resourceInfor?.mem?.totalMemory ?? 1) if (resourceInfor?.mem?.usedMemory) setUsedRam(resourceInfor.mem.usedMemory) if (resourceInfor?.mem?.totalMemory) setTotalRam(resourceInfor.mem.totalMemory) - setRam(Math.round(ram * 100)) - if (resourceInfor.mem.totalMemory && resourceInfor.mem.usedMemory) - setAvailableRam( - resourceInfor.mem.totalMemory - resourceInfor.mem.usedMemory - ) - setCPU(Math.round(currentLoadInfor?.cpu?.usage ?? 0)) + const ramUtilitized = + ((resourceInfor?.mem?.usedMemory ?? 0) / + (resourceInfor?.mem?.totalMemory ?? 1)) * + 100 + setRamUtilitized(Math.round(ramUtilitized)) + setCpuUsage(Math.round(currentLoadInfor?.cpu?.usage ?? 0)) const gpus = currentLoadInfor?.gpu ?? [] - setGPUs(gpus) + setGpus(gpus) let totalNvidiaVram = 0 if (gpus.length > 0) { @@ -65,27 +64,49 @@ export default function useGetSystemResources() { ) } setTotalNvidiaVram(totalNvidiaVram) - } + }, [ + setUsedRam, + setTotalRam, + setRamUtilitized, + setCpuUsage, + setGpus, + setTotalNvidiaVram, + ]) - useEffect(() => { + const watch = () => { getSystemResources() // Fetch interval - every 2s - // TODO: Will we really need this? - // There is a possibility that this will be removed and replaced by the process event hook? - const intervalId = setInterval(() => { + const itv = setInterval(() => { getSystemResources() - }, 5000) + }, 2000) + setIntervalId(itv) + } + const stopWatching = useCallback(() => { + if (intervalId) clearInterval(intervalId) + }, [intervalId]) - // clean up interval - return () => clearInterval(intervalId) - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []) + useEffect(() => { + getSystemResources() + // Component did unmount + // Stop watching if any + return () => { + stopWatching() + } + }, [getSystemResources, stopWatching]) return { - totalRamAtom, - ram, - cpu, - gpus, + /** + * Fetch resource informations once + */ + getSystemResources, + /** + * Fetch & watch for resource update + */ + watch, + /** + * Stop watching + */ + stopWatching, } }