import { Fragment, useCallback, useEffect, useRef, useState } from 'react' import { ResourceStatus } from '@janhq/core' import { Progress } from '@janhq/joi' import { useClickOutside } from '@janhq/joi' import { fetchEventSource } from '@microsoft/fetch-event-source' import { useAtom, useAtomValue } from 'jotai' import { MonitorIcon, XIcon, ChevronDown, ChevronUp, FolderOpenIcon, } from 'lucide-react' import { twMerge } from 'tailwind-merge' import { toGibibytes } from '@/utils/converter' import TableActiveModel from './TableActiveModel' import { showSystemMonitorPanelAtom } from '@/helpers/atoms/App.atom' import { hostAtom } from '@/helpers/atoms/AppConfig.atom' import { reduceTransparentAtom } from '@/helpers/atoms/Setting.atom' import { cpuUsageAtom, gpusAtom, ramUtilitizedAtom, totalRamAtom, usedRamAtom, } from '@/helpers/atoms/SystemBar.atom' const SystemMonitor: React.FC = () => { const host = useAtomValue(hostAtom) const [usedRam, setUsedRam] = useAtom(usedRamAtom) const [totalRam, setTotalRam] = useAtom(totalRamAtom) const [cpuUsage, setCpuUsage] = useAtom(cpuUsageAtom) const gpus = useAtomValue(gpusAtom) const [showFullScreen, setShowFullScreen] = useState(false) const ramUtilitized = useAtomValue(ramUtilitizedAtom) const [showSystemMonitorPanel, setShowSystemMonitorPanel] = useAtom( showSystemMonitorPanelAtom ) const [control, setControl] = useState(null) const [elementExpand, setElementExpand] = useState( null ) const reduceTransparent = useAtomValue(reduceTransparentAtom) const abortControllerRef = useRef(null) const onOpenAppLogClick = useCallback(() => { window?.electronAPI?.openAppLog() }, []) const register = useCallback(async () => { if (abortControllerRef.current) return abortControllerRef.current = new AbortController() await fetchEventSource(`${host}/system/events/resources`, { onmessage(ev) { if (!ev.data || ev.data === '') return try { const resourceEvent = JSON.parse(ev.data) as ResourceStatus setUsedRam(resourceEvent.mem.used) setTotalRam(resourceEvent.mem.total) setCpuUsage(resourceEvent.cpu.usage) } catch (err) { console.error(err) } }, signal: abortControllerRef.current.signal, }) }, [host, setTotalRam, setUsedRam, setCpuUsage]) const unregister = useCallback(() => { if (!abortControllerRef.current) return abortControllerRef.current.abort() abortControllerRef.current = null }, []) useClickOutside( () => { setShowSystemMonitorPanel(false) setShowFullScreen(false) }, null, [control, elementExpand] ) useEffect(() => { register() return () => { unregister() } }, [register, unregister]) return (
{ setShowSystemMonitorPanel(!showSystemMonitorPanel) setShowFullScreen(false) }} > System Monitor
{showSystemMonitorPanel && (
Running Models
onOpenAppLogClick()} > App Log
{showFullScreen ? ( setShowFullScreen(!showFullScreen)} /> ) : ( setShowFullScreen(!showFullScreen)} /> )} { setShowSystemMonitorPanel(false) setShowFullScreen(false) }} />
CPU
{cpuUsage}%
Memory
{toGibibytes(usedRam, { hideUnit: true })}/ {toGibibytes(totalRam, { hideUnit: true })} GB
{ramUtilitized}%
{gpus.length > 0 && (
{gpus.map((gpu, index) => (
{gpu.name}
{gpu.memoryTotal - gpu.memoryFree}/ {gpu.memoryTotal} MB
{gpu.utilization}%
))}
)}
)}
) } export default SystemMonitor