mirror of
https://github.com/jamiepine/voicebox.git
synced 2026-09-18 22:30:40 -07:00
feat: async generation queue with serial execution
Generations now return immediately with a 'generating' status and appear
in history right away. TTS runs in a serial background queue to avoid
GPU contention. Users can kick off multiple generations without blocking.
- Async POST /generate creates DB record immediately, queues TTS work
- Serial generation queue prevents concurrent GPU access (Metal/CUDA/CPU)
- SSE endpoint GET /generate/{id}/status for real-time completion tracking
- Retry endpoint POST /generate/{id}/retry for failed generations
- Store engine and model_size on generation records for retry support
- History cards show animated loader (react-loaders) for generating/playing
- Failed generations show retry button instead of actions menu
- Model downloads happen inline in the queue instead of rejecting with 202
- Stale 'generating' records marked as failed on server startup
- Autoplay on generate setting (default: on)
- Show engine name on generation cards
- Remove sidebar generation spinner
- Checkbox alignment fix in settings
This commit is contained in:
@@ -124,6 +124,7 @@ export function ConnectionForm() {
|
||||
<div className="flex items-start space-x-3">
|
||||
<Checkbox
|
||||
id="keepServerRunning"
|
||||
className="mt-[6px]"
|
||||
checked={keepServerRunningOnClose}
|
||||
onCheckedChange={(checked: boolean) => {
|
||||
setKeepServerRunningOnClose(checked);
|
||||
@@ -158,6 +159,7 @@ export function ConnectionForm() {
|
||||
<div className="flex items-start space-x-3">
|
||||
<Checkbox
|
||||
id="allowNetworkAccess"
|
||||
className="mt-[6px]"
|
||||
checked={mode === 'remote'}
|
||||
onCheckedChange={(checked: boolean) => {
|
||||
setMode(checked ? 'remote' : 'local');
|
||||
|
||||
@@ -10,6 +10,8 @@ export function GenerationSettings() {
|
||||
const setCrossfadeMs = useServerStore((state) => state.setCrossfadeMs);
|
||||
const normalizeAudio = useServerStore((state) => state.normalizeAudio);
|
||||
const setNormalizeAudio = useServerStore((state) => state.setNormalizeAudio);
|
||||
const autoplayOnGenerate = useServerStore((state) => state.autoplayOnGenerate);
|
||||
const setAutoplayOnGenerate = useServerStore((state) => state.setAutoplayOnGenerate);
|
||||
|
||||
return (
|
||||
<Card role="region" aria-label="Generation Settings" tabIndex={0}>
|
||||
@@ -35,7 +37,7 @@ export function GenerationSettings() {
|
||||
value={[maxChunkChars]}
|
||||
onValueChange={([value]) => setMaxChunkChars(value)}
|
||||
min={100}
|
||||
max={2000}
|
||||
max={5000}
|
||||
step={50}
|
||||
aria-label="Auto-chunking character limit"
|
||||
/>
|
||||
@@ -73,6 +75,7 @@ export function GenerationSettings() {
|
||||
id="normalizeAudio"
|
||||
checked={normalizeAudio}
|
||||
onCheckedChange={setNormalizeAudio}
|
||||
className="mt-[6px]"
|
||||
/>
|
||||
<div className="space-y-1">
|
||||
<label
|
||||
@@ -86,6 +89,26 @@ export function GenerationSettings() {
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-start gap-3">
|
||||
<Checkbox
|
||||
id="autoplayOnGenerate"
|
||||
checked={autoplayOnGenerate}
|
||||
onCheckedChange={setAutoplayOnGenerate}
|
||||
className="mt-[6px]"
|
||||
/>
|
||||
<div className="space-y-1">
|
||||
<label
|
||||
htmlFor="autoplayOnGenerate"
|
||||
className="text-sm font-medium leading-none cursor-pointer"
|
||||
>
|
||||
Autoplay on generate
|
||||
</label>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Automatically play audio when a generation completes.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
Reference in New Issue
Block a user