mirror of
https://github.com/lone-cloud/gerbil
synced 2026-06-03 19:54:44 -07:00
warnings for users that don't have cuda/rocm installed but use binaries that support them
This commit is contained in:
parent
0410e199f1
commit
c1b7c7f73e
15 changed files with 272 additions and 68 deletions
|
|
@ -1,3 +1,4 @@
|
|||
alsa
|
||||
AMDGPU
|
||||
APPIMAGE
|
||||
asar
|
||||
|
|
@ -29,6 +30,7 @@ KOBOLDAI
|
|||
koboldcpp
|
||||
KoboldCpp
|
||||
KOBOLDCPP
|
||||
libxss
|
||||
lora
|
||||
lowvram
|
||||
Lowvram
|
||||
|
|
@ -50,8 +52,16 @@ nvidia
|
|||
oldpc
|
||||
OLDPC
|
||||
opencl
|
||||
optdepends
|
||||
paru
|
||||
pkexec
|
||||
pkgbase
|
||||
PKGBUILD
|
||||
pkgdesc
|
||||
pkgdir
|
||||
pkgname
|
||||
pkgrel
|
||||
pkgver
|
||||
quantmatmul
|
||||
radeon
|
||||
remotetunnel
|
||||
|
|
@ -70,6 +80,8 @@ SDXL
|
|||
Segoe
|
||||
sonarjs
|
||||
SPACEBAR
|
||||
squashfs
|
||||
SRCINFO
|
||||
taskkill
|
||||
Tauri
|
||||
togglefullscreen
|
||||
|
|
|
|||
4
.github/workflows/aur-release.yml
vendored
4
.github/workflows/aur-release.yml
vendored
|
|
@ -100,7 +100,7 @@ jobs:
|
|||
# Maintainer: ${{ steps.release_info.outputs.author_name }} <${{ steps.release_info.outputs.author_email }}>
|
||||
pkgname=friendly-kobold
|
||||
pkgver=${{ steps.release_info.outputs.version }}
|
||||
pkgrel=2
|
||||
pkgrel=3
|
||||
pkgdesc="A desktop app for running Large Language Models locally"
|
||||
arch=('x86_64')
|
||||
url="https://github.com/lone-cloud/friendly-kobold"
|
||||
|
|
@ -167,7 +167,7 @@ jobs:
|
|||
pkgbase = friendly-kobold
|
||||
pkgdesc = A desktop app for running Large Language Models locally
|
||||
pkgver = ${{ steps.release_info.outputs.version }}
|
||||
pkgrel = 2
|
||||
pkgrel = 3
|
||||
url = https://github.com/lone-cloud/friendly-kobold
|
||||
arch = x86_64
|
||||
license = AGPL-3.0-or-later
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "friendly-kobold",
|
||||
"productName": "Friendly Kobold",
|
||||
"version": "0.6.1",
|
||||
"version": "0.6.2",
|
||||
"description": "A desktop app for running Large Language Models locally",
|
||||
"main": "out/main/index.js",
|
||||
"homepage": "./",
|
||||
|
|
|
|||
|
|
@ -33,16 +33,14 @@ export const AdvancedTab = () => {
|
|||
useEffect(() => {
|
||||
const detectBackendSupport = async () => {
|
||||
try {
|
||||
const currentBinaryInfo =
|
||||
await window.electronAPI.kobold.getCurrentBinaryInfo();
|
||||
if (currentBinaryInfo?.path) {
|
||||
const support = await window.electronAPI.kobold.detectBackendSupport(
|
||||
currentBinaryInfo.path
|
||||
);
|
||||
const support = await window.electronAPI.kobold.detectBackendSupport();
|
||||
if (support) {
|
||||
setBackendSupport({
|
||||
noavx2: support.noavx2,
|
||||
failsafe: support.failsafe,
|
||||
});
|
||||
} else {
|
||||
setBackendSupport({ noavx2: false, failsafe: false });
|
||||
}
|
||||
} catch (error) {
|
||||
window.electronAPI.logs.logError(
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { useState, useEffect, useRef } from 'react';
|
|||
import { InfoTooltip } from '@/components/InfoTooltip';
|
||||
import { BackendSelectItem } from '@/components/screens/Launch/GeneralTab/BackendSelectItem';
|
||||
import { useLaunchConfig } from '@/hooks/useLaunchConfig';
|
||||
import { checkBackendWarnings } from '@/utils/backendWarnings';
|
||||
|
||||
interface BackendSelectorProps {
|
||||
onWarningsChange?: (
|
||||
|
|
@ -89,41 +90,26 @@ export const BackendSelector = ({
|
|||
useEffect(() => {
|
||||
if (!onWarningsChange) return;
|
||||
|
||||
if (backend !== 'cpu' || !cpuCapabilities) {
|
||||
onWarningsChange([]);
|
||||
return;
|
||||
}
|
||||
const updateWarnings = async () => {
|
||||
try {
|
||||
const warnings = await checkBackendWarnings({
|
||||
backend,
|
||||
cpuCapabilities,
|
||||
noavx2,
|
||||
failsafe,
|
||||
availableBackends,
|
||||
});
|
||||
onWarningsChange(warnings);
|
||||
} catch (error) {
|
||||
window.electronAPI.logs.logError(
|
||||
'Failed to check backend warnings:',
|
||||
error as Error
|
||||
);
|
||||
onWarningsChange([]);
|
||||
}
|
||||
};
|
||||
|
||||
const warnings: Array<{ type: 'warning' | 'info'; message: string }> = [];
|
||||
|
||||
if (!cpuCapabilities.avx2 && !noavx2) {
|
||||
warnings.push({
|
||||
type: 'warning',
|
||||
message:
|
||||
'Your CPU does not support AVX2. Enable the "Disable AVX2" option on the Advanced tab to avoid crashes.',
|
||||
});
|
||||
}
|
||||
|
||||
if (!cpuCapabilities.avx && !cpuCapabilities.avx2 && !failsafe) {
|
||||
warnings.push({
|
||||
type: 'warning',
|
||||
message:
|
||||
'Your CPU does not support AVX or AVX2. Enable the "Failsafe" option on the Advanced tab to avoid crashes.',
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
availableBackends.length > 0 &&
|
||||
availableBackends.some((b) => b.value === 'cpu')
|
||||
) {
|
||||
warnings.push({
|
||||
type: 'info',
|
||||
message:
|
||||
"Performance Note: LLMs run significantly faster on GPU-accelerated systems. Consider using NVIDIA's CUDA or AMD's ROCm backends for optimal performance.",
|
||||
});
|
||||
}
|
||||
|
||||
onWarningsChange(warnings);
|
||||
updateWarnings();
|
||||
}, [
|
||||
backend,
|
||||
cpuCapabilities,
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ class FriendlyKoboldApp {
|
|||
this.ensureInstallDirectory();
|
||||
this.windowManager = new WindowManager();
|
||||
this.githubService = new GitHubService(this.logManager);
|
||||
this.hardwareService = new HardwareService();
|
||||
this.hardwareService = new HardwareService(this.logManager);
|
||||
|
||||
this.koboldManager = new KoboldCppManager(
|
||||
this.configManager,
|
||||
|
|
|
|||
|
|
@ -142,8 +142,10 @@ export class KoboldCppManager {
|
|||
try {
|
||||
unlinkSync(tempPackedFilePath);
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn('Failed to cleanup packed file:', error);
|
||||
this.logManager.logError(
|
||||
'Failed to cleanup packed file:',
|
||||
error as Error
|
||||
);
|
||||
}
|
||||
|
||||
const launcherPath = this.getLauncherPath(unpackedDirPath);
|
||||
|
|
@ -700,8 +702,10 @@ export class KoboldCppManager {
|
|||
try {
|
||||
unlinkSync(tempPackedFilePath);
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn('Failed to cleanup packed ROCm file:', error);
|
||||
this.logManager.logError(
|
||||
'Failed to cleanup packed ROCm file:',
|
||||
error as Error
|
||||
);
|
||||
}
|
||||
|
||||
const launcherPath = this.getLauncherPath(unpackedDirPath);
|
||||
|
|
|
|||
|
|
@ -33,7 +33,9 @@ export class BinaryService {
|
|||
this.hardwareService = hardwareService;
|
||||
}
|
||||
|
||||
detectBackendSupport(koboldBinaryPath: string): BackendSupport {
|
||||
private detectBackendSupportFromPath(
|
||||
koboldBinaryPath: string
|
||||
): BackendSupport {
|
||||
if (this.backendSupportCache.has(koboldBinaryPath)) {
|
||||
return this.backendSupportCache.get(koboldBinaryPath)!;
|
||||
}
|
||||
|
|
@ -87,6 +89,24 @@ export class BinaryService {
|
|||
return support;
|
||||
}
|
||||
|
||||
async detectBackendSupport(): Promise<BackendSupport | null> {
|
||||
try {
|
||||
const currentBinaryInfo = await this.koboldManager.getCurrentBinaryInfo();
|
||||
|
||||
if (!currentBinaryInfo?.path) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.detectBackendSupportFromPath(currentBinaryInfo.path);
|
||||
} catch (error) {
|
||||
this.logManager.logError(
|
||||
'Error detecting current binary backend support:',
|
||||
error as Error
|
||||
);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async getAvailableBackends(): Promise<
|
||||
Array<{ value: string; label: string; devices?: string[] }>
|
||||
> {
|
||||
|
|
@ -106,7 +126,12 @@ export class BinaryService {
|
|||
return this.availableBackendsCache.get(cacheKey)!;
|
||||
}
|
||||
|
||||
const backendSupport = this.detectBackendSupport(currentBinaryInfo.path);
|
||||
const backendSupport = await this.detectBackendSupport();
|
||||
|
||||
if (!backendSupport) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const backends: Array<{
|
||||
value: string;
|
||||
label: string;
|
||||
|
|
|
|||
|
|
@ -24,8 +24,7 @@ export class GitHubService {
|
|||
|
||||
if (!response.ok) {
|
||||
if (response.status === 403) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn(
|
||||
this.logManager.logError(
|
||||
'GitHub API rate limit reached, using cached data if available'
|
||||
);
|
||||
return this.cachedRelease
|
||||
|
|
@ -78,8 +77,7 @@ export class GitHubService {
|
|||
|
||||
if (!response.ok) {
|
||||
if (response.status === 403) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn(
|
||||
this.logManager.logError(
|
||||
'GitHub API rate limit reached, using cached data if available'
|
||||
);
|
||||
return this.cachedRelease;
|
||||
|
|
|
|||
|
|
@ -1,17 +1,25 @@
|
|||
/* eslint-disable no-comments/disallowComments */
|
||||
import si from 'systeminformation';
|
||||
import { shortenDeviceName } from '@/utils';
|
||||
import { LogManager } from '@/main/managers/LogManager';
|
||||
import type {
|
||||
CPUCapabilities,
|
||||
GPUCapabilities,
|
||||
BasicGPUInfo,
|
||||
HardwareInfo,
|
||||
GPUMemoryInfo,
|
||||
} from '@/types/hardware';
|
||||
|
||||
export class HardwareService {
|
||||
private cpuCapabilitiesCache: CPUCapabilities | null = null;
|
||||
private basicGPUInfoCache: BasicGPUInfo | null = null;
|
||||
private gpuCapabilitiesCache: GPUCapabilities | null = null;
|
||||
private gpuMemoryInfoCache: GPUMemoryInfo[] | null = null;
|
||||
private logManager: LogManager;
|
||||
|
||||
constructor(logManager: LogManager) {
|
||||
this.logManager = logManager;
|
||||
}
|
||||
|
||||
async detectCPU(): Promise<CPUCapabilities> {
|
||||
if (this.cpuCapabilitiesCache) {
|
||||
|
|
@ -37,8 +45,7 @@ export class HardwareService {
|
|||
|
||||
return this.cpuCapabilitiesCache;
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn('CPU detection failed:', error);
|
||||
this.logManager.logError('CPU detection failed:', error as Error);
|
||||
const fallbackCapabilities = {
|
||||
avx: false,
|
||||
avx2: false,
|
||||
|
|
@ -98,8 +105,7 @@ export class HardwareService {
|
|||
|
||||
return this.basicGPUInfoCache;
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn('GPU detection failed:', error);
|
||||
this.logManager.logError('GPU detection failed:', error as Error);
|
||||
const fallbackGPUInfo = {
|
||||
hasAMD: false,
|
||||
hasNVIDIA: false,
|
||||
|
|
@ -443,4 +449,37 @@ export class HardwareService {
|
|||
return { supported: false, devices: [] };
|
||||
}
|
||||
}
|
||||
|
||||
async detectGPUMemory(): Promise<GPUMemoryInfo[]> {
|
||||
if (this.gpuMemoryInfoCache) {
|
||||
return this.gpuMemoryInfoCache;
|
||||
}
|
||||
|
||||
const memoryInfo: GPUMemoryInfo[] = [];
|
||||
|
||||
try {
|
||||
const graphics = await si.graphics();
|
||||
|
||||
for (const controller of graphics.controllers) {
|
||||
if (controller.model) {
|
||||
let vram = controller.vram;
|
||||
// systeminformation returns 0 or 1 if unknown/invalid
|
||||
if (!vram || vram === 1) {
|
||||
vram = null;
|
||||
}
|
||||
memoryInfo.push({
|
||||
deviceName: shortenDeviceName(controller.model),
|
||||
totalMemoryMB: vram,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.gpuMemoryInfoCache = memoryInfo;
|
||||
} catch (error) {
|
||||
this.logManager.logError('GPU memory detection failed:', error as Error);
|
||||
this.gpuMemoryInfoCache = [];
|
||||
}
|
||||
|
||||
return this.gpuMemoryInfoCache;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -112,6 +112,10 @@ export class IPCHandlers {
|
|||
this.hardwareService.detectGPUCapabilities()
|
||||
);
|
||||
|
||||
ipcMain.handle('kobold:detectGPUMemory', () =>
|
||||
this.hardwareService.detectGPUMemory()
|
||||
);
|
||||
|
||||
ipcMain.handle('kobold:detectROCm', () =>
|
||||
this.hardwareService.detectROCm()
|
||||
);
|
||||
|
|
@ -120,8 +124,8 @@ export class IPCHandlers {
|
|||
this.hardwareService.detectAllWithCapabilities()
|
||||
);
|
||||
|
||||
ipcMain.handle('kobold:detectBackendSupport', (_, binaryPath: string) =>
|
||||
this.binaryService.detectBackendSupport(binaryPath)
|
||||
ipcMain.handle('kobold:detectBackendSupport', () =>
|
||||
this.binaryService.detectBackendSupport()
|
||||
);
|
||||
|
||||
ipcMain.handle('kobold:getAvailableBackends', () =>
|
||||
|
|
|
|||
|
|
@ -14,17 +14,19 @@ const koboldAPI: KoboldAPI = {
|
|||
getPlatform: () => ipcRenderer.invoke('kobold:getPlatform'),
|
||||
detectGPU: () => ipcRenderer.invoke('kobold:detectGPU'),
|
||||
detectCPU: () => ipcRenderer.invoke('kobold:detectCPU'),
|
||||
detectGPUCapabilities: () =>
|
||||
ipcRenderer.invoke('kobold:detectGPUCapabilities'),
|
||||
detectGPUMemory: () => ipcRenderer.invoke('kobold:detectGPUMemory'),
|
||||
detectROCm: () => ipcRenderer.invoke('kobold:detectROCm'),
|
||||
detectBackendSupport: (binaryPath: string) =>
|
||||
ipcRenderer.invoke('kobold:detectBackendSupport', binaryPath),
|
||||
detectBackendSupport: () => ipcRenderer.invoke('kobold:detectBackendSupport'),
|
||||
getAvailableBackends: () => ipcRenderer.invoke('kobold:getAvailableBackends'),
|
||||
getCurrentInstallDir: () => ipcRenderer.invoke('kobold:getCurrentInstallDir'),
|
||||
selectInstallDirectory: () =>
|
||||
ipcRenderer.invoke('kobold:selectInstallDirectory'),
|
||||
downloadRelease: (asset) =>
|
||||
ipcRenderer.invoke('kobold:downloadRelease', asset),
|
||||
launchKoboldCpp: (args?: string[], configFilePath?: string) =>
|
||||
ipcRenderer.invoke('kobold:launchKoboldCpp', args, configFilePath),
|
||||
launchKoboldCpp: (args?: string[]) =>
|
||||
ipcRenderer.invoke('kobold:launchKoboldCpp', args),
|
||||
getConfigFiles: () => ipcRenderer.invoke('kobold:getConfigFiles'),
|
||||
saveConfigFile: (
|
||||
configName: string,
|
||||
|
|
|
|||
10
src/types/electron.d.ts
vendored
10
src/types/electron.d.ts
vendored
|
|
@ -4,6 +4,7 @@ import type {
|
|||
BasicGPUInfo,
|
||||
HardwareInfo,
|
||||
PlatformInfo,
|
||||
GPUMemoryInfo,
|
||||
} from '@/types/hardware';
|
||||
|
||||
interface GitHubAsset {
|
||||
|
|
@ -67,15 +68,17 @@ export interface KoboldAPI {
|
|||
getPlatform: () => Promise<PlatformInfo>;
|
||||
detectGPU: () => Promise<BasicGPUInfo>;
|
||||
detectCPU: () => Promise<CPUCapabilities>;
|
||||
detectGPUCapabilities: () => Promise<GPUCapabilities>;
|
||||
detectGPUMemory: () => Promise<GPUMemoryInfo[]>;
|
||||
detectROCm: () => Promise<{ supported: boolean; devices: string[] }>;
|
||||
detectBackendSupport: (binaryPath: string) => Promise<{
|
||||
detectBackendSupport: () => Promise<{
|
||||
rocm: boolean;
|
||||
vulkan: boolean;
|
||||
clblast: boolean;
|
||||
noavx2: boolean;
|
||||
failsafe: boolean;
|
||||
cuda: boolean;
|
||||
}>;
|
||||
} | null>;
|
||||
getAvailableBackends: () => Promise<
|
||||
Array<{ value: string; label: string; devices?: string[] }>
|
||||
>;
|
||||
|
|
@ -92,8 +95,7 @@ export interface KoboldAPI {
|
|||
getROCmDownload: () => Promise<DownloadItem | null>;
|
||||
getLatestReleaseWithStatus: () => Promise<ReleaseWithStatus | null>;
|
||||
launchKoboldCpp: (
|
||||
args?: string[],
|
||||
configFilePath?: string
|
||||
args?: string[]
|
||||
) => Promise<{ success: boolean; pid?: number; error?: string }>;
|
||||
getConfigFiles: () => Promise<
|
||||
Array<{ name: string; path: string; size: number }>
|
||||
|
|
|
|||
5
src/types/hardware.d.ts
vendored
5
src/types/hardware.d.ts
vendored
|
|
@ -4,6 +4,11 @@ export interface CPUCapabilities {
|
|||
devices: string[];
|
||||
}
|
||||
|
||||
export interface GPUMemoryInfo {
|
||||
deviceName: string;
|
||||
totalMemoryMB: number | null;
|
||||
}
|
||||
|
||||
export interface GPUCapabilities {
|
||||
cuda: {
|
||||
supported: boolean;
|
||||
|
|
|
|||
129
src/utils/backendWarnings.ts
Normal file
129
src/utils/backendWarnings.ts
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
export interface BackendWarning {
|
||||
type: 'warning' | 'info';
|
||||
message: string;
|
||||
}
|
||||
|
||||
interface WarningParams {
|
||||
backend: string;
|
||||
cpuCapabilities: {
|
||||
avx: boolean;
|
||||
avx2: boolean;
|
||||
} | null;
|
||||
noavx2: boolean;
|
||||
failsafe: boolean;
|
||||
availableBackends: Array<{
|
||||
value: string;
|
||||
label: string;
|
||||
devices?: string[];
|
||||
}>;
|
||||
}
|
||||
|
||||
export const checkBackendWarnings = async (
|
||||
params?: WarningParams
|
||||
// eslint-disable-next-line sonarjs/cognitive-complexity
|
||||
): Promise<BackendWarning[]> => {
|
||||
const warnings: BackendWarning[] = [];
|
||||
|
||||
try {
|
||||
const [backendSupport, gpuCapabilities] = await Promise.all([
|
||||
window.electronAPI.kobold.detectBackendSupport(),
|
||||
window.electronAPI.kobold.detectGPUCapabilities(),
|
||||
]);
|
||||
|
||||
if (!backendSupport) {
|
||||
return warnings;
|
||||
}
|
||||
|
||||
if (backendSupport.cuda && !gpuCapabilities.cuda.supported) {
|
||||
warnings.push({
|
||||
type: 'warning',
|
||||
message:
|
||||
'Your KoboldCpp binary supports CUDA, but CUDA runtime is not detected on your system.',
|
||||
});
|
||||
}
|
||||
|
||||
if (backendSupport.rocm && !gpuCapabilities.rocm.supported) {
|
||||
warnings.push({
|
||||
type: 'warning',
|
||||
message:
|
||||
'Your KoboldCpp binary supports ROCm, but ROCm runtime is not detected on your system.',
|
||||
});
|
||||
}
|
||||
|
||||
if (params) {
|
||||
const { backend, cpuCapabilities, noavx2, failsafe, availableBackends } =
|
||||
params;
|
||||
|
||||
const isGpuBackend = ['cuda', 'rocm', 'vulkan', 'clblast'].includes(
|
||||
backend
|
||||
);
|
||||
|
||||
if (isGpuBackend) {
|
||||
try {
|
||||
const gpuMemoryInfo =
|
||||
await window.electronAPI.kobold.detectGPUMemory();
|
||||
const lowVramGpus = gpuMemoryInfo.filter(
|
||||
(gpu) =>
|
||||
typeof gpu.totalMemoryMB === 'number' && gpu.totalMemoryMB < 8192
|
||||
);
|
||||
|
||||
if (lowVramGpus.length > 0) {
|
||||
warnings.push({
|
||||
type: 'warning',
|
||||
message: `Low VRAM detected (${lowVramGpus
|
||||
.map(
|
||||
(gpu) =>
|
||||
`${gpu.deviceName}: ${(gpu.totalMemoryMB! / 1024).toFixed(1)}GB`
|
||||
)
|
||||
.join(
|
||||
', '
|
||||
)}). Consider using smaller models, reducing GPU layers, or enabling the "Low VRAM" option on the Advanced tab.`,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
window.electronAPI.logs.logError(
|
||||
'Failed to detect GPU memory:',
|
||||
error as Error
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (backend === 'cpu' && cpuCapabilities) {
|
||||
if (!cpuCapabilities.avx2 && !noavx2) {
|
||||
warnings.push({
|
||||
type: 'warning',
|
||||
message:
|
||||
'Your CPU does not support AVX2. Enable the "Disable AVX2" option on the Advanced tab to avoid crashes.',
|
||||
});
|
||||
}
|
||||
|
||||
if (!cpuCapabilities.avx && !cpuCapabilities.avx2 && !failsafe) {
|
||||
warnings.push({
|
||||
type: 'warning',
|
||||
message:
|
||||
'Your CPU does not support AVX or AVX2. Enable the "Failsafe" option on the Advanced tab to avoid crashes.',
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
availableBackends.length > 0 &&
|
||||
availableBackends.some((b) => b.value === 'cpu')
|
||||
) {
|
||||
warnings.push({
|
||||
type: 'info',
|
||||
message:
|
||||
"LLMs run significantly faster on GPU-accelerated systems. Consider using NVIDIA's CUDA, AMD's ROCm or Vulkan backends for optimal performance.",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return warnings;
|
||||
} catch (error) {
|
||||
window.electronAPI.logs.logError(
|
||||
'Failed to check backend warnings:',
|
||||
error as Error
|
||||
);
|
||||
return warnings;
|
||||
}
|
||||
};
|
||||
Loading…
Add table
Reference in a new issue