mirror of
https://github.com/jamiepine/voicebox.git
synced 2026-10-03 00:55:14 -07:00
Enhance ProviderSettings component for platform-specific functionality
- Added platform detection for macOS and Windows to improve user experience. - Updated UI to conditionally disable options and provide clearer guidance based on installed providers. - Refactored button states and labels for PyTorch CUDA and CPU to reflect availability and download status accurately.
This commit is contained in:
@@ -22,6 +22,12 @@ import { apiClient } from '@/lib/api/client';
|
|||||||
import { useModelDownloadToast } from '@/lib/hooks/useModelDownloadToast';
|
import { useModelDownloadToast } from '@/lib/hooks/useModelDownloadToast';
|
||||||
|
|
||||||
const isMacOS = () => navigator.platform.toLowerCase().includes('mac');
|
const isMacOS = () => navigator.platform.toLowerCase().includes('mac');
|
||||||
|
const isWindows = () => navigator.platform.toLowerCase().includes('win');
|
||||||
|
const getPlatformName = () => {
|
||||||
|
if (isMacOS()) return 'macOS';
|
||||||
|
if (isWindows()) return 'Windows';
|
||||||
|
return 'Linux';
|
||||||
|
};
|
||||||
|
|
||||||
type ProviderType =
|
type ProviderType =
|
||||||
| 'auto'
|
| 'auto'
|
||||||
@@ -200,14 +206,12 @@ export function ProviderSettings() {
|
|||||||
disabled={isStarting}
|
disabled={isStarting}
|
||||||
>
|
>
|
||||||
{/* PyTorch CUDA */}
|
{/* PyTorch CUDA */}
|
||||||
<div
|
<div className="flex items-center justify-between py-2">
|
||||||
className={`flex items-center justify-between py-2 ${isMacOS() ? 'opacity-50' : ''}`}
|
<div className={`flex items-center space-x-3 flex-1 ${isMacOS() || !installedProviders.includes('pytorch-cuda') ? 'opacity-50' : ''}`}>
|
||||||
>
|
<RadioGroupItem value="pytorch-cuda" id="cuda" disabled={isMacOS() || isStarting || !installedProviders.includes('pytorch-cuda')} />
|
||||||
<div className="flex items-center space-x-3 flex-1">
|
|
||||||
<RadioGroupItem value="pytorch-cuda" id="cuda" disabled={isMacOS() || isStarting} />
|
|
||||||
<Label
|
<Label
|
||||||
htmlFor="cuda"
|
htmlFor="cuda"
|
||||||
className={`flex-1 ${isMacOS() || isStarting ? 'cursor-not-allowed' : 'cursor-pointer'}`}
|
className={`flex-1 ${isMacOS() || isStarting || !installedProviders.includes('pytorch-cuda') ? 'cursor-not-allowed' : 'cursor-pointer'}`}
|
||||||
>
|
>
|
||||||
<div className="font-medium">PyTorch CUDA</div>
|
<div className="font-medium">PyTorch CUDA</div>
|
||||||
<div className="text-sm text-muted-foreground">
|
<div className="text-sm text-muted-foreground">
|
||||||
@@ -216,41 +220,45 @@ export function ProviderSettings() {
|
|||||||
</Label>
|
</Label>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
{!installedProviders.includes('pytorch-cuda') && (
|
{isMacOS() && (
|
||||||
<Button
|
<>
|
||||||
onClick={() => handleDownload('pytorch-cuda')}
|
<span className="text-xs text-muted-foreground">2.4GB</span>
|
||||||
size="sm"
|
<Button size="sm" variant="secondary" disabled>
|
||||||
disabled={downloadingProvider === 'pytorch-cuda' || isStarting}
|
Not Available on macOS
|
||||||
>
|
</Button>
|
||||||
{downloadingProvider === 'pytorch-cuda' ? (
|
</>
|
||||||
<Icon icon="svg-spinners:ring-resize" className="h-4 w-4 animate-spin" />
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<HugeiconsIcon icon={Download01Icon} size={16} className="h-4 w-4 mr-1" />
|
|
||||||
Download (2.4GB)
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Button>
|
|
||||||
)}
|
)}
|
||||||
{installedProviders.includes('pytorch-cuda') &&
|
{!isMacOS() && !installedProviders.includes('pytorch-cuda') && (
|
||||||
selectedProvider !== 'pytorch-cuda' && (
|
<>
|
||||||
|
<span className="text-xs text-muted-foreground">2.4GB</span>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => handleStart('pytorch-cuda')}
|
onClick={() => handleDownload('pytorch-cuda')}
|
||||||
size="sm"
|
size="sm"
|
||||||
variant="outline"
|
variant="outline"
|
||||||
disabled={isStarting}
|
disabled={downloadingProvider === 'pytorch-cuda' || isStarting}
|
||||||
|
className="shrink-0"
|
||||||
>
|
>
|
||||||
Start
|
{downloadingProvider === 'pytorch-cuda' ? (
|
||||||
|
<Icon icon="svg-spinners:ring-resize" className="h-4 w-4 animate-spin" />
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<HugeiconsIcon icon={Download01Icon} size={16} className="h-4 w-4 mr-2" />
|
||||||
|
Download
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
</>
|
||||||
|
)}
|
||||||
{installedProviders.includes('pytorch-cuda') && (
|
{installedProviders.includes('pytorch-cuda') && (
|
||||||
<Button
|
<Button
|
||||||
onClick={() => handleDelete('pytorch-cuda')}
|
onClick={() => handleDelete('pytorch-cuda')}
|
||||||
size="sm"
|
size="sm"
|
||||||
variant="ghost"
|
variant="outline"
|
||||||
disabled={isStarting}
|
disabled={isStarting}
|
||||||
|
className="shrink-0"
|
||||||
>
|
>
|
||||||
<HugeiconsIcon icon={Delete01Icon} size={16} className="h-4 w-4" />
|
<HugeiconsIcon icon={Delete01Icon} size={16} className="h-4 w-4 mr-2" />
|
||||||
|
Uninstall
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -258,11 +266,11 @@ export function ProviderSettings() {
|
|||||||
|
|
||||||
{/* PyTorch CPU */}
|
{/* PyTorch CPU */}
|
||||||
<div className="flex items-center justify-between py-2">
|
<div className="flex items-center justify-between py-2">
|
||||||
<div className="flex items-center space-x-3 flex-1">
|
<div className={`flex items-center space-x-3 flex-1 ${!installedProviders.includes('pytorch-cpu') ? 'opacity-50' : ''}`}>
|
||||||
<RadioGroupItem value="pytorch-cpu" id="cpu" disabled={isStarting} />
|
<RadioGroupItem value="pytorch-cpu" id="cpu" disabled={isStarting || !installedProviders.includes('pytorch-cpu')} />
|
||||||
<Label
|
<Label
|
||||||
htmlFor="cpu"
|
htmlFor="cpu"
|
||||||
className={`flex-1 ${isStarting ? 'cursor-not-allowed' : 'cursor-pointer'}`}
|
className={`flex-1 ${isStarting || !installedProviders.includes('pytorch-cpu') ? 'cursor-not-allowed' : 'cursor-pointer'}`}
|
||||||
>
|
>
|
||||||
<div className="font-medium">PyTorch CPU</div>
|
<div className="font-medium">PyTorch CPU</div>
|
||||||
<div className="text-sm text-muted-foreground">
|
<div className="text-sm text-muted-foreground">
|
||||||
@@ -272,64 +280,67 @@ export function ProviderSettings() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
{!installedProviders.includes('pytorch-cpu') && (
|
{!installedProviders.includes('pytorch-cpu') && (
|
||||||
<Button
|
<>
|
||||||
onClick={() => handleDownload('pytorch-cpu')}
|
<span className="text-xs text-muted-foreground">242MB</span>
|
||||||
size="sm"
|
|
||||||
disabled={downloadingProvider === 'pytorch-cpu' || isStarting}
|
|
||||||
>
|
|
||||||
{downloadingProvider === 'pytorch-cpu' ? (
|
|
||||||
<Icon icon="svg-spinners:ring-resize" className="h-4 w-4 animate-spin" />
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<HugeiconsIcon icon={Download01Icon} size={16} className="h-4 w-4 mr-1" />
|
|
||||||
Download (300MB)
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
{installedProviders.includes('pytorch-cpu') &&
|
|
||||||
selectedProvider !== 'pytorch-cpu' && (
|
|
||||||
<Button
|
<Button
|
||||||
onClick={() => handleStart('pytorch-cpu')}
|
onClick={() => handleDownload('pytorch-cpu')}
|
||||||
size="sm"
|
size="sm"
|
||||||
variant="outline"
|
variant="outline"
|
||||||
disabled={isStarting}
|
disabled={downloadingProvider === 'pytorch-cpu' || isStarting}
|
||||||
|
className="shrink-0"
|
||||||
>
|
>
|
||||||
Start
|
{downloadingProvider === 'pytorch-cpu' ? (
|
||||||
|
<Icon icon="svg-spinners:ring-resize" className="h-4 w-4 animate-spin" />
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<HugeiconsIcon icon={Download01Icon} size={16} className="h-4 w-4 mr-2" />
|
||||||
|
Download
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
</>
|
||||||
|
)}
|
||||||
{installedProviders.includes('pytorch-cpu') && (
|
{installedProviders.includes('pytorch-cpu') && (
|
||||||
<Button
|
<Button
|
||||||
onClick={() => handleDelete('pytorch-cpu')}
|
onClick={() => handleDelete('pytorch-cpu')}
|
||||||
size="sm"
|
size="sm"
|
||||||
variant="ghost"
|
variant="outline"
|
||||||
disabled={isStarting}
|
disabled={isStarting}
|
||||||
|
className="shrink-0"
|
||||||
>
|
>
|
||||||
<HugeiconsIcon icon={Delete01Icon} size={16} className="h-4 w-4" />
|
<HugeiconsIcon icon={Delete01Icon} size={16} className="h-4 w-4 mr-2" />
|
||||||
|
Uninstall
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* MLX bundled (macOS Apple Silicon only) */}
|
{/* MLX bundled (macOS Apple Silicon only) */}
|
||||||
<div className="flex items-center space-x-3 py-2">
|
<div className="flex items-center justify-between py-2">
|
||||||
<RadioGroupItem value="apple-mlx" id="mlx" disabled={isStarting || !isMacOS()} />
|
<div className={`flex items-center space-x-3 flex-1 ${!isMacOS() ? 'opacity-50' : ''}`}>
|
||||||
<Label
|
<RadioGroupItem value="apple-mlx" id="mlx" disabled={isStarting || !isMacOS()} />
|
||||||
htmlFor="mlx"
|
<Label
|
||||||
className={`flex-1 ${isStarting ? 'cursor-not-allowed' : 'cursor-pointer'}`}
|
htmlFor="mlx"
|
||||||
>
|
className={`flex-1 ${isStarting || !isMacOS() ? 'cursor-not-allowed' : 'cursor-pointer'}`}
|
||||||
<div className="font-medium">Apple MLX</div>
|
>
|
||||||
<div className="text-sm text-muted-foreground">
|
<div className="font-medium">Apple MLX</div>
|
||||||
{isMacOS()
|
<div className="text-sm text-muted-foreground">
|
||||||
? 'Bundled with this version, optimized for Apple Silicon'
|
{isMacOS()
|
||||||
: 'Only available on Apple Silicon'}
|
? 'Bundled with this version, optimized for Apple Silicon'
|
||||||
</div>
|
: 'Only available on Apple Silicon'}
|
||||||
</Label>
|
</div>
|
||||||
|
</Label>
|
||||||
|
</div>
|
||||||
|
{!isMacOS() && (
|
||||||
|
<Button size="sm" variant="secondary" disabled>
|
||||||
|
Not Available on {getPlatformName()}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Remote */}
|
{/* Remote */}
|
||||||
<div className="space-y-2 py-2 opacity-50">
|
<div className="flex items-center justify-between py-2">
|
||||||
<div className="flex items-center space-x-3">
|
<div className="flex items-center space-x-3 flex-1 opacity-50">
|
||||||
<RadioGroupItem value="remote" id="remote" disabled />
|
<RadioGroupItem value="remote" id="remote" disabled />
|
||||||
<Label htmlFor="remote" className="flex-1 cursor-not-allowed">
|
<Label htmlFor="remote" className="flex-1 cursor-not-allowed">
|
||||||
<div className="font-medium">Remote Server</div>
|
<div className="font-medium">Remote Server</div>
|
||||||
@@ -338,17 +349,23 @@ export function ProviderSettings() {
|
|||||||
</div>
|
</div>
|
||||||
</Label>
|
</Label>
|
||||||
</div>
|
</div>
|
||||||
|
<Button size="sm" variant="secondary" disabled>
|
||||||
|
Coming Soon
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* OpenAI */}
|
{/* OpenAI */}
|
||||||
<div className="space-y-2 py-2 opacity-50">
|
<div className="flex items-center justify-between py-2">
|
||||||
<div className="flex items-center space-x-3">
|
<div className="flex items-center space-x-3 flex-1 opacity-50">
|
||||||
<RadioGroupItem value="openai" id="openai" disabled />
|
<RadioGroupItem value="openai" id="openai" disabled />
|
||||||
<Label htmlFor="openai" className="flex-1 cursor-not-allowed">
|
<Label htmlFor="openai" className="flex-1 cursor-not-allowed">
|
||||||
<div className="font-medium">OpenAI API</div>
|
<div className="font-medium">OpenAI API</div>
|
||||||
<div className="text-sm text-muted-foreground">Use OpenAI's TTS API</div>
|
<div className="text-sm text-muted-foreground">Use OpenAI's TTS API</div>
|
||||||
</Label>
|
</Label>
|
||||||
</div>
|
</div>
|
||||||
|
<Button size="sm" variant="secondary" disabled>
|
||||||
|
Coming Soon
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</RadioGroup>
|
</RadioGroup>
|
||||||
<p className="text-xs text-muted-foreground mt-5">
|
<p className="text-xs text-muted-foreground mt-5">
|
||||||
|
|||||||
@@ -220,16 +220,11 @@ class ProviderManager:
|
|||||||
installed.append("pytorch-cpu")
|
installed.append("pytorch-cpu")
|
||||||
# Linux: no bundled provider - users must download
|
# Linux: no bundled provider - users must download
|
||||||
|
|
||||||
# Check for downloaded providers (Phase 2)
|
# Check for downloaded providers by checking if binary path exists
|
||||||
providers_dir = _get_providers_dir()
|
for provider_type in ["pytorch-cpu", "pytorch-cuda"]:
|
||||||
if providers_dir.exists():
|
binary_path = get_provider_binary_path(provider_type)
|
||||||
for provider_file in providers_dir.glob("tts-provider-*"):
|
if binary_path and binary_path.exists() and provider_type not in installed:
|
||||||
if provider_file.is_file() and provider_file.stat().st_size > 0:
|
installed.append(provider_type)
|
||||||
name = provider_file.name
|
|
||||||
if "pytorch-cpu" in name:
|
|
||||||
installed.append("pytorch-cpu")
|
|
||||||
elif "pytorch-cuda" in name:
|
|
||||||
installed.append("pytorch-cuda")
|
|
||||||
|
|
||||||
return installed
|
return installed
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Reference in New Issue
Block a user