mirror of
https://github.com/jamiepine/voicebox.git
synced 2026-09-29 15:15:27 -07:00
Fix player not loading new version after applying effects
Reload the player with the version-specific audio URL when effects are applied to the currently playing generation. Also consolidate the instruct/effects buttons into a single button with the effects editor shown inline when instruct mode is open.
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
import { useMatchRoute } from '@tanstack/react-router';
|
import { useMatchRoute } from '@tanstack/react-router';
|
||||||
import { AnimatePresence, motion } from 'framer-motion';
|
import { AnimatePresence, motion } from 'framer-motion';
|
||||||
import { Loader2, SlidersHorizontal, Sparkles, Wand2 } from 'lucide-react';
|
import { Loader2, SlidersHorizontal, Sparkles } from 'lucide-react';
|
||||||
import { useEffect, useRef, useState } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
import { EffectsChainEditor } from '@/components/Effects/EffectsChainEditor';
|
import { EffectsChainEditor } from '@/components/Effects/EffectsChainEditor';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
@@ -39,7 +39,6 @@ export function FloatingGenerateBox({
|
|||||||
const { data: profiles } = useProfiles();
|
const { data: profiles } = useProfiles();
|
||||||
const [isExpanded, setIsExpanded] = useState(false);
|
const [isExpanded, setIsExpanded] = useState(false);
|
||||||
const [isInstructMode, setIsInstructMode] = useState(false);
|
const [isInstructMode, setIsInstructMode] = useState(false);
|
||||||
const [isEffectsMode, setIsEffectsMode] = useState(false);
|
|
||||||
const [effectsChain, setEffectsChain] = useState<EffectConfig[]>([]);
|
const [effectsChain, setEffectsChain] = useState<EffectConfig[]>([]);
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
const textareaRef = useRef<HTMLTextAreaElement | null>(null);
|
const textareaRef = useRef<HTMLTextAreaElement | null>(null);
|
||||||
@@ -360,7 +359,9 @@ export function FloatingGenerateBox({
|
|||||||
'h-10 w-10 rounded-full transition-all duration-200',
|
'h-10 w-10 rounded-full transition-all duration-200',
|
||||||
isInstructMode
|
isInstructMode
|
||||||
? 'bg-accent text-accent-foreground border border-accent hover:bg-accent/90'
|
? 'bg-accent text-accent-foreground border border-accent hover:bg-accent/90'
|
||||||
: 'bg-card border border-border hover:bg-background/50',
|
: effectsChain.length > 0
|
||||||
|
? 'bg-accent/50 text-accent-foreground border border-accent/50 hover:bg-accent/70'
|
||||||
|
: 'bg-card border border-border hover:bg-background/50',
|
||||||
)}
|
)}
|
||||||
aria-label={
|
aria-label={
|
||||||
isInstructMode ? 'Fine tune instructions, on' : 'Fine tune instructions'
|
isInstructMode ? 'Fine tune instructions, on' : 'Fine tune instructions'
|
||||||
@@ -369,47 +370,7 @@ export function FloatingGenerateBox({
|
|||||||
<SlidersHorizontal className="h-4 w-4" />
|
<SlidersHorizontal className="h-4 w-4" />
|
||||||
</Button>
|
</Button>
|
||||||
<span className="pointer-events-none absolute bottom-full left-1/2 -translate-x-1/2 mb-2 whitespace-nowrap rounded-md bg-popover px-3 py-1.5 text-xs text-popover-foreground border border-border opacity-0 transition-opacity group-hover:opacity-100 z-[9999]">
|
<span className="pointer-events-none absolute bottom-full left-1/2 -translate-x-1/2 mb-2 whitespace-nowrap rounded-md bg-popover px-3 py-1.5 text-xs text-popover-foreground border border-border opacity-0 transition-opacity group-hover:opacity-100 z-[9999]">
|
||||||
Fine tune instructions
|
Fine tune instructions & effects
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</motion.div>
|
|
||||||
)}
|
|
||||||
{isExpanded && (
|
|
||||||
<motion.div
|
|
||||||
initial={{ opacity: 0, scale: 0.8 }}
|
|
||||||
animate={{ opacity: 1, scale: 1 }}
|
|
||||||
exit={{ opacity: 0, scale: 0.8 }}
|
|
||||||
transition={{ duration: 0.2 }}
|
|
||||||
className={cn(
|
|
||||||
'absolute top-0',
|
|
||||||
form.watch('engine') === 'qwen'
|
|
||||||
? 'right-[calc(100%+3.5rem)]'
|
|
||||||
: 'right-[calc(100%+0.5rem)]',
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<div className="group relative">
|
|
||||||
<Button
|
|
||||||
type="button"
|
|
||||||
variant="ghost"
|
|
||||||
size="icon"
|
|
||||||
onClick={() => {
|
|
||||||
const next = !isEffectsMode;
|
|
||||||
setIsEffectsMode(next);
|
|
||||||
if (next) setIsInstructMode(false);
|
|
||||||
}}
|
|
||||||
className={cn(
|
|
||||||
'h-10 w-10 rounded-full transition-all duration-200',
|
|
||||||
isEffectsMode || effectsChain.length > 0
|
|
||||||
? 'bg-accent text-accent-foreground border border-accent hover:bg-accent/90'
|
|
||||||
: 'bg-card border border-border hover:bg-background/50',
|
|
||||||
)}
|
|
||||||
aria-label={isEffectsMode ? 'Effects, on' : 'Post-processing effects'}
|
|
||||||
>
|
|
||||||
<Wand2 className="h-4 w-4" />
|
|
||||||
</Button>
|
|
||||||
<span className="pointer-events-none absolute bottom-full left-1/2 -translate-x-1/2 mb-2 whitespace-nowrap rounded-md bg-popover px-3 py-1.5 text-xs text-popover-foreground border border-border opacity-0 transition-opacity group-hover:opacity-100 z-[9999]">
|
|
||||||
Post-processing effects
|
|
||||||
{effectsChain.length > 0 && ` (${effectsChain.length} active)`}
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
@@ -418,9 +379,9 @@ export function FloatingGenerateBox({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Effects chain editor panel */}
|
{/* Effects chain editor panel - shown alongside instruct */}
|
||||||
<AnimatePresence>
|
<AnimatePresence>
|
||||||
{isExpanded && isEffectsMode && (
|
{isExpanded && isInstructMode && (
|
||||||
<motion.div
|
<motion.div
|
||||||
initial={{ height: 0, opacity: 0 }}
|
initial={{ height: 0, opacity: 0 }}
|
||||||
animate={{ height: 'auto', opacity: 1 }}
|
animate={{ height: 'auto', opacity: 1 }}
|
||||||
|
|||||||
@@ -234,11 +234,26 @@ export function HistoryTable() {
|
|||||||
if (!effectsTargetId || effectsChain.length === 0) return;
|
if (!effectsTargetId || effectsChain.length === 0) return;
|
||||||
setApplyingEffects(true);
|
setApplyingEffects(true);
|
||||||
try {
|
try {
|
||||||
await apiClient.applyEffectsToGeneration(effectsTargetId, {
|
const newVersion = await apiClient.applyEffectsToGeneration(effectsTargetId, {
|
||||||
effects_chain: effectsChain,
|
effects_chain: effectsChain,
|
||||||
set_as_default: true,
|
set_as_default: true,
|
||||||
});
|
});
|
||||||
queryClient.invalidateQueries({ queryKey: ['history'] });
|
queryClient.invalidateQueries({ queryKey: ['history'] });
|
||||||
|
|
||||||
|
// If the player is currently on this generation, reload with the new version audio
|
||||||
|
if (currentAudioId === effectsTargetId) {
|
||||||
|
const gen = allHistory.find((g) => g.id === effectsTargetId);
|
||||||
|
if (gen) {
|
||||||
|
const versionUrl = apiClient.getVersionAudioUrl(newVersion.id);
|
||||||
|
setAudioWithAutoPlay(
|
||||||
|
versionUrl,
|
||||||
|
effectsTargetId,
|
||||||
|
gen.profile_id,
|
||||||
|
gen.text.substring(0, 50),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setEffectsDialogOpen(false);
|
setEffectsDialogOpen(false);
|
||||||
toast({ title: 'Effects applied', description: 'A new version has been created.' });
|
toast({ title: 'Effects applied', description: 'A new version has been created.' });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
Reference in New Issue
Block a user