mirror of
https://github.com/lone-cloud/gerbil
synced 2026-06-03 09:33:10 -07:00
use autoGpuLayers by default and persist its value to config, show un update app icon in appheader, more code cleanup
This commit is contained in:
parent
c00b97a3f6
commit
aa554a1b58
16 changed files with 421 additions and 379 deletions
|
|
@ -13,7 +13,7 @@ A desktop app for running Large Language Models locally. <!-- markdownlint-disab
|
|||
- **Smart process management** - Prevents runaway background processes and system resource waste
|
||||
- **Optimized performance** - Automatically unpacks binaries for faster operation and reduced memory usage
|
||||
- **Image generation support** - Built-in presets for Flux and Chroma image generation workflows
|
||||
- **Adaptive theming** - Light, dark, and system theme modes that automatically follow your OS preferences
|
||||
- **SillyTavern integration** - Seamlessly launch SillyTavern for advanced character interactions (requires [Node.js](https://nodejs.org/))
|
||||
- **Privacy-focused** - Everything runs locally on your machine, no data sent to external servers
|
||||
|
||||
## Installation
|
||||
|
|
|
|||
|
|
@ -10,8 +10,9 @@ import {
|
|||
Image,
|
||||
Tooltip,
|
||||
} from '@mantine/core';
|
||||
import { Settings, ArrowLeft } from 'lucide-react';
|
||||
import { Settings, ArrowLeft, CircleFadingArrowUp } from 'lucide-react';
|
||||
import { soundAssets, playSound, initializeAudio } from '@/utils/sounds';
|
||||
import { useAppUpdateChecker } from '@/hooks/useAppUpdateChecker';
|
||||
import iconUrl from '/icon.png';
|
||||
import { FRONTENDS } from '@/constants';
|
||||
import type { InterfaceTab, FrontendPreference, Screen } from '@/types';
|
||||
|
|
@ -38,6 +39,7 @@ export const AppHeader = ({
|
|||
const [logoClickCount, setLogoClickCount] = useState(0);
|
||||
const [isElephantMode, setIsElephantMode] = useState(false);
|
||||
const [isMouseSqueaking, setIsMouseSqueaking] = useState(false);
|
||||
const { hasUpdate, openReleasePage } = useAppUpdateChecker();
|
||||
|
||||
const handleLogoClick = async () => {
|
||||
await initializeAudio();
|
||||
|
|
@ -148,8 +150,25 @@ export const AppHeader = ({
|
|||
minWidth: '6.25rem',
|
||||
display: 'flex',
|
||||
justifyContent: 'flex-end',
|
||||
gap: '0.5rem',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
{hasUpdate && (
|
||||
<Tooltip label="New release available" position="bottom">
|
||||
<ActionIcon
|
||||
variant="light"
|
||||
color="orange"
|
||||
size="xl"
|
||||
onClick={openReleasePage}
|
||||
aria-label="New release available"
|
||||
>
|
||||
<CircleFadingArrowUp
|
||||
style={{ width: rem(20), height: rem(20) }}
|
||||
/>
|
||||
</ActionIcon>
|
||||
</Tooltip>
|
||||
)}
|
||||
<Tooltip label="Settings" position="bottom">
|
||||
<ActionIcon
|
||||
variant="subtle"
|
||||
|
|
|
|||
|
|
@ -163,6 +163,7 @@ export const LaunchScreen = ({
|
|||
};
|
||||
|
||||
const buildConfigData = () => ({
|
||||
autoGpuLayers: autoGpuLayers,
|
||||
gpulayers: gpuLayers,
|
||||
contextsize: contextSize,
|
||||
model: modelPath,
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ export const VersionsTab = () => {
|
|||
downloadProgress,
|
||||
loadRemoteVersions,
|
||||
handleDownload: sharedHandleDownload,
|
||||
getLatestReleaseWithDownloadStatus,
|
||||
} = useKoboldVersions();
|
||||
|
||||
const [installedVersions, setInstalledVersions] = useState<
|
||||
|
|
@ -104,8 +105,7 @@ export const VersionsTab = () => {
|
|||
|
||||
const loadLatestRelease = useCallback(async () => {
|
||||
try {
|
||||
const release =
|
||||
await window.electronAPI.kobold.getLatestReleaseWithStatus();
|
||||
const release = await getLatestReleaseWithDownloadStatus();
|
||||
setLatestRelease(release);
|
||||
} catch (error) {
|
||||
window.electronAPI.logs.logError(
|
||||
|
|
@ -113,7 +113,7 @@ export const VersionsTab = () => {
|
|||
error as Error
|
||||
);
|
||||
}
|
||||
}, []);
|
||||
}, [getLatestReleaseWithDownloadStatus]);
|
||||
|
||||
useEffect(() => {
|
||||
loadInstalledVersions();
|
||||
|
|
|
|||
80
src/hooks/useAppUpdateChecker.ts
Normal file
80
src/hooks/useAppUpdateChecker.ts
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
import { useState, useCallback, useEffect } from 'react';
|
||||
import { compareVersions } from '@/utils/downloadUtils';
|
||||
import { GITHUB_API } from '@/constants';
|
||||
|
||||
interface AppUpdateInfo {
|
||||
currentVersion: string;
|
||||
latestVersion: string;
|
||||
releaseUrl: string;
|
||||
hasUpdate: boolean;
|
||||
}
|
||||
|
||||
export const useAppUpdateChecker = () => {
|
||||
const [updateInfo, setUpdateInfo] = useState<AppUpdateInfo | null>(null);
|
||||
const [isChecking, setIsChecking] = useState(false);
|
||||
const [lastChecked, setLastChecked] = useState<Date | null>(null);
|
||||
|
||||
const checkForAppUpdates = useCallback(async () => {
|
||||
setIsChecking(true);
|
||||
|
||||
try {
|
||||
const currentVersion = await window.electronAPI.app.getVersion();
|
||||
|
||||
const response = await fetch(
|
||||
`${GITHUB_API.BASE_URL}/repos/${GITHUB_API.FRIENDLY_KOBOLD_REPO}/releases/latest`
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch latest release');
|
||||
}
|
||||
|
||||
const release = await response.json();
|
||||
const latestVersion = release.tag_name?.replace(/^v/, '') || '';
|
||||
|
||||
if (!latestVersion) {
|
||||
throw new Error('Invalid release data');
|
||||
}
|
||||
|
||||
const hasUpdate = compareVersions(latestVersion, currentVersion) > 0;
|
||||
|
||||
const updateInfo: AppUpdateInfo = {
|
||||
currentVersion,
|
||||
latestVersion,
|
||||
releaseUrl: release.html_url,
|
||||
hasUpdate,
|
||||
};
|
||||
|
||||
setUpdateInfo(updateInfo);
|
||||
setLastChecked(new Date());
|
||||
|
||||
return updateInfo;
|
||||
} catch (error) {
|
||||
window.electronAPI.logs.logError(
|
||||
'Failed to check for app updates:',
|
||||
error as Error
|
||||
);
|
||||
return null;
|
||||
} finally {
|
||||
setIsChecking(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const openReleasePage = useCallback(() => {
|
||||
if (updateInfo?.releaseUrl) {
|
||||
window.electronAPI.app.openExternal(updateInfo.releaseUrl);
|
||||
}
|
||||
}, [updateInfo]);
|
||||
|
||||
useEffect(() => {
|
||||
checkForAppUpdates();
|
||||
}, [checkForAppUpdates]);
|
||||
|
||||
return {
|
||||
updateInfo,
|
||||
isChecking,
|
||||
lastChecked,
|
||||
checkForAppUpdates,
|
||||
openReleasePage,
|
||||
hasUpdate: updateInfo?.hasUpdate || false,
|
||||
};
|
||||
};
|
||||
|
|
@ -1,5 +1,13 @@
|
|||
import { useState, useEffect, useCallback } from 'react';
|
||||
import type { DownloadItem } from '@/types/electron';
|
||||
import { GITHUB_API, ROCM } from '@/constants';
|
||||
import { filterAssetsByPlatform } from '@/utils/platform';
|
||||
import type {
|
||||
DownloadItem,
|
||||
GitHubRelease,
|
||||
ReleaseWithStatus,
|
||||
GitHubAsset,
|
||||
InstalledVersion,
|
||||
} from '@/types/electron';
|
||||
|
||||
interface PlatformInfo {
|
||||
platform: string;
|
||||
|
|
@ -7,6 +15,164 @@ interface PlatformInfo {
|
|||
hasROCm: boolean;
|
||||
}
|
||||
|
||||
interface CachedReleaseData {
|
||||
releases: DownloadItem[];
|
||||
timestamp: number;
|
||||
}
|
||||
|
||||
const CACHE_KEY = 'kobold-releases-cache';
|
||||
const CACHE_DURATION = 60000;
|
||||
|
||||
const loadFromCache = (): CachedReleaseData | null => {
|
||||
try {
|
||||
const cached = localStorage.getItem(CACHE_KEY);
|
||||
if (!cached) return null;
|
||||
|
||||
const data: CachedReleaseData = JSON.parse(cached);
|
||||
const isExpired = Date.now() - data.timestamp > CACHE_DURATION;
|
||||
|
||||
return isExpired ? null : data;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const saveToCache = (releases: DownloadItem[]) => {
|
||||
try {
|
||||
const data: CachedReleaseData = {
|
||||
releases,
|
||||
timestamp: Date.now(),
|
||||
};
|
||||
localStorage.setItem(CACHE_KEY, JSON.stringify(data));
|
||||
} catch (error) {
|
||||
window.electronAPI.logs.logError(
|
||||
'Failed to save releases to cache',
|
||||
error as Error
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const transformReleaseToDownloadItems = (
|
||||
release: GitHubRelease,
|
||||
platform: string
|
||||
): DownloadItem[] => {
|
||||
const version = release.tag_name?.replace(/^v/, '') || 'unknown';
|
||||
const platformAssets = filterAssetsByPlatform(release.assets, platform);
|
||||
|
||||
return platformAssets.map((asset) => ({
|
||||
name: asset.name,
|
||||
url: asset.browser_download_url,
|
||||
size: asset.size,
|
||||
version,
|
||||
type: 'asset' as const,
|
||||
}));
|
||||
};
|
||||
|
||||
const fetchLatestReleaseFromAPI = async (
|
||||
platform: string
|
||||
): Promise<DownloadItem[]> => {
|
||||
const response = await fetch(GITHUB_API.LATEST_RELEASE_URL);
|
||||
|
||||
if (!response.ok) {
|
||||
if (response.status === 403) {
|
||||
throw new Error('GitHub API rate limit reached');
|
||||
}
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
const release: GitHubRelease = await response.json();
|
||||
return transformReleaseToDownloadItems(release, platform);
|
||||
};
|
||||
|
||||
const getROCmDownload = async (
|
||||
platform: string
|
||||
): Promise<DownloadItem | null> => {
|
||||
if (platform !== 'linux') {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(GITHUB_API.LATEST_RELEASE_URL);
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
const latestRelease = await response.json();
|
||||
const version = latestRelease?.tag_name?.replace(/^v/, '') || 'unknown';
|
||||
|
||||
return {
|
||||
name: ROCM.BINARY_NAME,
|
||||
url: ROCM.DOWNLOAD_URL,
|
||||
size: ROCM.SIZE_BYTES_APPROX,
|
||||
version,
|
||||
type: 'rocm',
|
||||
};
|
||||
} catch (error) {
|
||||
window.electronAPI.logs.logError(
|
||||
'Failed to fetch ROCm version info:',
|
||||
error as Error
|
||||
);
|
||||
return {
|
||||
name: ROCM.BINARY_NAME,
|
||||
url: ROCM.DOWNLOAD_URL,
|
||||
size: ROCM.SIZE_BYTES_APPROX,
|
||||
version: 'unknown',
|
||||
type: 'rocm',
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const getLatestReleaseWithDownloadStatus =
|
||||
async (): Promise<ReleaseWithStatus | null> => {
|
||||
try {
|
||||
const response = await fetch(GITHUB_API.LATEST_RELEASE_URL);
|
||||
if (!response.ok) return null;
|
||||
|
||||
const latestRelease = await response.json();
|
||||
if (!latestRelease) return null;
|
||||
|
||||
const installedVersions =
|
||||
await window.electronAPI.kobold.getInstalledVersions();
|
||||
|
||||
const availableAssets = latestRelease.assets.map((asset: GitHubAsset) => {
|
||||
const installedVersion = installedVersions.find(
|
||||
(v: InstalledVersion) => {
|
||||
const pathParts = v.path.split(/[/\\]/);
|
||||
const launcherIndex = pathParts.findIndex(
|
||||
(part) =>
|
||||
part === 'koboldcpp-launcher' ||
|
||||
part === 'koboldcpp-launcher.exe'
|
||||
);
|
||||
|
||||
if (launcherIndex > 0) {
|
||||
const directoryName = pathParts[launcherIndex - 1];
|
||||
return directoryName === asset.name;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
);
|
||||
|
||||
return {
|
||||
asset,
|
||||
isDownloaded: !!installedVersion,
|
||||
installedVersion: installedVersion?.version,
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
release: latestRelease,
|
||||
availableAssets,
|
||||
};
|
||||
} catch (error) {
|
||||
window.electronAPI.logs.logError(
|
||||
'Failed to fetch latest release with status:',
|
||||
error as Error
|
||||
);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
interface UseKoboldVersionsReturn {
|
||||
platformInfo: PlatformInfo;
|
||||
availableDownloads: DownloadItem[];
|
||||
|
|
@ -15,6 +181,7 @@ interface UseKoboldVersionsReturn {
|
|||
downloading: string | null;
|
||||
downloadProgress: Record<string, number>;
|
||||
loadRemoteVersions: () => Promise<void>;
|
||||
refresh: () => Promise<void>;
|
||||
handleDownload: (
|
||||
type: 'asset' | 'rocm',
|
||||
item?: DownloadItem,
|
||||
|
|
@ -27,6 +194,8 @@ interface UseKoboldVersionsReturn {
|
|||
| Record<string, number>
|
||||
| ((prev: Record<string, number>) => Record<string, number>)
|
||||
) => void;
|
||||
getROCmDownload: (platform?: string) => Promise<DownloadItem | null>;
|
||||
getLatestReleaseWithDownloadStatus: () => Promise<ReleaseWithStatus | null>;
|
||||
}
|
||||
|
||||
export const useKoboldVersions = (): UseKoboldVersionsReturn => {
|
||||
|
|
@ -93,11 +262,25 @@ export const useKoboldVersions = (): UseKoboldVersionsReturn => {
|
|||
setLoadingRemote(true);
|
||||
|
||||
try {
|
||||
const cached = loadFromCache();
|
||||
if (cached) {
|
||||
const rocm = await getROCmDownload(platformInfo.platform);
|
||||
const allDownloads: DownloadItem[] = [...cached.releases];
|
||||
if (rocm) {
|
||||
allDownloads.push(rocm);
|
||||
}
|
||||
setAvailableDownloads(allDownloads);
|
||||
setLoadingRemote(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const [releases, rocm] = await Promise.all([
|
||||
window.electronAPI.kobold.getLatestRelease(),
|
||||
window.electronAPI.kobold.getROCmDownload(),
|
||||
fetchLatestReleaseFromAPI(platformInfo.platform),
|
||||
getROCmDownload(platformInfo.platform),
|
||||
]);
|
||||
|
||||
saveToCache(releases);
|
||||
|
||||
const allDownloads: DownloadItem[] = [...releases];
|
||||
if (rocm) {
|
||||
allDownloads.push(rocm);
|
||||
|
|
@ -109,6 +292,18 @@ export const useKoboldVersions = (): UseKoboldVersionsReturn => {
|
|||
'Failed to load remote versions:',
|
||||
error as Error
|
||||
);
|
||||
|
||||
const cached = loadFromCache();
|
||||
if (cached) {
|
||||
const rocm = await getROCmDownload(platformInfo.platform).catch(
|
||||
() => null
|
||||
);
|
||||
const allDownloads: DownloadItem[] = [...cached.releases];
|
||||
if (rocm) {
|
||||
allDownloads.push(rocm);
|
||||
}
|
||||
setAvailableDownloads(allDownloads);
|
||||
}
|
||||
} finally {
|
||||
setLoadingRemote(false);
|
||||
}
|
||||
|
|
@ -160,6 +355,11 @@ export const useKoboldVersions = (): UseKoboldVersionsReturn => {
|
|||
[]
|
||||
);
|
||||
|
||||
const refresh = useCallback(async () => {
|
||||
localStorage.removeItem(CACHE_KEY);
|
||||
await loadRemoteVersions();
|
||||
}, [loadRemoteVersions]);
|
||||
|
||||
useEffect(() => {
|
||||
loadPlatformInfo();
|
||||
}, [loadPlatformInfo]);
|
||||
|
|
@ -195,8 +395,12 @@ export const useKoboldVersions = (): UseKoboldVersionsReturn => {
|
|||
downloading,
|
||||
downloadProgress,
|
||||
loadRemoteVersions,
|
||||
refresh,
|
||||
handleDownload,
|
||||
setDownloading,
|
||||
setDownloadProgress,
|
||||
getROCmDownload: (platform?: string) =>
|
||||
getROCmDownload(platform || platformInfo.platform),
|
||||
getLatestReleaseWithDownloadStatus,
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { useState, useCallback, useEffect } from 'react';
|
||||
import { getDisplayNameFromPath } from '@/utils/versionUtils';
|
||||
import { compareVersions } from '@/utils/downloadUtils';
|
||||
import { useKoboldVersions } from '@/hooks/useKoboldVersions';
|
||||
import type { InstalledVersion, DownloadItem } from '@/types/electron';
|
||||
|
||||
interface UpdateInfo {
|
||||
|
|
@ -17,6 +18,8 @@ export const useUpdateChecker = () => {
|
|||
);
|
||||
const [dismissedUpdatesLoaded, setDismissedUpdatesLoaded] = useState(false);
|
||||
|
||||
const { availableDownloads: releases, getROCmDownload } = useKoboldVersions();
|
||||
|
||||
useEffect(() => {
|
||||
const loadDismissedUpdates = async () => {
|
||||
try {
|
||||
|
|
@ -54,28 +57,26 @@ export const useUpdateChecker = () => {
|
|||
}, []);
|
||||
|
||||
const checkForUpdates = useCallback(async () => {
|
||||
if (!dismissedUpdatesLoaded) {
|
||||
if (!dismissedUpdatesLoaded || releases.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
setIsChecking(true);
|
||||
|
||||
try {
|
||||
const [currentBinaryPath, installedVersions, releases, rocm] =
|
||||
const [currentBinaryPath, installedVersionsResult, rocmDownload] =
|
||||
await Promise.all([
|
||||
window.electronAPI.config.get(
|
||||
'currentKoboldBinary'
|
||||
) as Promise<string>,
|
||||
window.electronAPI.kobold.getInstalledVersions(),
|
||||
window.electronAPI.kobold.getLatestRelease(),
|
||||
window.electronAPI.kobold.getROCmDownload(),
|
||||
getROCmDownload(),
|
||||
]);
|
||||
|
||||
if (!currentBinaryPath || installedVersions.length === 0) {
|
||||
if (!currentBinaryPath || installedVersionsResult.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentVersion = installedVersions.find(
|
||||
const currentVersion = installedVersionsResult.find(
|
||||
(v: InstalledVersion) => v.path === currentBinaryPath
|
||||
);
|
||||
if (!currentVersion) {
|
||||
|
|
@ -83,8 +84,8 @@ export const useUpdateChecker = () => {
|
|||
}
|
||||
|
||||
const availableDownloads: DownloadItem[] = [...releases];
|
||||
if (rocm) {
|
||||
availableDownloads.push(rocm);
|
||||
if (rocmDownload) {
|
||||
availableDownloads.push(rocmDownload);
|
||||
}
|
||||
|
||||
const currentDisplayName = getDisplayNameFromPath(currentVersion);
|
||||
|
|
@ -122,7 +123,7 @@ export const useUpdateChecker = () => {
|
|||
} finally {
|
||||
setIsChecking(false);
|
||||
}
|
||||
}, [dismissedUpdates, dismissedUpdatesLoaded]);
|
||||
}, [dismissedUpdates, dismissedUpdatesLoaded, releases, getROCmDownload]);
|
||||
|
||||
const dismissUpdate = useCallback(async () => {
|
||||
if (updateInfo) {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import { ConfigManager } from '@/main/managers/ConfigManager';
|
|||
import { LogManager } from '@/main/managers/LogManager';
|
||||
import { KoboldCppManager } from '@/main/managers/KoboldCppManager';
|
||||
import { SillyTavernManager } from '@/main/managers/SillyTavernManager';
|
||||
import { GitHubService } from '@/main/services/GitHubService';
|
||||
import { HardwareService } from '@/main/services/HardwareService';
|
||||
import { BinaryService } from '@/main/services/BinaryService';
|
||||
import { IPCHandlers } from '@/main/ipc';
|
||||
|
|
@ -16,11 +15,10 @@ import { homedir } from 'os';
|
|||
|
||||
export class FriendlyKoboldApp {
|
||||
private windowManager: WindowManager;
|
||||
private koboldManager: KoboldCppManager;
|
||||
private configManager: ConfigManager;
|
||||
private logManager: LogManager;
|
||||
private koboldManager: KoboldCppManager;
|
||||
private sillyTavernManager: SillyTavernManager;
|
||||
private githubService: GitHubService;
|
||||
private hardwareService: HardwareService;
|
||||
private binaryService: BinaryService;
|
||||
private ipcHandlers: IPCHandlers;
|
||||
|
|
@ -35,12 +33,10 @@ export class FriendlyKoboldApp {
|
|||
);
|
||||
this.ensureInstallDirectory();
|
||||
this.windowManager = new WindowManager();
|
||||
this.githubService = new GitHubService(this.logManager);
|
||||
this.hardwareService = new HardwareService(this.logManager);
|
||||
|
||||
this.koboldManager = new KoboldCppManager(
|
||||
this.configManager,
|
||||
this.githubService,
|
||||
this.windowManager,
|
||||
this.logManager
|
||||
);
|
||||
|
|
@ -59,7 +55,6 @@ export class FriendlyKoboldApp {
|
|||
this.ipcHandlers = new IPCHandlers(
|
||||
this.koboldManager,
|
||||
this.configManager,
|
||||
this.githubService,
|
||||
this.hardwareService,
|
||||
this.binaryService,
|
||||
this.logManager,
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
import { ipcMain, shell, app } from 'electron';
|
||||
import { KoboldCppManager } from '@/main/managers/KoboldCppManager';
|
||||
import { ConfigManager } from '@/main/managers/ConfigManager';
|
||||
import { LogManager } from '@/main/managers/LogManager';
|
||||
import { SillyTavernManager } from '@/main/managers/SillyTavernManager';
|
||||
import { GitHubService } from '@/main/services/GitHubService';
|
||||
import type { KoboldCppManager } from '@/main/managers/KoboldCppManager';
|
||||
import type { ConfigManager } from '@/main/managers/ConfigManager';
|
||||
import type { LogManager } from '@/main/managers/LogManager';
|
||||
import type { SillyTavernManager } from '@/main/managers/SillyTavernManager';
|
||||
import { HardwareService } from '@/main/services/HardwareService';
|
||||
import { BinaryService } from '@/main/services/BinaryService';
|
||||
import type { FrontendPreference } from '@/types';
|
||||
|
|
@ -13,14 +12,12 @@ export class IPCHandlers {
|
|||
private configManager: ConfigManager;
|
||||
private logManager: LogManager;
|
||||
private sillyTavernManager: SillyTavernManager;
|
||||
private githubService: GitHubService;
|
||||
private hardwareService: HardwareService;
|
||||
private binaryService: BinaryService;
|
||||
|
||||
constructor(
|
||||
koboldManager: KoboldCppManager,
|
||||
configManager: ConfigManager,
|
||||
githubService: GitHubService,
|
||||
hardwareService: HardwareService,
|
||||
binaryService: BinaryService,
|
||||
logManager: LogManager,
|
||||
|
|
@ -30,7 +27,6 @@ export class IPCHandlers {
|
|||
this.configManager = configManager;
|
||||
this.logManager = logManager;
|
||||
this.sillyTavernManager = sillyTavernManager;
|
||||
this.githubService = githubService;
|
||||
this.hardwareService = hardwareService;
|
||||
this.binaryService = binaryService;
|
||||
}
|
||||
|
|
@ -74,15 +70,6 @@ export class IPCHandlers {
|
|||
}
|
||||
|
||||
setupHandlers() {
|
||||
ipcMain.handle('kobold:getLatestRelease', () =>
|
||||
this.githubService.getLatestRelease()
|
||||
);
|
||||
|
||||
ipcMain.handle('kobold:checkForUpdates', async () => {
|
||||
const latest = await this.githubService.getRawLatestRelease();
|
||||
return latest;
|
||||
});
|
||||
|
||||
ipcMain.handle('kobold:downloadRelease', async (_event, asset) => {
|
||||
try {
|
||||
const mainWindow = this.koboldManager
|
||||
|
|
@ -126,14 +113,6 @@ export class IPCHandlers {
|
|||
this.configManager.setSelectedConfig(configName)
|
||||
);
|
||||
|
||||
ipcMain.handle('kobold:getCurrentVersion', () =>
|
||||
this.koboldManager.getCurrentVersion()
|
||||
);
|
||||
|
||||
ipcMain.handle('kobold:getCurrentBinaryInfo', () =>
|
||||
this.koboldManager.getCurrentBinaryInfo()
|
||||
);
|
||||
|
||||
ipcMain.handle('kobold:setCurrentVersion', (_event, version) =>
|
||||
this.koboldManager.setCurrentVersion(version)
|
||||
);
|
||||
|
|
@ -162,10 +141,6 @@ export class IPCHandlers {
|
|||
this.hardwareService.detectROCm()
|
||||
);
|
||||
|
||||
ipcMain.handle('kobold:detectAllCapabilities', () =>
|
||||
this.hardwareService.detectAllWithCapabilities()
|
||||
);
|
||||
|
||||
ipcMain.handle('kobold:detectBackendSupport', () =>
|
||||
this.binaryService.detectBackendSupport()
|
||||
);
|
||||
|
|
@ -181,10 +156,6 @@ export class IPCHandlers {
|
|||
arch: process.arch,
|
||||
}));
|
||||
|
||||
ipcMain.handle('kobold:getROCmDownload', () =>
|
||||
this.koboldManager.getROCmDownload()
|
||||
);
|
||||
|
||||
ipcMain.handle('kobold:downloadROCm', async () => {
|
||||
try {
|
||||
const mainWindow = this.koboldManager
|
||||
|
|
@ -201,18 +172,6 @@ export class IPCHandlers {
|
|||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('kobold:getInstalledVersion', () =>
|
||||
this.koboldManager.getInstalledVersion()
|
||||
);
|
||||
|
||||
ipcMain.handle('kobold:getVersionFromBinary', (_event, binaryPath) =>
|
||||
this.koboldManager.getVersionFromBinary(binaryPath)
|
||||
);
|
||||
|
||||
ipcMain.handle('kobold:getLatestReleaseWithStatus', () =>
|
||||
this.koboldManager.getLatestReleaseWithDownloadStatus()
|
||||
);
|
||||
|
||||
ipcMain.handle('kobold:launchKoboldCpp', (_event, args) =>
|
||||
this.launchKoboldCppWithCustomFrontends(args)
|
||||
);
|
||||
|
|
|
|||
|
|
@ -16,19 +16,16 @@ import { dialog } from 'electron';
|
|||
import { execa } from 'execa';
|
||||
import { got } from 'got';
|
||||
import { pipeline } from 'stream/promises';
|
||||
import { GitHubService } from '@/main/services/GitHubService';
|
||||
import { ConfigManager } from '@/main/managers/ConfigManager';
|
||||
import { LogManager } from '@/main/managers/LogManager';
|
||||
import { WindowManager } from '@/main/managers/WindowManager';
|
||||
import { ROCM, PRODUCT_NAME } from '@/constants';
|
||||
import { ROCM, PRODUCT_NAME, GITHUB_API } from '@/constants';
|
||||
import { stripAssetExtensions } from '@/utils/versionUtils';
|
||||
import { compareVersions } from '@/utils/downloadUtils';
|
||||
import type {
|
||||
DownloadItem,
|
||||
GitHubAsset,
|
||||
UpdateInfo,
|
||||
ReleaseWithStatus,
|
||||
InstalledVersion,
|
||||
KoboldConfig,
|
||||
} from '@/types/electron';
|
||||
|
||||
export class KoboldCppManager {
|
||||
|
|
@ -36,18 +33,15 @@ export class KoboldCppManager {
|
|||
private koboldProcess: ChildProcess | null = null;
|
||||
private configManager: ConfigManager;
|
||||
private logManager: LogManager;
|
||||
private githubService: GitHubService;
|
||||
private windowManager: WindowManager;
|
||||
|
||||
constructor(
|
||||
configManager: ConfigManager,
|
||||
githubService: GitHubService,
|
||||
windowManager: WindowManager,
|
||||
logManager: LogManager
|
||||
) {
|
||||
this.configManager = configManager;
|
||||
this.logManager = logManager;
|
||||
this.githubService = githubService;
|
||||
this.windowManager = windowManager;
|
||||
this.installDir = this.configManager.getInstallDir() || '';
|
||||
}
|
||||
|
|
@ -265,12 +259,7 @@ export class KoboldCppManager {
|
|||
return configFiles.sort((a, b) => a.name.localeCompare(b.name));
|
||||
}
|
||||
|
||||
async parseConfigFile(filePath: string): Promise<{
|
||||
gpulayers?: number;
|
||||
contextsize?: number;
|
||||
model?: string;
|
||||
[key: string]: unknown;
|
||||
} | null> {
|
||||
async parseConfigFile(filePath: string): Promise<KoboldConfig | null> {
|
||||
try {
|
||||
if (!existsSync(filePath)) {
|
||||
return null;
|
||||
|
|
@ -288,33 +277,7 @@ export class KoboldCppManager {
|
|||
|
||||
async saveConfigFile(
|
||||
configName: string,
|
||||
configData: {
|
||||
gpulayers?: number;
|
||||
contextsize?: number;
|
||||
model?: string;
|
||||
port?: number;
|
||||
host?: string;
|
||||
multiuser?: number;
|
||||
multiplayer?: boolean;
|
||||
remotetunnel?: boolean;
|
||||
nocertify?: boolean;
|
||||
websearch?: boolean;
|
||||
noshift?: boolean;
|
||||
flashattention?: boolean;
|
||||
noavx2?: boolean;
|
||||
failsafe?: boolean;
|
||||
usemmap?: boolean;
|
||||
usecuda?: boolean;
|
||||
usevulkan?: boolean;
|
||||
useclblast?: [number, number] | boolean;
|
||||
sdmodel?: string;
|
||||
sdt5xxl?: string;
|
||||
sdclipl?: string;
|
||||
sdclipg?: string;
|
||||
sdphotomaker?: string;
|
||||
sdvae?: string;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
configData: KoboldConfig
|
||||
): Promise<boolean> {
|
||||
try {
|
||||
if (!this.installDir) {
|
||||
|
|
@ -549,16 +512,35 @@ export class KoboldCppManager {
|
|||
const platform = process.platform;
|
||||
|
||||
if (platform === 'linux') {
|
||||
const latestRelease = await this.githubService.getRawLatestRelease();
|
||||
const version = latestRelease?.tag_name?.replace(/^v/, '') || 'unknown';
|
||||
try {
|
||||
const response = await fetch(GITHUB_API.LATEST_RELEASE_URL);
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
return {
|
||||
name: ROCM.BINARY_NAME,
|
||||
url: ROCM.DOWNLOAD_URL,
|
||||
size: ROCM.SIZE_BYTES_APPROX,
|
||||
version,
|
||||
type: 'rocm',
|
||||
};
|
||||
const latestRelease = await response.json();
|
||||
const version = latestRelease?.tag_name?.replace(/^v/, '') || 'unknown';
|
||||
|
||||
return {
|
||||
name: ROCM.BINARY_NAME,
|
||||
url: ROCM.DOWNLOAD_URL,
|
||||
size: ROCM.SIZE_BYTES_APPROX,
|
||||
version,
|
||||
type: 'rocm',
|
||||
};
|
||||
} catch (error) {
|
||||
this.logManager.logError(
|
||||
'Failed to fetch ROCm version info:',
|
||||
error as Error
|
||||
);
|
||||
return {
|
||||
name: ROCM.BINARY_NAME,
|
||||
url: ROCM.DOWNLOAD_URL,
|
||||
size: ROCM.SIZE_BYTES_APPROX,
|
||||
version: 'unknown',
|
||||
type: 'rocm',
|
||||
};
|
||||
}
|
||||
} else if (platform === 'win32') {
|
||||
return null;
|
||||
// The launcher doesn't exist in unpacked state yet.
|
||||
|
|
@ -706,73 +688,6 @@ export class KoboldCppManager {
|
|||
return currentVersion?.version;
|
||||
}
|
||||
|
||||
async checkForUpdates(): Promise<UpdateInfo | null> {
|
||||
try {
|
||||
const currentVersion = await this.getCurrentVersion();
|
||||
if (!currentVersion) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const latestRelease = await this.githubService.getRawLatestRelease();
|
||||
if (!latestRelease) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const latestVersion = latestRelease.tag_name.replace(/^v/, '');
|
||||
const current = currentVersion.version.replace(/^v/, '');
|
||||
|
||||
const hasUpdate = compareVersions(current, latestVersion) < 0;
|
||||
|
||||
return {
|
||||
currentVersion: current,
|
||||
latestVersion,
|
||||
releaseInfo: latestRelease,
|
||||
hasUpdate,
|
||||
};
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async getLatestReleaseWithDownloadStatus(): Promise<ReleaseWithStatus | null> {
|
||||
try {
|
||||
const latestRelease = await this.githubService.getRawLatestRelease();
|
||||
if (!latestRelease) return null;
|
||||
|
||||
const installedVersions = await this.getInstalledVersions();
|
||||
|
||||
const availableAssets = latestRelease.assets.map((asset: GitHubAsset) => {
|
||||
const installedVersion = installedVersions.find((v) => {
|
||||
const pathParts = v.path.split(/[/\\]/);
|
||||
const launcherIndex = pathParts.findIndex(
|
||||
(part) =>
|
||||
part === 'koboldcpp-launcher' || part === 'koboldcpp-launcher.exe'
|
||||
);
|
||||
|
||||
if (launcherIndex > 0) {
|
||||
const directoryName = pathParts[launcherIndex - 1];
|
||||
return directoryName === asset.name;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
return {
|
||||
asset,
|
||||
isDownloaded: !!installedVersion,
|
||||
installedVersion: installedVersion?.version,
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
release: latestRelease,
|
||||
availableAssets,
|
||||
};
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async launchKoboldCpp(
|
||||
args: string[] = []
|
||||
): Promise<{ success: boolean; pid?: number; error?: string }> {
|
||||
|
|
|
|||
|
|
@ -113,6 +113,13 @@ export class SillyTavernManager {
|
|||
}
|
||||
}
|
||||
|
||||
private createNpxProcess(args: string[]): ChildProcess {
|
||||
return spawn('npx', args, {
|
||||
stdio: ['pipe', 'pipe', 'pipe'],
|
||||
detached: false,
|
||||
});
|
||||
}
|
||||
|
||||
private async ensureSillyTavernSettings(): Promise<void> {
|
||||
const settingsPath = this.getSillyTavernSettingsPath();
|
||||
|
||||
|
|
@ -132,10 +139,7 @@ export class SillyTavernManager {
|
|||
);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const initProcess = spawn('npx', spawnArgs, {
|
||||
stdio: ['pipe', 'pipe', 'pipe'],
|
||||
detached: false,
|
||||
});
|
||||
const initProcess = this.createNpxProcess(spawnArgs);
|
||||
|
||||
let hasResolved = false;
|
||||
|
||||
|
|
@ -364,10 +368,7 @@ export class SillyTavernManager {
|
|||
config.port.toString(),
|
||||
];
|
||||
|
||||
this.sillyTavernProcess = spawn('npx', sillyTavernArgs, {
|
||||
stdio: ['pipe', 'pipe', 'pipe'],
|
||||
detached: false,
|
||||
});
|
||||
this.sillyTavernProcess = this.createNpxProcess(sillyTavernArgs);
|
||||
|
||||
if (this.sillyTavernProcess.stdout) {
|
||||
this.sillyTavernProcess.stdout.on('data', (data: Buffer) => {
|
||||
|
|
|
|||
|
|
@ -1,99 +0,0 @@
|
|||
import type { GitHubRelease, DownloadItem } from '@/types/electron';
|
||||
import { LogManager } from '@/main/managers/LogManager';
|
||||
import { GITHUB_API } from '@/constants';
|
||||
import { filterAssetsByPlatform } from '@/utils/platform';
|
||||
|
||||
export class GitHubService {
|
||||
private lastApiCall = 0;
|
||||
private apiCooldown = 60000;
|
||||
private cachedRelease: GitHubRelease | null = null;
|
||||
private logManager: LogManager;
|
||||
|
||||
constructor(logManager: LogManager) {
|
||||
this.logManager = logManager;
|
||||
}
|
||||
|
||||
async getLatestRelease(): Promise<DownloadItem[]> {
|
||||
const now = Date.now();
|
||||
if (now - this.lastApiCall < this.apiCooldown && this.cachedRelease) {
|
||||
return this.transformReleaseToDownloadItems(this.cachedRelease);
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(GITHUB_API.LATEST_RELEASE_URL);
|
||||
|
||||
if (!response.ok) {
|
||||
if (response.status === 403) {
|
||||
this.logManager.logError(
|
||||
'GitHub API rate limit reached, using cached data if available'
|
||||
);
|
||||
return this.cachedRelease
|
||||
? this.transformReleaseToDownloadItems(this.cachedRelease)
|
||||
: [];
|
||||
}
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
this.lastApiCall = now;
|
||||
this.cachedRelease = (await response.json()) as GitHubRelease;
|
||||
return this.transformReleaseToDownloadItems(this.cachedRelease);
|
||||
} catch (error) {
|
||||
this.logManager.logError(
|
||||
'Error fetching latest release:',
|
||||
error as Error
|
||||
);
|
||||
return this.cachedRelease
|
||||
? this.transformReleaseToDownloadItems(this.cachedRelease)
|
||||
: [];
|
||||
}
|
||||
}
|
||||
|
||||
private transformReleaseToDownloadItems(
|
||||
release: GitHubRelease
|
||||
): DownloadItem[] {
|
||||
const version = release.tag_name?.replace(/^v/, '') || 'unknown';
|
||||
const platformAssets = filterAssetsByPlatform(
|
||||
release.assets,
|
||||
process.platform
|
||||
);
|
||||
|
||||
return platformAssets.map((asset) => ({
|
||||
name: asset.name,
|
||||
url: asset.browser_download_url,
|
||||
size: asset.size,
|
||||
version,
|
||||
type: 'asset' as const,
|
||||
}));
|
||||
}
|
||||
|
||||
async getRawLatestRelease(): Promise<GitHubRelease | null> {
|
||||
const now = Date.now();
|
||||
if (now - this.lastApiCall < this.apiCooldown && this.cachedRelease) {
|
||||
return this.cachedRelease;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(GITHUB_API.LATEST_RELEASE_URL);
|
||||
|
||||
if (!response.ok) {
|
||||
if (response.status === 403) {
|
||||
this.logManager.logError(
|
||||
'GitHub API rate limit reached, using cached data if available'
|
||||
);
|
||||
return this.cachedRelease;
|
||||
}
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
this.lastApiCall = now;
|
||||
this.cachedRelease = (await response.json()) as GitHubRelease;
|
||||
return this.cachedRelease;
|
||||
} catch (error) {
|
||||
this.logManager.logError(
|
||||
'Error fetching latest release:',
|
||||
error as Error
|
||||
);
|
||||
return this.cachedRelease;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -141,16 +141,6 @@ export class HardwareService {
|
|||
return { cpu, gpu };
|
||||
}
|
||||
|
||||
async detectAllWithCapabilities(): Promise<HardwareInfo> {
|
||||
const [cpu, gpu, gpuCapabilities] = await Promise.all([
|
||||
this.detectCPU(),
|
||||
this.detectGPU(),
|
||||
this.detectGPUCapabilities(),
|
||||
]);
|
||||
|
||||
return { cpu, gpu, gpuCapabilities };
|
||||
}
|
||||
|
||||
private async detectCUDA(): Promise<{
|
||||
supported: boolean;
|
||||
devices: string[];
|
||||
|
|
|
|||
|
|
@ -5,18 +5,14 @@ import type {
|
|||
ConfigAPI,
|
||||
LogsAPI,
|
||||
SillyTavernAPI,
|
||||
KoboldConfig,
|
||||
} from '@/types/electron';
|
||||
|
||||
const koboldAPI: KoboldAPI = {
|
||||
getInstalledVersions: () => ipcRenderer.invoke('kobold:getInstalledVersions'),
|
||||
getCurrentBinaryInfo: () => ipcRenderer.invoke('kobold:getCurrentBinaryInfo'),
|
||||
setCurrentVersion: (version: string) =>
|
||||
ipcRenderer.invoke('kobold:setCurrentVersion', version),
|
||||
getLatestReleaseWithStatus: () =>
|
||||
ipcRenderer.invoke('kobold:getLatestReleaseWithStatus'),
|
||||
getROCmDownload: () => ipcRenderer.invoke('kobold:getROCmDownload'),
|
||||
downloadROCm: () => ipcRenderer.invoke('kobold:downloadROCm'),
|
||||
getLatestRelease: () => ipcRenderer.invoke('kobold:getLatestRelease'),
|
||||
getPlatform: () => ipcRenderer.invoke('kobold:getPlatform'),
|
||||
detectGPU: () => ipcRenderer.invoke('kobold:detectGPU'),
|
||||
detectCPU: () => ipcRenderer.invoke('kobold:detectCPU'),
|
||||
|
|
@ -35,36 +31,8 @@ const koboldAPI: KoboldAPI = {
|
|||
launchKoboldCpp: (args?: string[]) =>
|
||||
ipcRenderer.invoke('kobold:launchKoboldCpp', args),
|
||||
getConfigFiles: () => ipcRenderer.invoke('kobold:getConfigFiles'),
|
||||
saveConfigFile: (
|
||||
configName: string,
|
||||
configData: {
|
||||
gpulayers?: number;
|
||||
contextsize?: number;
|
||||
model_param?: string;
|
||||
port?: number;
|
||||
host?: string;
|
||||
multiuser?: number;
|
||||
multiplayer?: boolean;
|
||||
remotetunnel?: boolean;
|
||||
nocertify?: boolean;
|
||||
websearch?: boolean;
|
||||
noshift?: boolean;
|
||||
flashattention?: boolean;
|
||||
noavx2?: boolean;
|
||||
failsafe?: boolean;
|
||||
usemmap?: boolean;
|
||||
usecuda?: boolean;
|
||||
usevulkan?: boolean;
|
||||
useclblast?: boolean;
|
||||
sdmodel?: string;
|
||||
sdt5xxl?: string;
|
||||
sdclipl?: string;
|
||||
sdclipg?: string;
|
||||
sdphotomaker?: string;
|
||||
sdvae?: string;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
) => ipcRenderer.invoke('kobold:saveConfigFile', configName, configData),
|
||||
saveConfigFile: (configName: string, configData: KoboldConfig) =>
|
||||
ipcRenderer.invoke('kobold:saveConfigFile', configName, configData),
|
||||
getSelectedConfig: () => ipcRenderer.invoke('kobold:getSelectedConfig'),
|
||||
setSelectedConfig: (configName: string) =>
|
||||
ipcRenderer.invoke('kobold:setSelectedConfig', configName),
|
||||
|
|
@ -109,6 +77,7 @@ const koboldAPI: KoboldAPI = {
|
|||
|
||||
const appAPI: AppAPI = {
|
||||
openExternal: (url) => ipcRenderer.invoke('app:openExternal', url),
|
||||
getVersion: () => ipcRenderer.invoke('app:getVersion'),
|
||||
};
|
||||
|
||||
const configAPI: ConfigAPI = {
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ interface LaunchConfigState {
|
|||
|
||||
export const useLaunchConfigStore = create<LaunchConfigState>((set, get) => ({
|
||||
gpuLayers: 0,
|
||||
autoGpuLayers: false,
|
||||
autoGpuLayers: true,
|
||||
contextSize: DEFAULT_CONTEXT_SIZE,
|
||||
modelPath: '',
|
||||
additionalArguments: '',
|
||||
|
|
@ -163,6 +163,12 @@ export const useLaunchConfigStore = create<LaunchConfigState>((set, get) => ({
|
|||
if (configData) {
|
||||
const updates: Partial<LaunchConfigState> = {};
|
||||
|
||||
if (typeof configData.autoGpuLayers === 'boolean') {
|
||||
updates.autoGpuLayers = configData.autoGpuLayers;
|
||||
} else {
|
||||
updates.autoGpuLayers = true;
|
||||
}
|
||||
|
||||
if (typeof configData.gpulayers === 'number') {
|
||||
updates.gpuLayers = configData.gpulayers;
|
||||
} else {
|
||||
|
|
|
|||
81
src/types/electron.d.ts
vendored
81
src/types/electron.d.ts
vendored
|
|
@ -57,14 +57,47 @@ export interface DownloadItem {
|
|||
type: 'asset' | 'rocm';
|
||||
}
|
||||
|
||||
export interface KoboldConfig {
|
||||
gpulayers?: number;
|
||||
contextsize?: number;
|
||||
model_param?: string;
|
||||
port?: number;
|
||||
host?: string;
|
||||
multiuser?: number;
|
||||
multiplayer?: boolean;
|
||||
remotetunnel?: boolean;
|
||||
nocertify?: boolean;
|
||||
websearch?: boolean;
|
||||
noshift?: boolean;
|
||||
flashattention?: boolean;
|
||||
noavx2?: boolean;
|
||||
failsafe?: boolean;
|
||||
lowvram?: boolean;
|
||||
quantmatmul?: boolean;
|
||||
usemmap?: boolean;
|
||||
usecuda?: boolean;
|
||||
usevulkan?: boolean;
|
||||
useclblast?: boolean | [number, number];
|
||||
gpuDeviceSelection?: string;
|
||||
tensorSplit?: string;
|
||||
gpuPlatform?: number;
|
||||
sdmodel?: string;
|
||||
sdt5xxl?: string;
|
||||
sdclipl?: string;
|
||||
sdclipg?: string;
|
||||
sdphotomaker?: string;
|
||||
sdvae?: string;
|
||||
sdlora?: string;
|
||||
sdconvdirect?: string;
|
||||
additionalArguments?: string;
|
||||
autoGpuLayers?: boolean;
|
||||
model?: string;
|
||||
backend?: string;
|
||||
}
|
||||
|
||||
export interface KoboldAPI {
|
||||
getInstalledVersions: () => Promise<InstalledVersion[]>;
|
||||
getCurrentBinaryInfo: () => Promise<{
|
||||
path: string;
|
||||
filename: string;
|
||||
} | null>;
|
||||
setCurrentVersion: (version: string) => Promise<boolean>;
|
||||
getLatestRelease: () => Promise<DownloadItem[]>;
|
||||
getPlatform: () => Promise<PlatformInfo>;
|
||||
detectGPU: () => Promise<BasicGPUInfo>;
|
||||
detectCPU: () => Promise<CPUCapabilities>;
|
||||
|
|
@ -90,50 +123,17 @@ export interface KoboldAPI {
|
|||
path?: string;
|
||||
error?: string;
|
||||
}>;
|
||||
getROCmDownload: () => Promise<DownloadItem | null>;
|
||||
getLatestReleaseWithStatus: () => Promise<ReleaseWithStatus | null>;
|
||||
launchKoboldCpp: (
|
||||
args?: string[]
|
||||
) => Promise<{ success: boolean; pid?: number; error?: string }>;
|
||||
getConfigFiles: () => Promise<{ name: string; path: string; size: number }[]>;
|
||||
saveConfigFile: (
|
||||
configName: string,
|
||||
configData: {
|
||||
gpulayers?: number;
|
||||
contextsize?: number;
|
||||
model_param?: string;
|
||||
port?: number;
|
||||
host?: string;
|
||||
multiuser?: number;
|
||||
multiplayer?: boolean;
|
||||
remotetunnel?: boolean;
|
||||
nocertify?: boolean;
|
||||
websearch?: boolean;
|
||||
noshift?: boolean;
|
||||
flashattention?: boolean;
|
||||
noavx2?: boolean;
|
||||
failsafe?: boolean;
|
||||
usemmap?: boolean;
|
||||
usecuda?: boolean;
|
||||
usevulkan?: boolean;
|
||||
useclblast?: boolean;
|
||||
sdmodel?: string;
|
||||
sdt5xxl?: string;
|
||||
sdclipl?: string;
|
||||
sdclipg?: string;
|
||||
sdphotomaker?: string;
|
||||
sdvae?: string;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
configData: KoboldConfig
|
||||
) => Promise<boolean>;
|
||||
getSelectedConfig: () => Promise<string | null>;
|
||||
setSelectedConfig: (configName: string) => Promise<boolean>;
|
||||
parseConfigFile: (filePath: string) => Promise<{
|
||||
gpulayers?: number;
|
||||
contextsize?: number;
|
||||
model_param?: string;
|
||||
[key: string]: unknown;
|
||||
} | null>;
|
||||
parseConfigFile: (filePath: string) => Promise<KoboldConfig | null>;
|
||||
selectModelFile: () => Promise<string | null>;
|
||||
stopKoboldCpp: () => void;
|
||||
onDownloadProgress: (callback: (progress: number) => void) => void;
|
||||
|
|
@ -145,6 +145,7 @@ export interface KoboldAPI {
|
|||
|
||||
export interface AppAPI {
|
||||
openExternal: (url: string) => Promise<void>;
|
||||
getVersion: () => Promise<string>;
|
||||
}
|
||||
|
||||
export interface ConfigAPI {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue