From 1b66a528d13e72fef696856c215826509f485abf Mon Sep 17 00:00:00 2001
From: Jamie Pine
Date: Fri, 30 Jan 2026 02:53:15 -0800
Subject: [PATCH] Enhance README and UI Components for Performance and Features
- Updated README.md to highlight MLX backend performance improvements on Mac with Metal acceleration.
- Refined ProfileCard and ProfileForm components by optimizing imports and improving error handling for avatar uploads.
- Adjusted landing page content to better describe features, including a new multi-voice narrative editor and performance optimizations for different platforms.
- Bumped version to 0.1.11 in Cargo.lock to reflect recent changes.
---
README.md | 2 ++
.../components/VoiceProfiles/ProfileCard.tsx | 8 ++---
.../components/VoiceProfiles/ProfileForm.tsx | 8 +++--
backend/backends/mlx_backend.py | 29 +++++++++---------
landing/src/app/page.tsx | 22 +++++++------
tauri/src-tauri/Cargo.lock | 2 +-
tauri/src-tauri/gen/Assets.car | Bin 3847048 -> 3847048 bytes
7 files changed, 38 insertions(+), 33 deletions(-)
diff --git a/README.md b/README.md
index 725460ab..0b67840b 100644
--- a/README.md
+++ b/README.md
@@ -68,6 +68,7 @@ Unlike cloud services that lock your voice data behind subscriptions, Voicebox g
- **Model flexibility** — currently powered by Qwen3-TTS, with support for XTTS, Bark, and other models coming soon
- **API-first** — use the desktop app or integrate voice synthesis into your own projects
- **Native performance** — built with Tauri (Rust), not Electron
+- **Super fast on Mac** — MLX backend with native Metal acceleration for 4-5x faster inference on Apple Silicon
Download a voice model, clone any voice from a few seconds of audio, and compose multi-voice projects with studio-grade editing tools. No Python install required, no cloud dependency, no limits.
@@ -97,6 +98,7 @@ Powered by Alibaba's **Qwen3-TTS** — a breakthrough model that achieves near-p
- **Instant cloning** — Upload a sample, get a voice profile
- **High fidelity** — Natural prosody, emotion, and cadence
- **Multi-language** — English, Chinese, and more coming
+- **Lightning fast on Mac** — MLX backend leverages Apple Silicon's Neural Engine for super fast generation
### Voice Profile Management
diff --git a/app/src/components/VoiceProfiles/ProfileCard.tsx b/app/src/components/VoiceProfiles/ProfileCard.tsx
index ed46259b..e879294f 100644
--- a/app/src/components/VoiceProfiles/ProfileCard.tsx
+++ b/app/src/components/VoiceProfiles/ProfileCard.tsx
@@ -1,6 +1,5 @@
import { Download, Edit, Mic, Trash2 } from 'lucide-react';
import { useState } from 'react';
-import { useServerStore } from '@/stores/serverStore';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
@@ -16,6 +15,7 @@ import {
import type { VoiceProfileResponse } from '@/lib/api/types';
import { useDeleteProfile, useExportProfile } from '@/lib/hooks/useProfiles';
import { cn } from '@/lib/utils/cn';
+import { useServerStore } from '@/stores/serverStore';
import { useUIStore } from '@/stores/uiStore';
interface ProfileCardProps {
@@ -35,9 +35,7 @@ export function ProfileCard({ profile }: ProfileCardProps) {
const isSelected = selectedProfileId === profile.id;
- const avatarUrl = profile.avatar_path
- ? `${serverUrl}/profiles/${profile.id}/avatar`
- : null;
+ const avatarUrl = profile.avatar_path ? `${serverUrl}/profiles/${profile.id}/avatar` : null;
const handleSelect = () => {
setSelectedProfileId(isSelected ? null : profile.id);
@@ -81,7 +79,7 @@ export function ProfileCard({ profile }: ProfileCardProps) {
alt={`${profile.name} avatar`}
className={cn(
'h-full w-full object-cover transition-all duration-200',
- !isSelected && 'grayscale'
+ !isSelected && 'grayscale',
)}
onError={() => setAvatarError(true)}
/>
diff --git a/app/src/components/VoiceProfiles/ProfileForm.tsx b/app/src/components/VoiceProfiles/ProfileForm.tsx
index f7a84e15..90cc4fe0 100644
--- a/app/src/components/VoiceProfiles/ProfileForm.tsx
+++ b/app/src/components/VoiceProfiles/ProfileForm.tsx
@@ -45,8 +45,8 @@ import { useSystemAudioCapture } from '@/lib/hooks/useSystemAudioCapture';
import { useTranscription } from '@/lib/hooks/useTranscription';
import { isTauri } from '@/lib/tauri';
import { formatAudioDuration, getAudioDuration } from '@/lib/utils/audio';
-import { type ProfileFormDraft, useUIStore } from '@/stores/uiStore';
import { useServerStore } from '@/stores/serverStore';
+import { type ProfileFormDraft, useUIStore } from '@/stores/uiStore';
import { AudioSampleRecording } from './AudioSampleRecording';
import { AudioSampleSystem } from './AudioSampleSystem';
import { AudioSampleUpload } from './AudioSampleUpload';
@@ -427,7 +427,8 @@ export function ProfileForm() {
} catch (avatarError) {
toast({
title: 'Avatar upload failed',
- description: avatarError instanceof Error ? avatarError.message : 'Failed to upload avatar',
+ description:
+ avatarError instanceof Error ? avatarError.message : 'Failed to upload avatar',
variant: 'destructive',
});
}
@@ -520,7 +521,8 @@ export function ProfileForm() {
} catch (avatarError) {
toast({
title: 'Avatar upload failed',
- description: avatarError instanceof Error ? avatarError.message : 'Failed to upload avatar',
+ description:
+ avatarError instanceof Error ? avatarError.message : 'Failed to upload avatar',
variant: 'destructive',
});
}
diff --git a/backend/backends/mlx_backend.py b/backend/backends/mlx_backend.py
index 8eafc56e..7585c656 100644
--- a/backend/backends/mlx_backend.py
+++ b/backend/backends/mlx_backend.py
@@ -424,34 +424,35 @@ class MLXSTTBackend:
) -> str:
"""
Transcribe audio to text.
-
+
Args:
audio_path: Path to audio file
language: Optional language hint (en or zh)
-
+
Returns:
Transcribed text
"""
await self.load_model_async(None)
-
+
def _transcribe_sync():
"""Run synchronous transcription in thread pool."""
- # Load audio
- audio, sr = load_audio(audio_path, sample_rate=16000)
-
- # MLX Whisper transcription
- # The API may vary - check mlx-audio documentation
- # For now, assuming similar API to PyTorch Whisper
- result = self.model.transcribe(audio, language=language)
-
- # Extract text from result (format may vary)
+ # MLX Whisper transcription using generate method
+ # The generate method accepts audio path directly
+ decode_options = {}
+ if language:
+ decode_options["language"] = language
+
+ result = self.model.generate(str(audio_path), **decode_options)
+
+ # Extract text from result
if isinstance(result, str):
return result.strip()
elif isinstance(result, dict):
return result.get("text", "").strip()
+ elif hasattr(result, "text"):
+ return result.text.strip()
else:
- # Try to get text attribute
return str(result).strip()
-
+
# Run blocking transcription in thread pool
return await asyncio.to_thread(_transcribe_sync)
diff --git a/landing/src/app/page.tsx b/landing/src/app/page.tsx
index be4869f3..46cf3556 100644
--- a/landing/src/app/page.tsx
+++ b/landing/src/app/page.tsx
@@ -5,7 +5,7 @@ import Image from 'next/image';
import { useEffect, useState } from 'react';
import { AppleIcon, LinuxIcon, WindowsIcon } from '@/components/PlatformIcons';
import { Button } from '@/components/ui/button';
-import { Section, SectionTitle } from '@/components/ui/section';
+import { Section } from '@/components/ui/section';
import { DOWNLOAD_LINKS, GITHUB_REPO } from '@/lib/constants';
import type { DownloadLinks } from '@/lib/releases';
import { FeatureCard } from '../components/ui/feature-card';
@@ -39,17 +39,19 @@ export default function Home() {
"Powered by Alibaba's Qwen3-TTS model for exceptional voice quality and accuracy.",
icon: ,
},
+ {
+ title: 'Stories Editor',
+ description:
+ 'Create multi-voice narratives with a timeline-based editor. Arrange tracks, trim clips, and mix conversations.',
+ icon: ,
+ },
{
title: 'Multi-Sample Support',
description:
'Combine multiple voice samples for higher quality and more natural-sounding results.',
icon: ,
},
- {
- title: 'Smart Caching',
- description: 'Instant re-generation with voice prompt caching. No need to reprocess samples.',
- icon: ,
- },
+
{
title: 'Local or Remote',
description:
@@ -246,6 +248,10 @@ export default function Home() {
model, clone any voice from a few seconds of audio, and compose multi-voice projects
with studio-grade editing tools.
+
+ Optimized for performance with Metal acceleration on Mac and{' '}
+ CUDA acceleration on Windows/Linux for fast, local inference.
+
No Python install required.
@@ -281,10 +287,6 @@ export default function Home() {
{/* Features Section */}
- Features
-
- Everything you need for professional voice cloning in a desktop app.
-
{features.map((feature) => (
yF-%i_`)3sWy39~Q*Em(kgm^=B~
zK5ZSc#?h8}eRQVT(Ra;GKAKiN*UtM=N=`-Oj8x!(Y)qQ03p}$T6+uL@mf4Kh@Dp5R
zEK2Qo*m?K%&EfX?r-ADZ+yqQQ9j-wGuESI{aLw4rlV+9+#whRRXzf2+-9zEfQIy^|i{FVe4J{8er#$7S5h(&Ujb>4^O@_c+#4b2%c;iBe6n+6rD7txN0Ep7hW?4bX6^RNj6PYq;A#f6Ue5sguVg2Y?
zbdUF50KpD)fB^>q5)|m_c+XUSawn5X0au!wGNdfyv3IBpTVrU78l@CB-V?uE#
zeFI*>&WSNbD_Vat(f}veB8kE!B8zaud6tL>g=s}27l{$+tTu$6eVkG)qNXbQ
zjkj-J@2@R=?7Lpy4Z$$9;2Mm;br@~>uAN6}7knz#YLX-M=;J)Go?BvbmLitoqbZmB
zNY9HI^jU89>h`DBOG~ZdA`lflCsG(gf)|<~pL3_YXT@F4QC1gup7SoY=Z5Mexsn`%
z(`*BRkl{lLgcg%ab_sp#6+u#1aURr9?Zs9dyp@)hL~_WA$dDun!Wtr!4$7Gj1Mc+V
z4JH*RWrLuF-tKlA#$X&KU=pTa8agloH{d4Rf?1e@dAJQ{8H=z4cVHP-;4a*QRak@j
z@BkjdIy{2M@C2U1vu1bu`RQq`leV@fPqGq`NX0p^CF3thrUXw?VFee5ie6