enhancement: show readme on detail each model (#5705)
* 🧹cleanup: linter and log
* Update web-app/src/routes/hub/$modelId.tsx
Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
---------
Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
This commit is contained in:
parent
d4a3d6a0d6
commit
a0be23b500
@ -184,10 +184,10 @@ export const useHardware = create<HardwareStore>()(
|
|||||||
set({
|
set({
|
||||||
hardwareData: {
|
hardwareData: {
|
||||||
...data,
|
...data,
|
||||||
gpus: data.gpus.map(gpu => ({
|
gpus: data.gpus.map((gpu) => ({
|
||||||
...gpu,
|
...gpu,
|
||||||
activated: gpu.activated ?? false
|
activated: gpu.activated ?? false,
|
||||||
}))
|
})),
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|
||||||
@ -195,29 +195,30 @@ export const useHardware = create<HardwareStore>()(
|
|||||||
set((state) => {
|
set((state) => {
|
||||||
// If we have existing GPU data, preserve the order and activation state
|
// If we have existing GPU data, preserve the order and activation state
|
||||||
if (state.hardwareData.gpus.length > 0) {
|
if (state.hardwareData.gpus.length > 0) {
|
||||||
|
|
||||||
// Reorder fresh GPU data to match existing order, adding new GPUs at the end
|
// Reorder fresh GPU data to match existing order, adding new GPUs at the end
|
||||||
const reorderedGpus: GPU[] = []
|
const reorderedGpus: GPU[] = []
|
||||||
const processedUuids = new Set()
|
const processedUuids = new Set()
|
||||||
|
|
||||||
// First, add existing GPUs in their current order, preserving activation state
|
// First, add existing GPUs in their current order, preserving activation state
|
||||||
state.hardwareData.gpus.forEach(existingGpu => {
|
state.hardwareData.gpus.forEach((existingGpu) => {
|
||||||
const freshGpu = data.gpus.find(gpu => gpu.uuid === existingGpu.uuid)
|
const freshGpu = data.gpus.find(
|
||||||
|
(gpu) => gpu.uuid === existingGpu.uuid
|
||||||
|
)
|
||||||
if (freshGpu) {
|
if (freshGpu) {
|
||||||
reorderedGpus.push({
|
reorderedGpus.push({
|
||||||
...freshGpu,
|
...freshGpu,
|
||||||
activated: existingGpu.activated ?? false
|
activated: existingGpu.activated ?? false,
|
||||||
})
|
})
|
||||||
processedUuids.add(freshGpu.uuid)
|
processedUuids.add(freshGpu.uuid)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// Then, add any new GPUs that weren't in the existing order (default to inactive)
|
// Then, add any new GPUs that weren't in the existing order (default to inactive)
|
||||||
data.gpus.forEach(freshGpu => {
|
data.gpus.forEach((freshGpu) => {
|
||||||
if (!processedUuids.has(freshGpu.uuid)) {
|
if (!processedUuids.has(freshGpu.uuid)) {
|
||||||
reorderedGpus.push({
|
reorderedGpus.push({
|
||||||
...freshGpu,
|
...freshGpu,
|
||||||
activated: false
|
activated: false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -225,19 +226,19 @@ export const useHardware = create<HardwareStore>()(
|
|||||||
return {
|
return {
|
||||||
hardwareData: {
|
hardwareData: {
|
||||||
...data,
|
...data,
|
||||||
gpus: reorderedGpus
|
gpus: reorderedGpus,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// No existing GPU data, initialize all GPUs as inactive
|
// No existing GPU data, initialize all GPUs as inactive
|
||||||
return {
|
return {
|
||||||
hardwareData: {
|
hardwareData: {
|
||||||
...data,
|
...data,
|
||||||
gpus: data.gpus.map(gpu => ({
|
gpus: data.gpus.map((gpu) => ({
|
||||||
...gpu,
|
...gpu,
|
||||||
activated: false
|
activated: false,
|
||||||
}))
|
})),
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
@ -291,42 +292,35 @@ export const useHardware = create<HardwareStore>()(
|
|||||||
|
|
||||||
// Import and get backend type
|
// Import and get backend type
|
||||||
const { useModelProvider } = await import('./useModelProvider')
|
const { useModelProvider } = await import('./useModelProvider')
|
||||||
const { updateProvider, getProviderByName } = useModelProvider.getState()
|
const { updateProvider, getProviderByName } =
|
||||||
|
useModelProvider.getState()
|
||||||
|
|
||||||
const llamacppProvider = getProviderByName('llamacpp')
|
const llamacppProvider = getProviderByName('llamacpp')
|
||||||
const backendType = llamacppProvider?.settings.find(s => s.key === 'version_backend')?.controller_props.value as string
|
const backendType = llamacppProvider?.settings.find(
|
||||||
|
(s) => s.key === 'version_backend'
|
||||||
|
)?.controller_props.value as string
|
||||||
|
|
||||||
const deviceString = updatedState.getActivatedDeviceString(backendType)
|
const deviceString =
|
||||||
|
updatedState.getActivatedDeviceString(backendType)
|
||||||
console.log(`GPU ${index} activation toggled. Backend: "${backendType}", New device string: "${deviceString}"`)
|
|
||||||
console.log('Activated GPUs:', updatedState.hardwareData.gpus.filter(gpu => gpu.activated).map((gpu, i) => ({
|
|
||||||
name: gpu.name,
|
|
||||||
nvidia: gpu.nvidia_info?.index,
|
|
||||||
vulkan: gpu.vulkan_info?.index,
|
|
||||||
activated: gpu.activated
|
|
||||||
})))
|
|
||||||
|
|
||||||
if (llamacppProvider) {
|
if (llamacppProvider) {
|
||||||
const updatedSettings = llamacppProvider.settings.map(setting => {
|
const updatedSettings = llamacppProvider.settings.map((setting) => {
|
||||||
if (setting.key === 'device') {
|
if (setting.key === 'device') {
|
||||||
return {
|
return {
|
||||||
...setting,
|
...setting,
|
||||||
controller_props: {
|
controller_props: {
|
||||||
...setting.controller_props,
|
...setting.controller_props,
|
||||||
value: deviceString
|
value: deviceString,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return setting
|
return setting
|
||||||
})
|
})
|
||||||
|
|
||||||
updateProvider('llamacpp', {
|
updateProvider('llamacpp', {
|
||||||
settings: updatedSettings
|
settings: updatedSettings,
|
||||||
})
|
})
|
||||||
|
|
||||||
console.log(`Updated llamacpp device setting to: "${deviceString}"`)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
setGpuLoading(index, false)
|
setGpuLoading(index, false)
|
||||||
setTimeout(resumePolling, 1000) // Resume polling after 1s
|
setTimeout(resumePolling, 1000) // Resume polling after 1s
|
||||||
@ -359,8 +353,8 @@ export const useHardware = create<HardwareStore>()(
|
|||||||
|
|
||||||
// Get activated GPUs and generate appropriate device format based on backend
|
// Get activated GPUs and generate appropriate device format based on backend
|
||||||
const activatedDevices = hardwareData.gpus
|
const activatedDevices = hardwareData.gpus
|
||||||
.filter(gpu => gpu.activated)
|
.filter((gpu) => gpu.activated)
|
||||||
.map(gpu => {
|
.map((gpu) => {
|
||||||
const isCudaBackend = backendType?.includes('cuda')
|
const isCudaBackend = backendType?.includes('cuda')
|
||||||
const isVulkanBackend = backendType?.includes('vulkan')
|
const isVulkanBackend = backendType?.includes('vulkan')
|
||||||
|
|
||||||
@ -388,7 +382,7 @@ export const useHardware = create<HardwareStore>()(
|
|||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
})
|
})
|
||||||
.filter(device => device !== null) as string[]
|
.filter((device) => device !== null) as string[]
|
||||||
|
|
||||||
const deviceString = activatedDevices.join(',')
|
const deviceString = activatedDevices.join(',')
|
||||||
return deviceString
|
return deviceString
|
||||||
@ -401,23 +395,26 @@ export const useHardware = create<HardwareStore>()(
|
|||||||
// Parse device string to get active device indices
|
// Parse device string to get active device indices
|
||||||
const activeDevices = deviceString
|
const activeDevices = deviceString
|
||||||
.split(',')
|
.split(',')
|
||||||
.map(device => device.trim())
|
.map((device) => device.trim())
|
||||||
.filter(device => device.length > 0)
|
.filter((device) => device.length > 0)
|
||||||
.map(device => {
|
.map((device) => {
|
||||||
const match = device.match(/^(cuda|vulkan):(\d+)$/)
|
const match = device.match(/^(cuda|vulkan):(\d+)$/)
|
||||||
if (match) {
|
if (match) {
|
||||||
return {
|
return {
|
||||||
type: match[1] as 'cuda' | 'vulkan',
|
type: match[1] as 'cuda' | 'vulkan',
|
||||||
index: parseInt(match[2])
|
index: parseInt(match[2]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
})
|
})
|
||||||
.filter(device => device !== null) as Array<{type: 'cuda' | 'vulkan', index: number}>
|
.filter((device) => device !== null) as Array<{
|
||||||
|
type: 'cuda' | 'vulkan'
|
||||||
|
index: number
|
||||||
|
}>
|
||||||
|
|
||||||
// Update GPU activation states
|
// Update GPU activation states
|
||||||
newGPUs.forEach((gpu, gpuIndex) => {
|
newGPUs.forEach((gpu, gpuIndex) => {
|
||||||
const shouldBeActive = activeDevices.some(device => {
|
const shouldBeActive = activeDevices.some((device) => {
|
||||||
if (device.type === 'cuda' && gpu.nvidia_info) {
|
if (device.type === 'cuda' && gpu.nvidia_info) {
|
||||||
return gpu.nvidia_info.index === device.index
|
return gpu.nvidia_info.index === device.index
|
||||||
} else if (device.type === 'vulkan' && gpu.vulkan_info) {
|
} else if (device.type === 'vulkan' && gpu.vulkan_info) {
|
||||||
@ -428,15 +425,15 @@ export const useHardware = create<HardwareStore>()(
|
|||||||
|
|
||||||
newGPUs[gpuIndex] = {
|
newGPUs[gpuIndex] = {
|
||||||
...gpu,
|
...gpu,
|
||||||
activated: shouldBeActive
|
activated: shouldBeActive,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
hardwareData: {
|
hardwareData: {
|
||||||
...state.hardwareData,
|
...state.hardwareData,
|
||||||
gpus: newGPUs
|
gpus: newGPUs,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import { route } from '@/constants/routes'
|
|||||||
import { useModelSources } from '@/hooks/useModelSources'
|
import { useModelSources } from '@/hooks/useModelSources'
|
||||||
import { extractModelName, extractDescription } from '@/lib/models'
|
import { extractModelName, extractDescription } from '@/lib/models'
|
||||||
import { RenderMarkdown } from '@/containers/RenderMarkdown'
|
import { RenderMarkdown } from '@/containers/RenderMarkdown'
|
||||||
import { useEffect, useMemo, useCallback } from 'react'
|
import { useEffect, useMemo, useCallback, useState } from 'react'
|
||||||
import { useModelProvider } from '@/hooks/useModelProvider'
|
import { useModelProvider } from '@/hooks/useModelProvider'
|
||||||
import { useDownloadStore } from '@/hooks/useDownloadStore'
|
import { useDownloadStore } from '@/hooks/useDownloadStore'
|
||||||
import { pullModel } from '@/services/models'
|
import { pullModel } from '@/services/models'
|
||||||
@ -31,6 +31,10 @@ function HubModelDetail() {
|
|||||||
const { downloads, localDownloadingModels, addLocalDownloadingModel } =
|
const { downloads, localDownloadingModels, addLocalDownloadingModel } =
|
||||||
useDownloadStore()
|
useDownloadStore()
|
||||||
|
|
||||||
|
// State for README content
|
||||||
|
const [readmeContent, setReadmeContent] = useState<string>('')
|
||||||
|
const [isLoadingReadme, setIsLoadingReadme] = useState(false)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchSources()
|
fetchSources()
|
||||||
}, [fetchSources])
|
}, [fetchSources])
|
||||||
@ -112,6 +116,24 @@ function HubModelDetail() {
|
|||||||
})
|
})
|
||||||
}, [modelData])
|
}, [modelData])
|
||||||
|
|
||||||
|
|
||||||
|
// Fetch README content when modelData.readme is available
|
||||||
|
useEffect(() => {
|
||||||
|
if (modelData?.readme) {
|
||||||
|
setIsLoadingReadme(true)
|
||||||
|
fetch(modelData.readme)
|
||||||
|
.then((response) => response.text())
|
||||||
|
.then((content) => {
|
||||||
|
setReadmeContent(content)
|
||||||
|
setIsLoadingReadme(false)
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Failed to fetch README:', error)
|
||||||
|
setIsLoadingReadme(false)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, [modelData?.readme])
|
||||||
|
|
||||||
if (!modelData) {
|
if (!modelData) {
|
||||||
return (
|
return (
|
||||||
<div className="flex h-full w-full">
|
<div className="flex h-full w-full">
|
||||||
@ -358,6 +380,49 @@ function HubModelDetail() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* README Section */}
|
||||||
|
{modelData.readme && (
|
||||||
|
<div className="mb-8">
|
||||||
|
<div className="flex items-center gap-2 mb-4">
|
||||||
|
<IconFileCode size={20} className="text-main-view-fg/50" />
|
||||||
|
<h2 className="text-lg font-semibold text-main-view-fg">
|
||||||
|
README
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{isLoadingReadme ? (
|
||||||
|
<div className="flex items-center justify-center py-8">
|
||||||
|
<span className="text-main-view-fg/60">
|
||||||
|
Loading README...
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
) : readmeContent ? (
|
||||||
|
<div className="prose prose-invert max-w-none">
|
||||||
|
<RenderMarkdown
|
||||||
|
enableRawHtml={true}
|
||||||
|
className="text-main-view-fg/80"
|
||||||
|
components={{
|
||||||
|
a: ({ ...props }) => (
|
||||||
|
<a
|
||||||
|
{...props}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
content={readmeContent}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="flex items-center justify-center py-8">
|
||||||
|
<span className="text-main-view-fg/60">
|
||||||
|
Failed to load README
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
import { createFileRoute } from '@tanstack/react-router'
|
import { createFileRoute } from '@tanstack/react-router'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { useHardware } from '@/hooks/useHardware'
|
import { useHardware } from '@/hooks/useHardware'
|
||||||
@ -13,22 +14,28 @@ import { useTranslation } from '@/i18n/react-i18next-compat'
|
|||||||
import { toNumber } from '@/utils/number'
|
import { toNumber } from '@/utils/number'
|
||||||
import { useModelProvider } from '@/hooks/useModelProvider'
|
import { useModelProvider } from '@/hooks/useModelProvider'
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
export const Route = createFileRoute(route.systemMonitor as any)({
|
export const Route = createFileRoute(route.systemMonitor as any)({
|
||||||
component: SystemMonitor,
|
component: SystemMonitor,
|
||||||
})
|
})
|
||||||
|
|
||||||
function SystemMonitor() {
|
function SystemMonitor() {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { hardwareData, systemUsage, updateHardwareDataPreservingGpuOrder, updateSystemUsage, updateGPUActivationFromDeviceString } =
|
const {
|
||||||
useHardware()
|
hardwareData,
|
||||||
|
systemUsage,
|
||||||
|
updateHardwareDataPreservingGpuOrder,
|
||||||
|
updateSystemUsage,
|
||||||
|
updateGPUActivationFromDeviceString,
|
||||||
|
} = useHardware()
|
||||||
const [activeModels, setActiveModels] = useState<string[]>([])
|
const [activeModels, setActiveModels] = useState<string[]>([])
|
||||||
const { providers, getProviderByName } = useModelProvider()
|
const { providers, getProviderByName } = useModelProvider()
|
||||||
const [isInitialized, setIsInitialized] = useState(false)
|
const [isInitialized, setIsInitialized] = useState(false)
|
||||||
|
|
||||||
// Determine backend type and filter GPUs accordingly (same logic as hardware.tsx)
|
// Determine backend type and filter GPUs accordingly (same logic as hardware.tsx)
|
||||||
const llamacpp = providers.find((p) => p.provider === 'llamacpp')
|
const llamacpp = providers.find((p) => p.provider === 'llamacpp')
|
||||||
const versionBackend = llamacpp?.settings.find((s) => s.key === "version_backend")?.controller_props.value
|
const versionBackend = llamacpp?.settings.find(
|
||||||
|
(s) => s.key === 'version_backend'
|
||||||
|
)?.controller_props.value
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Initial data fetch - use updateHardwareDataPreservingGpuOrder like hardware.tsx
|
// Initial data fetch - use updateHardwareDataPreservingGpuOrder like hardware.tsx
|
||||||
@ -52,7 +59,9 @@ function SystemMonitor() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (hardwareData.gpus.length > 0 && !isInitialized) {
|
if (hardwareData.gpus.length > 0 && !isInitialized) {
|
||||||
const llamacppProvider = getProviderByName('llamacpp')
|
const llamacppProvider = getProviderByName('llamacpp')
|
||||||
const currentDeviceSetting = llamacppProvider?.settings.find(s => s.key === 'device')?.controller_props.value as string
|
const currentDeviceSetting = llamacppProvider?.settings.find(
|
||||||
|
(s) => s.key === 'device'
|
||||||
|
)?.controller_props.value as string
|
||||||
|
|
||||||
if (currentDeviceSetting) {
|
if (currentDeviceSetting) {
|
||||||
updateGPUActivationFromDeviceString(currentDeviceSetting)
|
updateGPUActivationFromDeviceString(currentDeviceSetting)
|
||||||
@ -60,45 +69,64 @@ function SystemMonitor() {
|
|||||||
|
|
||||||
setIsInitialized(true)
|
setIsInitialized(true)
|
||||||
}
|
}
|
||||||
}, [hardwareData.gpus.length, isInitialized, getProviderByName, updateGPUActivationFromDeviceString])
|
}, [
|
||||||
|
hardwareData.gpus.length,
|
||||||
|
isInitialized,
|
||||||
|
getProviderByName,
|
||||||
|
updateGPUActivationFromDeviceString,
|
||||||
|
])
|
||||||
|
|
||||||
// Sync device setting when GPU activations change (only after initialization) - same logic as hardware.tsx
|
// Sync device setting when GPU activations change (only after initialization) - same logic as hardware.tsx
|
||||||
const { getActivatedDeviceString } = useHardware()
|
const { getActivatedDeviceString } = useHardware()
|
||||||
const { updateProvider } = useModelProvider()
|
const { updateProvider } = useModelProvider()
|
||||||
const gpuActivationStates = hardwareData.gpus.map(gpu => gpu.activated)
|
const gpuActivationStates = hardwareData.gpus.map((gpu) => gpu.activated)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isInitialized && hardwareData.gpus.length > 0) {
|
if (isInitialized && hardwareData.gpus.length > 0) {
|
||||||
const llamacppProvider = getProviderByName('llamacpp')
|
const llamacppProvider = getProviderByName('llamacpp')
|
||||||
const backendType = llamacppProvider?.settings.find(s => s.key === 'version_backend')?.controller_props.value as string
|
const backendType = llamacppProvider?.settings.find(
|
||||||
|
(s) => s.key === 'version_backend'
|
||||||
|
)?.controller_props.value as string
|
||||||
const deviceString = getActivatedDeviceString(backendType)
|
const deviceString = getActivatedDeviceString(backendType)
|
||||||
|
|
||||||
if (llamacppProvider) {
|
if (llamacppProvider) {
|
||||||
const currentDeviceSetting = llamacppProvider.settings.find(s => s.key === 'device')
|
const currentDeviceSetting = llamacppProvider.settings.find(
|
||||||
|
(s) => s.key === 'device'
|
||||||
|
)
|
||||||
|
|
||||||
// Sync device string when GPU activations change (only after initialization)
|
// Sync device string when GPU activations change (only after initialization)
|
||||||
if (currentDeviceSetting && currentDeviceSetting.controller_props.value !== deviceString) {
|
if (
|
||||||
|
currentDeviceSetting &&
|
||||||
const updatedSettings = llamacppProvider.settings.map(setting => {
|
currentDeviceSetting.controller_props.value !== deviceString
|
||||||
|
) {
|
||||||
|
const updatedSettings = llamacppProvider.settings.map((setting) => {
|
||||||
if (setting.key === 'device') {
|
if (setting.key === 'device') {
|
||||||
return {
|
return {
|
||||||
...setting,
|
...setting,
|
||||||
controller_props: {
|
controller_props: {
|
||||||
...setting.controller_props,
|
...setting.controller_props,
|
||||||
value: deviceString
|
value: deviceString,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return setting
|
return setting
|
||||||
})
|
})
|
||||||
|
|
||||||
updateProvider('llamacpp', {
|
updateProvider('llamacpp', {
|
||||||
settings: updatedSettings
|
settings: updatedSettings,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [isInitialized, gpuActivationStates, versionBackend, getActivatedDeviceString, updateProvider, getProviderByName, hardwareData.gpus.length])
|
}, [
|
||||||
|
isInitialized,
|
||||||
|
gpuActivationStates,
|
||||||
|
versionBackend,
|
||||||
|
getActivatedDeviceString,
|
||||||
|
updateProvider,
|
||||||
|
getProviderByName,
|
||||||
|
hardwareData.gpus.length,
|
||||||
|
])
|
||||||
|
|
||||||
const stopRunningModel = (modelId: string) => {
|
const stopRunningModel = (modelId: string) => {
|
||||||
stopModel(modelId)
|
stopModel(modelId)
|
||||||
@ -120,8 +148,10 @@ function SystemMonitor() {
|
|||||||
) * 100
|
) * 100
|
||||||
|
|
||||||
// Determine backend type and filter GPUs accordingly
|
// Determine backend type and filter GPUs accordingly
|
||||||
const isCudaBackend = typeof versionBackend === 'string' && versionBackend.includes('cuda')
|
const isCudaBackend =
|
||||||
const isVulkanBackend = typeof versionBackend === 'string' && versionBackend.includes('vulkan')
|
typeof versionBackend === 'string' && versionBackend.includes('cuda')
|
||||||
|
const isVulkanBackend =
|
||||||
|
typeof versionBackend === 'string' && versionBackend.includes('vulkan')
|
||||||
|
|
||||||
// Check if GPU should be active based on backend compatibility
|
// Check if GPU should be active based on backend compatibility
|
||||||
const isGPUCompatible = (gpu: any) => {
|
const isGPUCompatible = (gpu: any) => {
|
||||||
@ -144,7 +174,7 @@ function SystemMonitor() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Filter to show only active GPUs
|
// Filter to show only active GPUs
|
||||||
const activeGPUs = hardwareData.gpus.filter(gpu => isGPUActive(gpu))
|
const activeGPUs = hardwareData.gpus.filter((gpu) => isGPUActive(gpu))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col h-full bg-main-view overflow-y-auto p-6">
|
<div className="flex flex-col h-full bg-main-view overflow-y-auto p-6">
|
||||||
@ -313,8 +343,9 @@ function SystemMonitor() {
|
|||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
{activeGPUs.map((gpu, index) => {
|
{activeGPUs.map((gpu, index) => {
|
||||||
// Find the corresponding system usage data for this GPU
|
// Find the corresponding system usage data for this GPU
|
||||||
const gpuUsage = systemUsage.gpus.find(usage => usage.uuid === gpu.uuid)
|
const gpuUsage = systemUsage.gpus.find(
|
||||||
const gpuIndex = hardwareData.gpus.findIndex(hwGpu => hwGpu.uuid === gpu.uuid)
|
(usage) => usage.uuid === gpu.uuid
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@ -337,13 +368,13 @@ function SystemMonitor() {
|
|||||||
<span className="text-main-view-fg">
|
<span className="text-main-view-fg">
|
||||||
{gpuUsage ? (
|
{gpuUsage ? (
|
||||||
<>
|
<>
|
||||||
{formatMegaBytes(gpuUsage.used_memory)}{' '}
|
{formatMegaBytes(gpuUsage.used_memory)} /{' '}
|
||||||
/ {formatMegaBytes(gpu.total_memory)}
|
{formatMegaBytes(gpu.total_memory)}
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
{formatMegaBytes(0)}{' '}
|
{formatMegaBytes(0)} /{' '}
|
||||||
/ {formatMegaBytes(gpu.total_memory)}
|
{formatMegaBytes(gpu.total_memory)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
@ -362,14 +393,16 @@ function SystemMonitor() {
|
|||||||
</span>
|
</span>
|
||||||
<span className="text-main-view-fg">
|
<span className="text-main-view-fg">
|
||||||
{gpu.nvidia_info?.compute_capability ||
|
{gpu.nvidia_info?.compute_capability ||
|
||||||
gpu.vulkan_info?.api_version || '-'}
|
gpu.vulkan_info?.api_version ||
|
||||||
|
'-'}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-2">
|
<div className="mt-2">
|
||||||
<Progress
|
<Progress
|
||||||
value={
|
value={
|
||||||
gpuUsage ?
|
gpuUsage
|
||||||
((gpuUsage.used_memory / gpu.total_memory) * 100) : 0
|
? (gpuUsage.used_memory / gpu.total_memory) * 100
|
||||||
|
: 0
|
||||||
}
|
}
|
||||||
className="h-2 w-full"
|
className="h-2 w-full"
|
||||||
/>
|
/>
|
||||||
@ -385,7 +418,6 @@ function SystemMonitor() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,6 +20,7 @@ export interface CatalogModel {
|
|||||||
num_quants: number
|
num_quants: number
|
||||||
quants: ModelQuant[]
|
quants: ModelQuant[]
|
||||||
created_at?: string
|
created_at?: string
|
||||||
|
readme?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ModelCatalog = CatalogModel[]
|
export type ModelCatalog = CatalogModel[]
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user