/* eslint-disable @typescript-eslint/no-explicit-any */ import * as React from 'react' import { useState } from 'react' import { DragDropContext, Draggable, Droppable } from '@hello-pangea/dnd' import { Progress, ScrollArea, Switch } from '@janhq/joi' import { useAtom, useAtomValue } from 'jotai' import { atomWithStorage } from 'jotai/utils' import { ChevronDownIcon, GripVerticalIcon } from 'lucide-react' import { twMerge } from 'tailwind-merge' import { useGetHardwareInfo, setActiveGpus, } from '@/hooks/useHardwareManagement' import { toGibibytes } from '@/utils/converter' import { utilizedMemory } from '@/utils/memory' import { cpuUsageAtom, ramUtilitizedAtom, totalRamAtom, usedRamAtom, gpusAtom, } from '@/helpers/atoms/SystemBar.atom' const orderGpusAtom = atomWithStorage('orderGpus', [], undefined, { getOnInit: true, }) const Hardware = () => { const { hardware, mutate } = useGetHardwareInfo() const [isActivatingGpu, setIsActivatingGpu] = useState>(new Set()) const [openPanels, setOpenPanels] = useState>({}) const cpuUsage = useAtomValue(cpuUsageAtom) const totalRam = useAtomValue(totalRamAtom) const usedRam = useAtomValue(usedRamAtom) const ramUtilitized = useAtomValue(ramUtilitizedAtom) const [gpus, setGpus] = useAtom(gpusAtom) const [orderGpus, setOrderGpus] = useAtom(orderGpusAtom) const togglePanel = (index: number) => { setOpenPanels((prev) => ({ ...prev, [index]: !prev[index], // Toggle the specific panel })) } // Handle switch toggle for GPU activation const handleSwitchChange = async (id: string, isActive: boolean) => { setIsActivatingGpu((prev) => new Set(prev).add(id)) const updatedGpus = gpus.map((gpu) => gpu.id === id ? { ...gpu, activated: isActive } : gpu ) // Call the API to update the active GPUs try { const activeGpuIds = updatedGpus .filter((gpu: any) => gpu.activated) .map((gpu: any) => Number(gpu.id)) await setActiveGpus({ gpus: activeGpuIds }) mutate() window.location.reload() } catch (error) { console.error('Failed to update active GPUs:', error) } } const handleDragEnd = (result: any) => { if (!result.destination) return const reorderedGpus = Array.from(gpus) const [movedGpu] = reorderedGpus.splice(result.source.index, 1) reorderedGpus.splice(result.destination.index, 0, movedGpu) setGpus(reorderedGpus) setOrderGpus(reorderedGpus.map((gpu) => gpu.id)) } React.useEffect(() => { if (hardware?.gpus) { setGpus((prevGpus: any) => { // Create a map of existing GPUs by UUID for quick lookup const gpuMap = new Map(prevGpus.map((gpu: any) => [gpu.uuid, gpu])) // Update existing GPUs or add new ones const updatedGpus = hardware.gpus.map((newGpu) => { const existingGpu: any = gpuMap.get(newGpu.uuid) if (existingGpu) { // Update the GPU properties while keeping the original order if (existingGpu.activated !== newGpu.activated) { setIsActivatingGpu((prev) => { const updated = new Set(prev) updated.delete(existingGpu.id) updated.clear() return updated }) } return { ...existingGpu, activated: newGpu.activated, free_vram: newGpu.free_vram, total_vram: newGpu.total_vram, } } // Return the new GPU if not already in the state return newGpu }) // Append GPUs from the previous state that are not in the hardware.gpus // This preserves user-reordered GPUs that aren't present in the new data const remainingGpus = prevGpus.filter( (prevGpu: any) => !hardware.gpus?.some((gpu) => gpu.uuid === prevGpu.uuid) ) return [...updatedGpus, ...remainingGpus] }) } }, [hardware?.gpus, setGpus]) return (
{/* CPU */}
CPU
{hardware?.cpu.model} | Cores: {hardware?.cpu.cores} | Architecture: {hardware?.cpu.arch}
{cpuUsage}%
{/* RAM */}
RAM
{toGibibytes(usedRam, { hideUnit: true })}GB /{' '} {toGibibytes(totalRam, { hideUnit: true })}GB {hardware?.ram.type && ( <> | Type: {hardware?.ram.type} )}
{ramUtilitized}%
{/* OS */}
OS
{hardware?.os.name} | {hardware?.os.version}
{/* GPUs */} {!isMac && gpus.length > 0 && (
GPUs

{`Enhance model performance by utilizing your device's GPU for acceleration.`}

{(provided) => (
{gpus .sort((a, b) => { const orderA = orderGpus.indexOf(a.id) const orderB = orderGpus.indexOf(b.id) return orderA - orderB }) .map((item: any, i) => { const gpuUtilization = utilizedMemory( item.free_vram, item.total_vram ) const isLoading = isActivatingGpu.has(item.id) return ( {(provided, snapshot) => (
1 && 'last:rounded-t-none', snapshot.isDragging ? 'border-b' : 'border-b-0 last:border-b' )} onClick={() => togglePanel(i)} >
{item.name}
{item.activated && (
{gpuUtilization}%
)}
{item.activated && ( {( (Number(item.total_vram) - Number(item.free_vram)) / 1024 ).toFixed(2)} GB /{' '} )} {( Number(item.total_vram) / 1024 ).toFixed(2)} GB
handleSwitchChange( item.id, e.target.checked ) } /> {isLoading && (
)}
{openPanels[i] && (
Driver Version
{ item.additional_information ?.driver_version }
Compute Capability
{ item.additional_information ?.compute_cap }
)}
)} ) })} {provided.placeholder}
)}
)}
) } export default Hardware