mirror of
https://github.com/lone-cloud/gerbil
synced 2026-06-04 12:13:28 -07:00
don't need to recommend ROCm as it's not that good compared to generally available Vulkan
This commit is contained in:
parent
1e7fd585f7
commit
82aa274e00
8 changed files with 42 additions and 208 deletions
|
|
@ -9,7 +9,6 @@ A koboldcpp manager. <!-- markdownlint-disable MD033 -->
|
|||
|
||||
- modern UI for [koboldcpp](https://github.com/LostRuins/koboldcpp) with full support for Linux Wayland
|
||||
- download and keep up-to-date your [koboldcpp](https://github.com/LostRuins/koboldcpp/releases) binary
|
||||
- better surface the ROCm-specific builds of koboldcpp from YellowRoseCx and from [koboldai.org](https://koboldai.org/cpplinuxrocm)
|
||||
- manage the koboldcpp binary to prevent it from running in the background indefinitely
|
||||
- automatically unpack all downloaded koboldcpp binaries for significantly faster operation and reduced RAM+HDD utilization (up to ~4GB less RAM usage for ROCm)
|
||||
- added presets for a basic flux or chroma image generation setup
|
||||
|
|
|
|||
|
|
@ -113,13 +113,7 @@ export const App = () => {
|
|||
|
||||
const handleBinaryUpdate = async (download: DownloadItem) => {
|
||||
try {
|
||||
const downloadType = download.type === 'rocm' ? 'rocm' : 'asset';
|
||||
const success = await sharedHandleDownload(
|
||||
downloadType,
|
||||
download,
|
||||
true,
|
||||
true
|
||||
);
|
||||
const success = await sharedHandleDownload('asset', download, true, true);
|
||||
|
||||
if (success) {
|
||||
dismissUpdate();
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ interface DownloadCardProps {
|
|||
size: string;
|
||||
version?: string;
|
||||
description?: string;
|
||||
isRecommended?: boolean;
|
||||
isCurrent?: boolean;
|
||||
isInstalled?: boolean;
|
||||
isDownloading?: boolean;
|
||||
|
|
@ -36,7 +35,6 @@ export const DownloadCard = ({
|
|||
size,
|
||||
version,
|
||||
description,
|
||||
isRecommended = false,
|
||||
isCurrent = false,
|
||||
isInstalled = false,
|
||||
isDownloading = false,
|
||||
|
|
@ -122,11 +120,6 @@ export const DownloadCard = ({
|
|||
Current
|
||||
</Badge>
|
||||
)}
|
||||
{isRecommended && (
|
||||
<Badge variant="light" color="blue" size="sm">
|
||||
Recommended
|
||||
</Badge>
|
||||
)}
|
||||
{hasUpdate && (
|
||||
<Badge variant="light" color="orange" size="sm">
|
||||
Update Available
|
||||
|
|
|
|||
|
|
@ -1,20 +1,8 @@
|
|||
import { useState, useCallback, useEffect, useRef } from 'react';
|
||||
import {
|
||||
Card,
|
||||
Text,
|
||||
Title,
|
||||
Loader,
|
||||
Stack,
|
||||
Container,
|
||||
Anchor,
|
||||
} from '@mantine/core';
|
||||
import { Card, Text, Title, Loader, Stack, Container } from '@mantine/core';
|
||||
import { DownloadCard } from '@/components/DownloadCard';
|
||||
import { getPlatformDisplayName, formatDownloadSize } from '@/utils';
|
||||
import {
|
||||
isAssetRecommended,
|
||||
sortAssetsByRecommendation,
|
||||
getAssetDescription,
|
||||
} from '@/utils/assets';
|
||||
import { getAssetDescription, sortDownloadsByType } from '@/utils/assets';
|
||||
import { useKoboldVersions } from '@/hooks/useKoboldVersions';
|
||||
import type { DownloadItem } from '@/types/electron';
|
||||
|
||||
|
|
@ -33,27 +21,20 @@ export const DownloadScreen = ({ onDownloadComplete }: DownloadScreenProps) => {
|
|||
handleDownload: sharedHandleDownload,
|
||||
} = useKoboldVersions();
|
||||
|
||||
const [downloadingType, setDownloadingType] = useState<
|
||||
'asset' | 'rocm' | null
|
||||
>(null);
|
||||
const [downloadingAsset, setDownloadingAsset] = useState<string | null>(null);
|
||||
const downloadingItemRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const loading = loadingPlatform || loadingRemote;
|
||||
|
||||
const regularDownloads = availableDownloads.filter((d) => d.type === 'asset');
|
||||
const rocmDownload = availableDownloads.find((d) => d.type === 'rocm');
|
||||
const sortedDownloads = sortDownloadsByType(availableDownloads);
|
||||
|
||||
const handleDownload = useCallback(
|
||||
async (type: 'asset' | 'rocm', download?: DownloadItem) => {
|
||||
if (type === 'asset' && !download) return;
|
||||
|
||||
setDownloadingType(type);
|
||||
setDownloadingAsset(type === 'asset' ? download!.name : null);
|
||||
async (download: DownloadItem) => {
|
||||
setDownloadingAsset(download.name);
|
||||
|
||||
try {
|
||||
const success = await sharedHandleDownload(
|
||||
type,
|
||||
'asset',
|
||||
download,
|
||||
false,
|
||||
false
|
||||
|
|
@ -63,17 +44,15 @@ export const DownloadScreen = ({ onDownloadComplete }: DownloadScreenProps) => {
|
|||
onDownloadComplete();
|
||||
|
||||
setTimeout(() => {
|
||||
setDownloadingType(null);
|
||||
setDownloadingAsset(null);
|
||||
}, 200);
|
||||
}
|
||||
} catch (error) {
|
||||
window.electronAPI.logs.logError(
|
||||
`Failed to download ${type}:`,
|
||||
`Failed to download ${download.name}:`,
|
||||
error as Error
|
||||
);
|
||||
} finally {
|
||||
setDownloadingType(null);
|
||||
setDownloadingAsset(null);
|
||||
}
|
||||
},
|
||||
|
|
@ -89,38 +68,6 @@ export const DownloadScreen = ({ onDownloadComplete }: DownloadScreenProps) => {
|
|||
}
|
||||
}, [downloading]);
|
||||
|
||||
const renderROCmCard = () => {
|
||||
if (!rocmDownload) return null;
|
||||
|
||||
const isDownloading = Boolean(downloading) && downloadingType === 'rocm';
|
||||
|
||||
return (
|
||||
<div ref={isDownloading ? downloadingItemRef : null}>
|
||||
<DownloadCard
|
||||
name={rocmDownload.name}
|
||||
size={formatDownloadSize(rocmDownload.size, rocmDownload.url, true)}
|
||||
description={getAssetDescription(rocmDownload.name)}
|
||||
version={rocmDownload.version}
|
||||
isRecommended={isAssetRecommended(
|
||||
rocmDownload.name,
|
||||
platformInfo.hasAMDGPU
|
||||
)}
|
||||
isDownloading={isDownloading}
|
||||
downloadProgress={
|
||||
downloadingType === 'rocm'
|
||||
? downloadProgress[rocmDownload.name] || 0
|
||||
: 0
|
||||
}
|
||||
disabled={Boolean(downloading) && downloadingType !== 'rocm'}
|
||||
onDownload={(e) => {
|
||||
e.stopPropagation();
|
||||
handleDownload('rocm', rocmDownload);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Container size="sm">
|
||||
<Stack gap="xl">
|
||||
|
|
@ -139,54 +86,9 @@ export const DownloadScreen = ({ onDownloadComplete }: DownloadScreenProps) => {
|
|||
<>
|
||||
{availableDownloads.length > 0 ? (
|
||||
<Stack gap="sm">
|
||||
{platformInfo.hasAMDGPU &&
|
||||
!platformInfo.hasROCm &&
|
||||
platformInfo.platform === 'linux' && (
|
||||
<Card withBorder p="md" bg="orange.0">
|
||||
<Stack gap="xs">
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '8px',
|
||||
}}
|
||||
>
|
||||
<Text fw={600} c="orange.9">
|
||||
AMD GPU Detected
|
||||
</Text>
|
||||
</div>
|
||||
<Text size="sm" c="orange.8">
|
||||
For best performance with your AMD GPU,
|
||||
consider installing ROCm support.{' '}
|
||||
<Anchor
|
||||
href="#"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
window.electronAPI.app.openExternal(
|
||||
'https://rocm.docs.amd.com/projects/install-on-linux/en/latest/reference/system-requirements.html'
|
||||
);
|
||||
}}
|
||||
size="sm"
|
||||
c="orange.8"
|
||||
>
|
||||
Learn more
|
||||
</Anchor>
|
||||
</Text>
|
||||
</Stack>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
{rocmDownload &&
|
||||
platformInfo.hasAMDGPU &&
|
||||
renderROCmCard()}
|
||||
|
||||
{sortAssetsByRecommendation(
|
||||
regularDownloads,
|
||||
platformInfo.hasAMDGPU
|
||||
).map((download) => {
|
||||
{sortedDownloads.map((download) => {
|
||||
const isDownloading =
|
||||
Boolean(downloading) &&
|
||||
downloadingType === 'asset' &&
|
||||
downloadingAsset === download.name;
|
||||
|
||||
return (
|
||||
|
|
@ -202,10 +104,6 @@ export const DownloadScreen = ({ onDownloadComplete }: DownloadScreenProps) => {
|
|||
)}
|
||||
version={download.version}
|
||||
description={getAssetDescription(download.name)}
|
||||
isRecommended={isAssetRecommended(
|
||||
download.name,
|
||||
platformInfo.hasAMDGPU
|
||||
)}
|
||||
isDownloading={isDownloading}
|
||||
downloadProgress={
|
||||
isDownloading
|
||||
|
|
@ -218,16 +116,12 @@ export const DownloadScreen = ({ onDownloadComplete }: DownloadScreenProps) => {
|
|||
}
|
||||
onDownload={(e) => {
|
||||
e.stopPropagation();
|
||||
handleDownload('asset', download);
|
||||
handleDownload(download);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
||||
{rocmDownload &&
|
||||
!platformInfo.hasAMDGPU &&
|
||||
renderROCmCard()}
|
||||
</Stack>
|
||||
) : (
|
||||
<Card withBorder p="md" bg="yellow.0" c="yellow.9">
|
||||
|
|
|
|||
|
|
@ -12,11 +12,7 @@ import {
|
|||
} from '@mantine/core';
|
||||
import { RotateCcw, ExternalLink } from 'lucide-react';
|
||||
import { DownloadCard } from '@/components/DownloadCard';
|
||||
import {
|
||||
getAssetDescription,
|
||||
sortAssetsByRecommendation,
|
||||
isAssetRecommended,
|
||||
} from '@/utils/assets';
|
||||
import { getAssetDescription, sortDownloadsByType } from '@/utils/assets';
|
||||
import {
|
||||
getDisplayNameFromPath,
|
||||
formatDownloadSize,
|
||||
|
|
@ -34,14 +30,12 @@ interface VersionInfo {
|
|||
isCurrent: boolean;
|
||||
downloadUrl?: string;
|
||||
installedPath?: string;
|
||||
isROCm?: boolean;
|
||||
hasUpdate?: boolean;
|
||||
newerVersion?: string;
|
||||
}
|
||||
|
||||
export const VersionsTab = () => {
|
||||
const {
|
||||
platformInfo,
|
||||
availableDownloads,
|
||||
loadingPlatform,
|
||||
loadingRemote,
|
||||
|
|
@ -131,7 +125,9 @@ export const VersionsTab = () => {
|
|||
const versions: VersionInfo[] = [];
|
||||
const processedInstalled = new Set<string>();
|
||||
|
||||
availableDownloads.forEach((download) => {
|
||||
const sortedDownloads = sortDownloadsByType(availableDownloads);
|
||||
|
||||
sortedDownloads.forEach((download) => {
|
||||
const downloadBaseName = stripAssetExtensions(download.name);
|
||||
|
||||
const installedVersion = installedVersions.find((v) => {
|
||||
|
|
@ -162,7 +158,6 @@ export const VersionsTab = () => {
|
|||
isCurrent,
|
||||
downloadUrl: download.url,
|
||||
installedPath: installedVersion.path,
|
||||
isROCm: download.type === 'rocm',
|
||||
hasUpdate,
|
||||
newerVersion: hasUpdate ? download.version : undefined,
|
||||
});
|
||||
|
|
@ -174,7 +169,6 @@ export const VersionsTab = () => {
|
|||
isInstalled: false,
|
||||
isCurrent: false,
|
||||
downloadUrl: download.url,
|
||||
isROCm: download.type === 'rocm',
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
@ -193,18 +187,12 @@ export const VersionsTab = () => {
|
|||
isInstalled: true,
|
||||
isCurrent,
|
||||
installedPath: installed.path,
|
||||
isROCm: false,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return sortAssetsByRecommendation(versions, platformInfo.hasAMDGPU);
|
||||
}, [
|
||||
availableDownloads,
|
||||
installedVersions,
|
||||
currentVersion,
|
||||
platformInfo.hasAMDGPU,
|
||||
]);
|
||||
return versions;
|
||||
}, [availableDownloads, installedVersions, currentVersion]);
|
||||
|
||||
useEffect(() => {
|
||||
if (downloading && downloadingItemRef.current) {
|
||||
|
|
@ -222,9 +210,8 @@ export const VersionsTab = () => {
|
|||
throw new Error('Download not found');
|
||||
}
|
||||
|
||||
const downloadType = download.type === 'rocm' ? 'rocm' : 'asset';
|
||||
const success = await sharedHandleDownload(
|
||||
downloadType,
|
||||
'asset',
|
||||
download,
|
||||
false,
|
||||
false
|
||||
|
|
@ -245,10 +232,9 @@ export const VersionsTab = () => {
|
|||
throw new Error('Download not found');
|
||||
}
|
||||
|
||||
const downloadType = download.type === 'rocm' ? 'rocm' : 'asset';
|
||||
const wasCurrentBinary = version.isCurrent;
|
||||
const success = await sharedHandleDownload(
|
||||
downloadType,
|
||||
'asset',
|
||||
download,
|
||||
true,
|
||||
wasCurrentBinary
|
||||
|
|
@ -368,19 +354,11 @@ export const VersionsTab = () => {
|
|||
name={version.name}
|
||||
size={
|
||||
version.size
|
||||
? formatDownloadSize(
|
||||
version.size,
|
||||
version.downloadUrl,
|
||||
version.isROCm
|
||||
)
|
||||
? formatDownloadSize(version.size, version.downloadUrl)
|
||||
: ''
|
||||
}
|
||||
version={version.version}
|
||||
description={getAssetDescription(version.name)}
|
||||
isRecommended={isAssetRecommended(
|
||||
version.name,
|
||||
platformInfo.hasAMDGPU
|
||||
)}
|
||||
isCurrent={version.isCurrent}
|
||||
isInstalled={version.isInstalled}
|
||||
isDownloading={isDownloading}
|
||||
|
|
|
|||
|
|
@ -38,10 +38,6 @@ export const KOBOLDAI_URLS = {
|
|||
DOMAIN: 'koboldai.org',
|
||||
} as const;
|
||||
|
||||
export const GITHUB_URLS = {
|
||||
DOMAIN: 'github.com',
|
||||
} as const;
|
||||
|
||||
export const ROCM = {
|
||||
BINARY_NAME: 'koboldcpp-linux-x64-rocm',
|
||||
DOWNLOAD_URL: KOBOLDAI_URLS.ROCM_DOWNLOAD,
|
||||
|
|
|
|||
|
|
@ -5,11 +5,11 @@ export const getAssetDescription = (assetName: string): string => {
|
|||
const name = stripAssetExtensions(assetName).toLowerCase();
|
||||
|
||||
if (name.includes(ASSET_SUFFIXES.ROCM)) {
|
||||
return 'Optimized for AMD GPUs with ROCm support.';
|
||||
return 'Adds dedicated ROCm support for AMD GPUs. Note that ROCm is unlikely to perform better than modern Vulkan in most cases.';
|
||||
}
|
||||
|
||||
if (name.endsWith(ASSET_SUFFIXES.OLDPC)) {
|
||||
return 'Meant for old PCs that cannot run the standard build.';
|
||||
return 'Meant for old PCs with outdated CPUs that may not work with the standard build. Does not support modern AVX2 CPU architectures.';
|
||||
}
|
||||
|
||||
if (name.endsWith(ASSET_SUFFIXES.NOCUDA)) {
|
||||
|
|
@ -19,24 +19,6 @@ export const getAssetDescription = (assetName: string): string => {
|
|||
return "Standard build that's ideal for most cases.";
|
||||
};
|
||||
|
||||
export const isAssetRecommended = (
|
||||
assetName: string,
|
||||
hasAMDGPU: boolean
|
||||
): boolean => {
|
||||
const name = stripAssetExtensions(assetName).toLowerCase();
|
||||
|
||||
if (hasAMDGPU && name.includes(ASSET_SUFFIXES.ROCM)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return (
|
||||
!hasAMDGPU &&
|
||||
!name.includes(ASSET_SUFFIXES.ROCM) &&
|
||||
!name.endsWith(ASSET_SUFFIXES.OLDPC) &&
|
||||
!name.endsWith(ASSET_SUFFIXES.NOCUDA)
|
||||
);
|
||||
};
|
||||
|
||||
export const isAssetStandard = (assetName: string): boolean => {
|
||||
const name = stripAssetExtensions(assetName).toLowerCase();
|
||||
|
||||
|
|
@ -47,23 +29,27 @@ export const isAssetStandard = (assetName: string): boolean => {
|
|||
);
|
||||
};
|
||||
|
||||
export const sortAssetsByRecommendation = <T extends { name: string }>(
|
||||
assets: T[],
|
||||
hasAMDGPU: boolean
|
||||
export const sortDownloadsByType = <T extends { name: string }>(
|
||||
downloads: T[]
|
||||
): T[] =>
|
||||
[...assets].sort((a, b) => {
|
||||
const aRecommended = isAssetRecommended(a.name, hasAMDGPU);
|
||||
const bRecommended = isAssetRecommended(b.name, hasAMDGPU);
|
||||
const aStandard = isAssetStandard(a.name);
|
||||
const bStandard = isAssetStandard(b.name);
|
||||
[...downloads].sort((a, b) => {
|
||||
const aName = stripAssetExtensions(a.name).toLowerCase();
|
||||
const bName = stripAssetExtensions(b.name).toLowerCase();
|
||||
|
||||
if (aRecommended && !bRecommended) return -1;
|
||||
if (!aRecommended && bRecommended) return 1;
|
||||
const getOrderPriority = (name: string): number => {
|
||||
if (isAssetStandard(name)) return 0;
|
||||
if (name.includes(ASSET_SUFFIXES.ROCM)) return 1;
|
||||
if (name.endsWith(ASSET_SUFFIXES.NOCUDA)) return 2;
|
||||
if (name.endsWith(ASSET_SUFFIXES.OLDPC)) return 3;
|
||||
return 4;
|
||||
};
|
||||
|
||||
if (aRecommended === bRecommended) {
|
||||
if (aStandard && !bStandard) return -1;
|
||||
if (!aStandard && bStandard) return 1;
|
||||
const aPriority = getOrderPriority(aName);
|
||||
const bPriority = getOrderPriority(bName);
|
||||
|
||||
if (aPriority !== bPriority) {
|
||||
return aPriority - bPriority;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return a.name.localeCompare(b.name);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,16 +1,10 @@
|
|||
import { formatFileSizeInMB } from '@/utils/fileSize';
|
||||
import { KOBOLDAI_URLS, GITHUB_URLS } from '@/constants';
|
||||
import { KOBOLDAI_URLS } from '@/constants';
|
||||
|
||||
export const formatDownloadSize = (
|
||||
size: number,
|
||||
url?: string,
|
||||
isROCm?: boolean
|
||||
): string => {
|
||||
export const formatDownloadSize = (size: number, url?: string): string => {
|
||||
if (!size) return '';
|
||||
|
||||
const isApproximateSize =
|
||||
url?.includes(KOBOLDAI_URLS.DOMAIN) ||
|
||||
(isROCm && !url?.includes(GITHUB_URLS.DOMAIN));
|
||||
const isApproximateSize = url?.includes(KOBOLDAI_URLS.DOMAIN);
|
||||
|
||||
return isApproximateSize
|
||||
? `~${formatFileSizeInMB(size)}`
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue