windows fixes of linux fixes of windows fixes

This commit is contained in:
Egor 2025-08-21 00:14:47 -07:00
parent c0f1b4790c
commit 982d6e4951
8 changed files with 159 additions and 128 deletions

View file

@ -40,11 +40,9 @@ export const BackendSelector = ({
useEffect(() => {
const loadBackends = async () => {
try {
const [currentBinaryInfo, cpuCapabilitiesResult, gpuCapabilities] =
await Promise.all([
window.electronAPI.kobold.getCurrentBinaryInfo(),
const [cpuCapabilitiesResult, backends] = await Promise.all([
window.electronAPI.kobold.detectCPU(),
window.electronAPI.kobold.detectGPUCapabilities(),
window.electronAPI.kobold.getAvailableBackends(),
]);
setCpuCapabilities({
@ -52,23 +50,10 @@ export const BackendSelector = ({
avx2: cpuCapabilitiesResult.avx2,
});
let backends: Array<{
value: string;
label: string;
devices?: string[];
}> = [];
if (currentBinaryInfo?.path) {
backends = await window.electronAPI.kobold.getAvailableBackends(
currentBinaryInfo.path,
gpuCapabilities
);
const cpuBackend = backends.find((b) => b.value === 'cpu');
if (cpuBackend) {
cpuBackend.devices = cpuCapabilitiesResult.devices;
}
}
setAvailableBackends(backends);
hasInitialized.current = true;
@ -231,7 +216,7 @@ export const BackendSelector = ({
step={1}
size="sm"
w={80}
disabled={autoGpuLayers}
disabled={autoGpuLayers || backend === 'cpu'}
/>
<Group gap="xs" align="center">
<Checkbox
@ -241,6 +226,7 @@ export const BackendSelector = ({
handleAutoGpuLayersChange(event.currentTarget.checked)
}
size="sm"
disabled={backend === 'cpu'}
/>
<InfoTooltip label="Automatically try to allocate the GPU layers based on available VRAM." />
</Group>

View file

@ -76,10 +76,7 @@ export const LaunchScreen = ({
const setHappyDefaults = useCallback(async () => {
try {
const backends = await window.electronAPI.kobold.getAvailableBackends(
(await window.electronAPI.kobold.getCurrentBinaryInfo())?.path || '',
await window.electronAPI.kobold.detectGPUCapabilities()
);
const backends = await window.electronAPI.kobold.getAvailableBackends();
if (!backend && backends.length > 0) {
handleBackendChange(backends[0].value);

View file

@ -35,7 +35,6 @@ class FriendlyKoboldApp {
this.windowManager = new WindowManager();
this.githubService = new GitHubService(this.logManager);
this.hardwareService = new HardwareService();
this.binaryService = new BinaryService(this.logManager);
this.koboldManager = new KoboldCppManager(
this.configManager,
@ -44,6 +43,12 @@ class FriendlyKoboldApp {
this.logManager
);
this.binaryService = new BinaryService(
this.logManager,
this.koboldManager,
this.hardwareService
);
this.ipcHandlers = new IPCHandlers(
this.koboldManager,
this.configManager,

View file

@ -1,6 +1,8 @@
import { existsSync } from 'fs';
import { join, dirname } from 'path';
import { LogManager } from '@/main/managers/LogManager';
import type { KoboldCppManager } from '@/main/managers/KoboldCppManager';
import type { HardwareService } from '@/main/services/HardwareService';
export interface BackendSupport {
rocm: boolean;
@ -18,9 +20,17 @@ export class BinaryService {
Array<{ value: string; label: string; devices?: string[] }>
>();
private logManager: LogManager;
private koboldManager: KoboldCppManager;
private hardwareService: HardwareService;
constructor(logManager: LogManager) {
constructor(
logManager: LogManager,
koboldManager: KoboldCppManager,
hardwareService: HardwareService
) {
this.logManager = logManager;
this.koboldManager = koboldManager;
this.hardwareService = hardwareService;
}
detectBackendSupport(koboldBinaryPath: string): BackendSupport {
@ -46,7 +56,18 @@ export class BinaryService {
const hasKoboldCppLib = (name: string) => {
const filename = `${name}${libExtension}`;
return existsSync(join(internalDir, filename));
if (platform === 'win32') {
return (
existsSync(join(binaryDir, filename)) ||
existsSync(join(internalDir, filename))
);
} else {
return (
existsSync(join(internalDir, filename)) ||
existsSync(join(binaryDir, filename))
);
}
};
support.rocm = hasKoboldCppLib('koboldcpp_hipblas');
@ -66,29 +87,33 @@ export class BinaryService {
return support;
}
getAvailableBackends(
koboldBinaryPath: string,
hardwareCapabilities?: {
cuda: { supported: boolean; devices: string[] };
rocm: { supported: boolean; devices: string[] };
vulkan: { supported: boolean; devices: string[] };
clblast: { supported: boolean; devices: string[] };
async getAvailableBackends(): Promise<
Array<{ value: string; label: string; devices?: string[] }>
> {
try {
const [currentBinaryInfo, hardwareCapabilities] = await Promise.all([
this.koboldManager.getCurrentBinaryInfo(),
this.hardwareService.detectGPUCapabilities(),
]);
if (!currentBinaryInfo?.path) {
return [{ value: 'cpu', label: 'CPU' }];
}
): Array<{ value: string; label: string; devices?: string[] }> {
const cacheKey = `${koboldBinaryPath}:${JSON.stringify(hardwareCapabilities)}`;
const cacheKey = `${currentBinaryInfo.path}:${JSON.stringify(hardwareCapabilities)}`;
if (this.availableBackendsCache.has(cacheKey)) {
return this.availableBackendsCache.get(cacheKey)!;
}
const backendSupport = this.detectBackendSupport(koboldBinaryPath);
const backendSupport = this.detectBackendSupport(currentBinaryInfo.path);
const backends: Array<{
value: string;
label: string;
devices?: string[];
}> = [];
if (backendSupport.cuda && hardwareCapabilities?.cuda.supported) {
if (backendSupport.cuda && hardwareCapabilities.cuda.supported) {
backends.push({
value: 'cuda',
label: 'CUDA',
@ -96,7 +121,7 @@ export class BinaryService {
});
}
if (backendSupport.rocm && hardwareCapabilities?.rocm.supported) {
if (backendSupport.rocm && hardwareCapabilities.rocm.supported) {
backends.push({
value: 'rocm',
label: 'ROCm',
@ -104,7 +129,7 @@ export class BinaryService {
});
}
if (backendSupport.vulkan && hardwareCapabilities?.vulkan.supported) {
if (backendSupport.vulkan && hardwareCapabilities.vulkan.supported) {
backends.push({
value: 'vulkan',
label: 'Vulkan',
@ -112,7 +137,7 @@ export class BinaryService {
});
}
if (backendSupport.clblast && hardwareCapabilities?.clblast.supported) {
if (backendSupport.clblast && hardwareCapabilities.clblast.supported) {
backends.push({
value: 'clblast',
label: 'CLBlast',
@ -127,6 +152,13 @@ export class BinaryService {
this.availableBackendsCache.set(cacheKey, backends);
return backends;
} catch (error) {
this.logManager.logError(
'Failed to get available backends:',
error as Error
);
return [{ value: 'cpu', label: 'CPU' }];
}
}
clearCache(): void {

View file

@ -125,6 +125,7 @@ export class HardwareService {
]);
this.gpuCapabilitiesCache = { cuda, rocm, vulkan, clblast };
return this.gpuCapabilitiesCache;
}
@ -303,13 +304,17 @@ export class HardwareService {
const lines = output.split('\n');
for (const line of lines) {
if (line.includes('deviceName')) {
const name = line.split('=')[1]?.trim();
// Handle both formats: "deviceName = AMD Radeon RX 7900 GRE" and other potential formats
if (line.includes('deviceName') && line.includes('=')) {
const parts = line.split('=');
if (parts.length >= 2) {
const name = parts[1]?.trim();
if (name) {
devices.push(shortenDeviceName(name));
}
}
}
}
resolve({
supported: devices.length > 0,
@ -343,29 +348,23 @@ export class HardwareService {
const lines = output.split('\n');
let currentPlatform = '';
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
// Extract platform name
for (let i = 0; i < lines.length; i++) {
const line = lines[i].trim();
// Extract platform name - this appears early in the output
if (line.includes('Platform Name:')) {
currentPlatform = line.split('Platform Name:')[1]?.trim() || '';
continue;
}
// Extract device names for GPU devices
if (line.includes('Device Name:')) {
const deviceName = line.split('Device Name:')[1]?.trim();
if (deviceName) {
// Look ahead to check if this is a GPU device
for (let j = i + 1; j < Math.min(i + 10, lines.length); j++) {
if (lines[j].includes('Device Type:') && lines[j].includes('GPU')) {
const deviceLabel = currentPlatform
? `${shortenDeviceName(deviceName)} (${currentPlatform})`
: shortenDeviceName(deviceName);
// When we find a GPU device type, look for device name
if (line.includes('Device Type:') && line.includes('GPU')) {
const deviceName = this.findDeviceNameInClInfo(lines, i);
if (deviceName && currentPlatform) {
const deviceLabel = `${shortenDeviceName(deviceName)} (${currentPlatform})`;
devices.push(deviceLabel);
break;
}
}
}
}
}
@ -373,6 +372,34 @@ export class HardwareService {
return devices;
}
private findDeviceNameInClInfo(lines: string[], startIndex: number): string {
// Look for Board name first (appears closer to Device Type and is more descriptive)
for (
let j = startIndex + 1;
j < Math.min(startIndex + 50, lines.length);
j++
) {
const nextLine = lines[j].trim();
if (nextLine.includes('Board name:')) {
return nextLine.split('Board name:')[1]?.trim() || '';
}
}
// If no Board name found, look for Name: field (appears much later)
for (
let j = startIndex + 1;
j < Math.min(startIndex + 100, lines.length);
j++
) {
const nextLine = lines[j].trim();
if (nextLine.startsWith('Name:')) {
return nextLine.split('Name:')[1]?.trim() || '';
}
}
return '';
}
private async detectCLBlast(): Promise<{
supported: boolean;
devices: string[];

View file

@ -6,7 +6,6 @@ import { LogManager } from '@/main/managers/LogManager';
import { GitHubService } from '@/main/services/GitHubService';
import { HardwareService } from '@/main/services/HardwareService';
import { BinaryService } from '@/main/services/BinaryService';
import type { GPUCapabilities } from '@/types/hardware';
export class IPCHandlers {
private koboldManager: KoboldCppManager;
@ -125,13 +124,8 @@ export class IPCHandlers {
this.binaryService.detectBackendSupport(binaryPath)
);
ipcMain.handle(
'kobold:getAvailableBackends',
(_, binaryPath: string, hardwareCapabilities: GPUCapabilities) =>
this.binaryService.getAvailableBackends(
binaryPath,
hardwareCapabilities
)
ipcMain.handle('kobold:getAvailableBackends', () =>
this.binaryService.getAvailableBackends()
);
ipcMain.handle('kobold:getPlatform', () => ({

View file

@ -6,7 +6,6 @@ import type {
LogsAPI,
UpdateInfo,
} from '@/types/electron';
import type { GPUCapabilities } from '@/types/hardware';
const koboldAPI: KoboldAPI = {
getInstalledVersion: () => ipcRenderer.invoke('kobold:getInstalledVersion'),
@ -32,15 +31,7 @@ const koboldAPI: KoboldAPI = {
ipcRenderer.invoke('kobold:detectAllCapabilities'),
detectBackendSupport: (binaryPath: string) =>
ipcRenderer.invoke('kobold:detectBackendSupport', binaryPath),
getAvailableBackends: (
binaryPath: string,
hardwareCapabilities: GPUCapabilities
) =>
ipcRenderer.invoke(
'kobold:getAvailableBackends',
binaryPath,
hardwareCapabilities
),
getAvailableBackends: () => ipcRenderer.invoke('kobold:getAvailableBackends'),
getCurrentInstallDir: () => ipcRenderer.invoke('kobold:getCurrentInstallDir'),
selectInstallDirectory: () =>
ipcRenderer.invoke('kobold:selectInstallDirectory'),

View file

@ -81,10 +81,9 @@ export interface KoboldAPI {
failsafe: boolean;
cuda: boolean;
}>;
getAvailableBackends: (
binaryPath: string,
hardwareCapabilities: GPUCapabilities
) => Promise<Array<{ value: string; label: string; devices?: string[] }>>;
getAvailableBackends: () => Promise<
Array<{ value: string; label: string; devices?: string[] }>
>;
getCurrentInstallDir: () => Promise<string>;
selectInstallDirectory: () => Promise<string | null>;
downloadRelease: (