fix: update default GPU toggle, and simplify state (#5937)
This commit is contained in:
parent
c3fa04fdd7
commit
54d44ce741
@ -31,15 +31,13 @@ describe('useLlamacppDevices', () => {
|
||||
expect(result.current.devices).toEqual([])
|
||||
expect(result.current.loading).toBe(false)
|
||||
expect(result.current.error).toBeNull()
|
||||
expect(result.current.activatedDevices).toEqual(new Set())
|
||||
expect(typeof result.current.fetchDevices).toBe('function')
|
||||
expect(typeof result.current.clearError).toBe('function')
|
||||
expect(typeof result.current.setDevices).toBe('function')
|
||||
expect(typeof result.current.toggleDevice).toBe('function')
|
||||
expect(typeof result.current.setActivatedDevices).toBe('function')
|
||||
})
|
||||
|
||||
it('should fetch devices successfully', async () => {
|
||||
it('should fetch devices successfully with activation status', async () => {
|
||||
const mockDevices = [
|
||||
{ id: 'CUDA0', name: 'NVIDIA GeForce RTX 4090', mem: 24576, free: 20480 },
|
||||
{ id: 'CUDA1', name: 'NVIDIA GeForce RTX 3080', mem: 10240, free: 8192 },
|
||||
@ -53,7 +51,11 @@ describe('useLlamacppDevices', () => {
|
||||
await result.current.fetchDevices()
|
||||
})
|
||||
|
||||
expect(result.current.devices).toEqual(mockDevices)
|
||||
// Should have devices with activated property (empty setting means all activated)
|
||||
expect(result.current.devices).toEqual([
|
||||
{ ...mockDevices[0], activated: true },
|
||||
{ ...mockDevices[1], activated: true },
|
||||
])
|
||||
expect(result.current.loading).toBe(false)
|
||||
expect(result.current.error).toBeNull()
|
||||
expect(mockGetLlamacppDevices).toHaveBeenCalledOnce()
|
||||
@ -89,44 +91,43 @@ describe('useLlamacppDevices', () => {
|
||||
expect(result.current.devices).toEqual(mockDevices)
|
||||
})
|
||||
|
||||
it('should toggle device activation', () => {
|
||||
it('should toggle device activation', async () => {
|
||||
const { result } = renderHook(() => useLlamacppDevices())
|
||||
|
||||
// Initially no devices are activated
|
||||
expect(result.current.activatedDevices).toEqual(new Set())
|
||||
// Set initial devices with activation status
|
||||
act(() => {
|
||||
result.current.setDevices([
|
||||
{ id: 'CUDA0', name: 'NVIDIA GeForce RTX 4090', mem: 24576, free: 20480, activated: false },
|
||||
{ id: 'CUDA1', name: 'NVIDIA GeForce RTX 3080', mem: 10240, free: 8192, activated: false },
|
||||
])
|
||||
})
|
||||
|
||||
// Toggle a device on
|
||||
act(() => {
|
||||
result.current.toggleDevice('CUDA0')
|
||||
await act(async () => {
|
||||
await result.current.toggleDevice('CUDA0')
|
||||
})
|
||||
|
||||
expect(result.current.activatedDevices).toEqual(new Set(['CUDA0']))
|
||||
expect(result.current.devices[0].activated).toBe(true)
|
||||
expect(result.current.devices[1].activated).toBe(false)
|
||||
|
||||
// Toggle the same device off
|
||||
act(() => {
|
||||
result.current.toggleDevice('CUDA0')
|
||||
await act(async () => {
|
||||
await result.current.toggleDevice('CUDA0')
|
||||
})
|
||||
|
||||
expect(result.current.activatedDevices).toEqual(new Set())
|
||||
expect(result.current.devices[0].activated).toBe(false)
|
||||
expect(result.current.devices[1].activated).toBe(false)
|
||||
|
||||
// Toggle multiple devices
|
||||
act(() => {
|
||||
result.current.toggleDevice('CUDA0')
|
||||
result.current.toggleDevice('CUDA1')
|
||||
await act(async () => {
|
||||
await result.current.toggleDevice('CUDA0')
|
||||
})
|
||||
await act(async () => {
|
||||
await result.current.toggleDevice('CUDA1')
|
||||
})
|
||||
|
||||
expect(result.current.activatedDevices).toEqual(new Set(['CUDA0', 'CUDA1']))
|
||||
expect(result.current.devices[0].activated).toBe(true)
|
||||
expect(result.current.devices[1].activated).toBe(true)
|
||||
})
|
||||
|
||||
it('should set activated devices', () => {
|
||||
const { result } = renderHook(() => useLlamacppDevices())
|
||||
|
||||
const deviceIds = ['CUDA0', 'CUDA1', 'Vulkan0']
|
||||
|
||||
act(() => {
|
||||
result.current.setActivatedDevices(deviceIds)
|
||||
})
|
||||
|
||||
expect(result.current.activatedDevices).toEqual(new Set(deviceIds))
|
||||
})
|
||||
})
|
||||
@ -4,31 +4,48 @@ import { updateSettings } from '@/services/providers'
|
||||
import { useModelProvider } from './useModelProvider'
|
||||
|
||||
interface LlamacppDevicesStore {
|
||||
devices: DeviceList[]
|
||||
devices: (DeviceList & { activated: boolean })[]
|
||||
loading: boolean
|
||||
error: string | null
|
||||
activatedDevices: Set<string> // Track which devices are activated
|
||||
|
||||
// Actions
|
||||
fetchDevices: () => Promise<void>
|
||||
clearError: () => void
|
||||
setDevices: (devices: DeviceList[]) => void
|
||||
setDevices: (devices: (DeviceList & { activated: boolean })[]) => void
|
||||
toggleDevice: (deviceId: string) => void
|
||||
setActivatedDevices: (deviceIds: string[]) => void
|
||||
}
|
||||
|
||||
export const useLlamacppDevices = create<LlamacppDevicesStore>((set, get) => ({
|
||||
devices: [],
|
||||
loading: false,
|
||||
error: null,
|
||||
activatedDevices: new Set(),
|
||||
|
||||
fetchDevices: async () => {
|
||||
set({ loading: true, error: null })
|
||||
|
||||
try {
|
||||
const devices = await getLlamacppDevices()
|
||||
set({ devices, loading: false })
|
||||
|
||||
// Check current device setting from provider
|
||||
const { getProviderByName } = useModelProvider.getState()
|
||||
const llamacppProvider = getProviderByName('llamacpp')
|
||||
const currentDeviceSetting = llamacppProvider?.settings.find(
|
||||
(s) => s.key === 'device'
|
||||
)?.controller_props.value as string
|
||||
|
||||
// Parse device setting from extension which represents activated devices
|
||||
const activatedDevices = currentDeviceSetting
|
||||
? currentDeviceSetting.split(',').map(d => d.trim()).filter(Boolean)
|
||||
: []
|
||||
|
||||
const devicesWithActivation = devices.map((device) => ({
|
||||
...device,
|
||||
activated:
|
||||
// Empty device setting means all devices are activated
|
||||
!currentDeviceSetting || currentDeviceSetting === '' || activatedDevices.includes(device.id),
|
||||
}))
|
||||
|
||||
set({ devices: devicesWithActivation, loading: false })
|
||||
} catch (error) {
|
||||
const errorMessage =
|
||||
error instanceof Error ? error.message : 'Failed to fetch devices'
|
||||
@ -41,22 +58,26 @@ export const useLlamacppDevices = create<LlamacppDevicesStore>((set, get) => ({
|
||||
setDevices: (devices) => set({ devices }),
|
||||
|
||||
toggleDevice: async (deviceId: string) => {
|
||||
set((state) => {
|
||||
const newActivatedDevices = new Set(state.activatedDevices)
|
||||
if (newActivatedDevices.has(deviceId)) {
|
||||
newActivatedDevices.delete(deviceId)
|
||||
} else {
|
||||
newActivatedDevices.add(deviceId)
|
||||
}
|
||||
return { activatedDevices: newActivatedDevices }
|
||||
})
|
||||
// Toggle device activation in the local state
|
||||
set((state) => ({
|
||||
devices: state.devices.map((device) =>
|
||||
device.id === deviceId
|
||||
? { ...device, activated: !device.activated }
|
||||
: device
|
||||
),
|
||||
}))
|
||||
|
||||
// Update llamacpp provider settings
|
||||
const { getProviderByName, updateProvider } = useModelProvider.getState()
|
||||
const llamacppProvider = getProviderByName('llamacpp')
|
||||
|
||||
if (llamacppProvider) {
|
||||
const deviceString = Array.from(get().activatedDevices).join(',')
|
||||
// Get activated devices after toggle
|
||||
const activatedDeviceIds = get().devices
|
||||
.filter((device) => device.activated)
|
||||
.map((device) => device.id)
|
||||
|
||||
const deviceString = activatedDeviceIds.join(',')
|
||||
|
||||
const updatedSettings = llamacppProvider.settings.map((setting) => {
|
||||
if (setting.key === 'device') {
|
||||
@ -64,7 +85,7 @@ export const useLlamacppDevices = create<LlamacppDevicesStore>((set, get) => ({
|
||||
...setting,
|
||||
controller_props: {
|
||||
...setting.controller_props,
|
||||
value: deviceString,
|
||||
value: deviceString.length > 0 ? deviceString : 'none',
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -78,7 +99,4 @@ export const useLlamacppDevices = create<LlamacppDevicesStore>((set, get) => ({
|
||||
}
|
||||
},
|
||||
|
||||
setActivatedDevices: (deviceIds: string[]) => {
|
||||
set({ activatedDevices: new Set(deviceIds) })
|
||||
},
|
||||
}))
|
||||
|
||||
@ -45,7 +45,6 @@ function Hardware() {
|
||||
devices: llamacppDevices,
|
||||
loading: llamacppDevicesLoading,
|
||||
error: llamacppDevicesError,
|
||||
activatedDevices,
|
||||
toggleDevice,
|
||||
fetchDevices,
|
||||
} = IS_MACOS
|
||||
@ -53,7 +52,6 @@ function Hardware() {
|
||||
devices: [],
|
||||
loading: false,
|
||||
error: null,
|
||||
activatedDevices: new Set(),
|
||||
toggleDevice: () => {},
|
||||
fetchDevices: () => {},
|
||||
}
|
||||
@ -87,43 +85,7 @@ function Hardware() {
|
||||
})
|
||||
}, [setHardwareData, updateSystemUsage])
|
||||
|
||||
const { getProviderByName } = useModelProvider()
|
||||
|
||||
// Initialize llamacpp device activations from provider settings
|
||||
useEffect(() => {
|
||||
if (llamacppDevices.length > 0 && activatedDevices.size === 0) {
|
||||
const llamacppProvider = getProviderByName('llamacpp')
|
||||
const currentDeviceSetting = llamacppProvider?.settings.find(
|
||||
(s) => s.key === 'device'
|
||||
)?.controller_props.value as string
|
||||
|
||||
if (currentDeviceSetting) {
|
||||
const deviceIds = currentDeviceSetting
|
||||
.split(',')
|
||||
.map((device) => device.trim())
|
||||
.filter((device) => device.length > 0)
|
||||
|
||||
// Find matching devices by ID
|
||||
const matchingDeviceIds = deviceIds.filter((deviceId) =>
|
||||
llamacppDevices.some((device) => device.id === deviceId)
|
||||
)
|
||||
|
||||
if (matchingDeviceIds.length > 0) {
|
||||
console.log(
|
||||
`Initializing llamacpp device activations from device setting: "${currentDeviceSetting}"`
|
||||
)
|
||||
// Update the activatedDevices in the hook
|
||||
const { setActivatedDevices } = useLlamacppDevices.getState()
|
||||
setActivatedDevices(matchingDeviceIds)
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [
|
||||
llamacppDevices.length,
|
||||
activatedDevices.size,
|
||||
getProviderByName,
|
||||
llamacppDevices,
|
||||
])
|
||||
|
||||
useEffect(() => {
|
||||
if (pollingPaused) return
|
||||
@ -361,7 +323,7 @@ function Hardware() {
|
||||
</span>
|
||||
</div> */}
|
||||
<Switch
|
||||
checked={activatedDevices.has(device.id)}
|
||||
checked={device.activated}
|
||||
onCheckedChange={() => {
|
||||
toggleDevice(device.id)
|
||||
stopAllModels()
|
||||
|
||||
@ -367,9 +367,10 @@ function ProviderDetail() {
|
||||
|
||||
// Reset llamacpp device activations when backend version changes
|
||||
if (providerName === 'llamacpp') {
|
||||
const { setActivatedDevices } =
|
||||
// Refresh devices to update activation status from provider settings
|
||||
const { fetchDevices } =
|
||||
useLlamacppDevices.getState()
|
||||
setActivatedDevices([])
|
||||
fetchDevices()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -9,7 +9,6 @@ import { IconDeviceDesktopAnalytics } from '@tabler/icons-react'
|
||||
import { useTranslation } from '@/i18n/react-i18next-compat'
|
||||
import { toNumber } from '@/utils/number'
|
||||
import { useLlamacppDevices } from '@/hooks/useLlamacppDevices'
|
||||
import { useModelProvider } from '@/hooks/useModelProvider'
|
||||
import { getSystemUsage } from '@/services/hardware'
|
||||
|
||||
export const Route = createFileRoute(route.systemMonitor as any)({
|
||||
@ -22,11 +21,8 @@ function SystemMonitor() {
|
||||
|
||||
const {
|
||||
devices: llamacppDevices,
|
||||
activatedDevices,
|
||||
fetchDevices,
|
||||
setActivatedDevices,
|
||||
} = useLlamacppDevices()
|
||||
const { getProviderByName } = useModelProvider()
|
||||
|
||||
const [isInitialized, setIsInitialized] = useState(false)
|
||||
|
||||
@ -57,41 +53,6 @@ function SystemMonitor() {
|
||||
}
|
||||
}, [hardwareData.gpus.length, isInitialized])
|
||||
|
||||
// Initialize llamacpp device activations from provider settings
|
||||
useEffect(() => {
|
||||
if (llamacppDevices.length > 0 && activatedDevices.size === 0) {
|
||||
const llamacppProvider = getProviderByName('llamacpp')
|
||||
const currentDeviceSetting = llamacppProvider?.settings.find(
|
||||
(s) => s.key === 'device'
|
||||
)?.controller_props.value as string
|
||||
|
||||
if (currentDeviceSetting) {
|
||||
const deviceIds = currentDeviceSetting
|
||||
.split(',')
|
||||
.map((device) => device.trim())
|
||||
.filter((device) => device.length > 0)
|
||||
|
||||
// Find matching devices by ID
|
||||
const matchingDeviceIds = deviceIds.filter((deviceId) =>
|
||||
llamacppDevices.some((device) => device.id === deviceId)
|
||||
)
|
||||
|
||||
if (matchingDeviceIds.length > 0) {
|
||||
console.log(
|
||||
`Initializing llamacpp device activations from device setting: "${currentDeviceSetting}"`
|
||||
)
|
||||
// Update the activatedDevices in the hook
|
||||
setActivatedDevices(matchingDeviceIds)
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [
|
||||
llamacppDevices.length,
|
||||
activatedDevices.size,
|
||||
getProviderByName,
|
||||
llamacppDevices,
|
||||
setActivatedDevices,
|
||||
])
|
||||
|
||||
// Calculate RAM usage percentage
|
||||
const ramUsagePercentage =
|
||||
@ -209,12 +170,12 @@ function SystemMonitor() {
|
||||
</span>
|
||||
<span
|
||||
className={`text-sm px-2 py-1 rounded-md ${
|
||||
activatedDevices.has(device.id)
|
||||
device.activated
|
||||
? 'bg-green-500/20 text-green-600 dark:text-green-400'
|
||||
: 'hidden'
|
||||
}`}
|
||||
>
|
||||
{activatedDevices.has(device.id)
|
||||
{device.activated
|
||||
? t('system-monitor:active')
|
||||
: 'Inactive'}
|
||||
</span>
|
||||
|
||||
@ -7,6 +7,7 @@ export interface DeviceList {
|
||||
name: string
|
||||
mem: number
|
||||
free: number
|
||||
activated: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
@ -31,12 +32,14 @@ export const getSystemUsage = async () => {
|
||||
*/
|
||||
export const getLlamacppDevices = async (): Promise<DeviceList[]> => {
|
||||
const extensionManager = window.core.extensionManager
|
||||
const llamacppExtension = extensionManager.getByName('@janhq/llamacpp-extension')
|
||||
|
||||
const llamacppExtension = extensionManager.getByName(
|
||||
'@janhq/llamacpp-extension'
|
||||
)
|
||||
|
||||
if (!llamacppExtension) {
|
||||
throw new Error('llamacpp extension not found')
|
||||
}
|
||||
|
||||
|
||||
return llamacppExtension.getDevices()
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user