import { useState, useEffect, useCallback } from 'react'; import { Card, Text, Title, Loader, Stack, Container } from '@mantine/core'; import { DownloadOptionCard } from '@/components/DownloadOptionCard'; import { getPlatformDisplayName, filterAssetsByPlatform, } from '@/utils/platform'; import { formatFileSize } from '@/utils/fileSize'; import { getAssetDescription, isAssetRecommended, sortAssetsByRecommendation, } from '@/utils/assets'; import { ROCM } from '@/constants/app'; import type { GitHubAsset, GitHubRelease } from '@/types'; interface DownloadScreenProps { onDownloadComplete: () => void; } export const DownloadScreen = ({ onDownloadComplete }: DownloadScreenProps) => { const [latestRelease, setLatestRelease] = useState( null ); const [filteredAssets, setFilteredAssets] = useState([]); const [selectedAsset, setSelectedAsset] = useState(null); const [selectedROCm, setSelectedROCm] = useState(false); const [userPlatform, setUserPlatform] = useState(''); const [hasAMDGPU, setHasAMDGPU] = useState(false); const [loading, setLoading] = useState(true); const [downloading, setDownloading] = useState(false); const [downloadProgress, setDownloadProgress] = useState(0); const [downloadingType, setDownloadingType] = useState< 'asset' | 'rocm' | null >(null); const [rocmDownload, setRocmDownload] = useState<{ name: string; url: string; size: number; version?: string; } | null>(null); const loadLatestReleaseAndPlatform = useCallback(async () => { try { setLoading(true); const [platformInfo, releaseData, rocmDownloadInfo] = await Promise.all([ window.electronAPI.kobold.getPlatform(), window.electronAPI.kobold.getLatestRelease(), window.electronAPI.kobold.getROCmDownload(), ]); setUserPlatform(platformInfo.platform); setLatestRelease(releaseData); setRocmDownload(rocmDownloadInfo); try { const gpuInfo = await window.electronAPI.kobold.detectGPU(); setHasAMDGPU(gpuInfo.hasAMD); } catch (gpuError) { console.warn( 'GPU detection failed, proceeding without GPU info:', gpuError ); setHasAMDGPU(false); } if (releaseData) { const filtered = filterAssetsByPlatform( releaseData.assets, platformInfo.platform ); setFilteredAssets(filtered); } else { console.error( 'GitHub API is currently unavailable. Please try again later.' ); } } catch (err) { console.error('Failed to load release information:', err); } finally { setLoading(false); } }, []); useEffect(() => { loadLatestReleaseAndPlatform(); window.electronAPI.kobold.onDownloadProgress((progress: number) => { setDownloadProgress(progress); }); return () => { window.electronAPI.kobold.removeAllListeners('download-progress'); }; // eslint-disable-next-line react-hooks/exhaustive-deps }, []); const handleDownload = async (type: 'asset' | 'rocm' = 'asset') => { if (type === 'asset' && !selectedAsset) return; try { setDownloading(true); setDownloadProgress(0); setDownloadingType(type); const result = type === 'rocm' ? await window.electronAPI.kobold.downloadROCm() : await window.electronAPI.kobold.downloadRelease(selectedAsset!); if (result.success) { onDownloadComplete(); } else { console.error( 'Download Failed', result.error || `${type === 'rocm' ? 'ROCm' : ''} Download failed` ); } } catch (err) { console.error(`${type === 'rocm' ? 'ROCm' : ''} Download error:`, err); } finally { setDownloading(false); setDownloadProgress(0); setDownloadingType(null); } }; const renderROCmCard = () => { if (!rocmDownload) return null; return ( { if (!selectedROCm) { setSelectedROCm(true); setSelectedAsset(null); } }} onDownload={(e) => { e.stopPropagation(); handleDownload('rocm'); }} /> ); }; return ( Available Binaries for Your Platform {loading ? ( Loading latest release... ) : ( <> {latestRelease && ( <>
Latest Version {(latestRelease.tag_name || latestRelease.name) .replace(/^v/, '') .replace(/^koboldcpp-/, '')} Released{' '} {new Date( latestRelease.published_at ).toLocaleDateString()}
{filteredAssets.length > 0 || rocmDownload ? ( {rocmDownload && hasAMDGPU && renderROCmCard()} {sortAssetsByRecommendation( filteredAssets, hasAMDGPU ).map((asset) => ( { if (selectedAsset?.name !== asset.name) { setSelectedAsset(asset); setSelectedROCm(false); } }} onDownload={(e) => { e.stopPropagation(); handleDownload(); }} /> ))} {rocmDownload && !hasAMDGPU && renderROCmCard()} ) : ( No downloads available No downloads available for your platform ( {getPlatformDisplayName(userPlatform)}). )} )} )}
); };