mirror of
https://github.com/jamiepine/voicebox.git
synced 2026-09-20 15:20:39 -07:00
Update dependencies and enhance UI components for better functionality
- Added new Tauri plugins: @tauri-apps/plugin-process and @tauri-apps/plugin-updater to improve application capabilities. - Introduced UpdateStatus component to display update information in the UI. - Enhanced GenerationForm to include an optional instruct field for additional input. - Refactored various components for improved styling and responsiveness, including Sidebar, AudioPlayer, and ProfileCard. - Updated API models and schemas to accommodate new instruct parameter in generation requests and responses. - Improved documentation for autoupdater setup and usage.
This commit is contained in:
@@ -77,9 +77,7 @@ export function ConnectionForm() {
|
||||
)}
|
||||
/>
|
||||
|
||||
{isDirty && (
|
||||
<Button type="submit">Update Connection</Button>
|
||||
)}
|
||||
{isDirty && <Button type="submit">Update Connection</Button>}
|
||||
</form>
|
||||
</Form>
|
||||
|
||||
@@ -106,8 +104,8 @@ export function ConnectionForm() {
|
||||
Keep server running when app closes
|
||||
</label>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
When enabled, the server will continue running in the background after closing the app.
|
||||
Disabled by default.
|
||||
When enabled, the server will continue running in the background after closing the
|
||||
app. Disabled by default.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -73,7 +73,9 @@ export function ModelManagement() {
|
||||
<div className="space-y-4">
|
||||
{/* TTS Models */}
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold mb-3 text-muted-foreground">Voice Generation Models</h3>
|
||||
<h3 className="text-sm font-semibold mb-3 text-muted-foreground">
|
||||
Voice Generation Models
|
||||
</h3>
|
||||
<div className="space-y-2">
|
||||
{modelStatus.models
|
||||
.filter((m) => m.model_name.startsWith('qwen-tts'))
|
||||
@@ -91,7 +93,9 @@ export function ModelManagement() {
|
||||
|
||||
{/* Whisper Models */}
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold mb-3 text-muted-foreground">Transcription Models</h3>
|
||||
<h3 className="text-sm font-semibold mb-3 text-muted-foreground">
|
||||
Transcription Models
|
||||
</h3>
|
||||
<div className="space-y-2">
|
||||
{modelStatus.models
|
||||
.filter((m) => m.model_name.startsWith('whisper'))
|
||||
@@ -109,7 +113,9 @@ export function ModelManagement() {
|
||||
|
||||
{/* Progress indicators */}
|
||||
<div className="pt-4 border-t">
|
||||
<h3 className="text-sm font-semibold mb-3 text-muted-foreground">Download Progress</h3>
|
||||
<h3 className="text-sm font-semibold mb-3 text-muted-foreground">
|
||||
Download Progress
|
||||
</h3>
|
||||
<div className="space-y-2">
|
||||
{modelStatus.models.map((model) => (
|
||||
<ModelProgress
|
||||
@@ -147,10 +153,14 @@ function ModelItem({ model, onDownload, isDownloading, formatSize }: ModelItemPr
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="font-medium text-sm">{model.display_name}</span>
|
||||
{model.loaded && (
|
||||
<Badge variant="default" className="text-xs">Loaded</Badge>
|
||||
<Badge variant="default" className="text-xs">
|
||||
Loaded
|
||||
</Badge>
|
||||
)}
|
||||
{model.downloaded && !model.loaded && (
|
||||
<Badge variant="secondary" className="text-xs">Downloaded</Badge>
|
||||
<Badge variant="secondary" className="text-xs">
|
||||
Downloaded
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
{model.downloaded && model.size_mb && (
|
||||
@@ -166,12 +176,7 @@ function ModelItem({ model, onDownload, isDownloading, formatSize }: ModelItemPr
|
||||
<span>Ready</span>
|
||||
</div>
|
||||
) : (
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={onDownload}
|
||||
disabled={isDownloading}
|
||||
variant="outline"
|
||||
>
|
||||
<Button size="sm" onClick={onDownload} disabled={isDownloading} variant="outline">
|
||||
{isDownloading ? (
|
||||
<>
|
||||
<Loader2 className="h-4 w-4 mr-2 animate-spin" />
|
||||
|
||||
@@ -25,7 +25,7 @@ export function ModelProgress({ modelName, displayName }: ModelProgressProps) {
|
||||
try {
|
||||
const data = JSON.parse(event.data) as ModelProgressType;
|
||||
setProgress(data);
|
||||
|
||||
|
||||
// Close connection if complete or error
|
||||
if (data.status === 'complete' || data.status === 'error') {
|
||||
eventSource.close();
|
||||
@@ -51,7 +51,10 @@ export function ModelProgress({ modelName, displayName }: ModelProgressProps) {
|
||||
}, [serverUrl, modelName, isSubscribed]);
|
||||
|
||||
// Don't render if no progress or if complete/error and some time has passed
|
||||
if (!progress || (progress.status === 'complete' && Date.now() - new Date(progress.timestamp).getTime() > 5000)) {
|
||||
if (
|
||||
!progress ||
|
||||
(progress.status === 'complete' && Date.now() - new Date(progress.timestamp).getTime() > 5000)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -111,9 +114,7 @@ export function ModelProgress({ modelName, displayName }: ModelProgressProps) {
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
{progress.total > 0 && (
|
||||
<Progress value={progress.progress} className="h-2" />
|
||||
)}
|
||||
{progress.total > 0 && <Progress value={progress.progress} className="h-2" />}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
@@ -47,7 +47,9 @@ export function ServerStatus() {
|
||||
<span className="text-sm">Connected</span>
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
<Badge variant={health.model_loaded || health.model_downloaded ? 'default' : 'secondary'}>
|
||||
<Badge
|
||||
variant={health.model_loaded || health.model_downloaded ? 'default' : 'secondary'}
|
||||
>
|
||||
{health.model_loaded || health.model_downloaded ? 'Model Ready' : 'No Model'}
|
||||
</Badge>
|
||||
<Badge variant={health.gpu_available ? 'default' : 'secondary'}>
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { RefreshCw, Download, CheckCircle2, AlertCircle } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Progress } from '@/components/ui/progress';
|
||||
import { useAutoUpdater } from '@/hooks/useAutoUpdater';
|
||||
import { getVersion } from '@tauri-apps/api/app';
|
||||
|
||||
export function UpdateStatus() {
|
||||
const { status, checkForUpdates, downloadAndInstall } = useAutoUpdater(false);
|
||||
const [currentVersion, setCurrentVersion] = useState<string>('');
|
||||
|
||||
useEffect(() => {
|
||||
getVersion()
|
||||
.then(setCurrentVersion)
|
||||
.catch(() => setCurrentVersion('0.1.0'));
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>App Updates</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="space-y-1">
|
||||
<div className="text-sm font-medium">Current Version</div>
|
||||
<div className="text-sm text-muted-foreground">v{currentVersion}</div>
|
||||
</div>
|
||||
<Button
|
||||
onClick={checkForUpdates}
|
||||
disabled={status.checking || status.downloading || status.installing}
|
||||
variant="outline"
|
||||
size="sm"
|
||||
>
|
||||
<RefreshCw className={`h-4 w-4 mr-2 ${status.checking ? 'animate-spin' : ''}`} />
|
||||
Check for Updates
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{status.checking && (
|
||||
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
||||
<RefreshCw className="h-4 w-4 animate-spin" />
|
||||
Checking for updates...
|
||||
</div>
|
||||
)}
|
||||
|
||||
{status.error && (
|
||||
<div className="flex items-center gap-2 text-sm text-destructive">
|
||||
<AlertCircle className="h-4 w-4" />
|
||||
{status.error}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{status.available && !status.downloading && !status.installing && (
|
||||
<div className="space-y-3 p-4 border rounded-lg bg-primary/5">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<div className="font-semibold">Update Available</div>
|
||||
<div className="text-sm text-muted-foreground">Version {status.version}</div>
|
||||
</div>
|
||||
<Badge>New</Badge>
|
||||
</div>
|
||||
<Button onClick={downloadAndInstall} className="w-full" size="sm">
|
||||
<Download className="h-4 w-4 mr-2" />
|
||||
Install Update
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{status.downloading && (
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center gap-2 text-sm">
|
||||
<Download className="h-4 w-4" />
|
||||
Downloading update...
|
||||
</div>
|
||||
<Progress />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{status.installing && (
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center gap-2 text-sm">
|
||||
<RefreshCw className="h-4 w-4 animate-spin" />
|
||||
Installing update...
|
||||
</div>
|
||||
<div className="text-xs text-muted-foreground">App will restart automatically</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!status.available && !status.checking && !status.error && status.checking === false && (
|
||||
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
||||
<CheckCircle2 className="h-4 w-4 text-green-500" />
|
||||
You're up to date
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user