import React, { useState, useCallback, useEffect, useRef } from 'react' import ModelSelector from './ModelSelector' import SeedRegionInfo from './SeedRegionInfo' import TaskTypeSelector from './TaskTypeSelector' import MusicGenParams from './MusicGenParams' import ACEStepParams from './ACEStepParams' import GenerationProgress from './GenerationProgress' import GenerationOutput from './GenerationOutput' // Map model+taskType to the param key used in the request function getTaskTypeKey(model) { if (model === 'ace-step') return 'task_type' return null } export default function GenerationPanel({ sessionId, detection, regionStart, regionEnd, hasRegion, onPlaySection, generation, // all state from useGeneration hook }) { const [isCollapsed, setIsCollapsed] = useState(false) const [isExtracting, setIsExtracting] = useState(false) const { selectedModel, setSelectedModel, modelParams, setModelParam, isGenerating, generationResult, generationProgress, modelAvailability, seedData, doExtractSeed, startGeneration, setGenerationResult, } = generation const currentParams = modelParams[selectedModel] || {} // Get the current task type for the selected model const taskTypeKey = getTaskTypeKey(selectedModel) const taskType = taskTypeKey ? currentParams[taskTypeKey] : 'continuation' const handleTaskTypeChange = useCallback((newType) => { if (taskTypeKey) { setModelParam(selectedModel, taskTypeKey, newType) } }, [selectedModel, taskTypeKey, setModelParam]) const handleParamChange = useCallback((key, value) => { setModelParam(selectedModel, key, value) }, [selectedModel, setModelParam]) // Auto-extract seed when region changes (debounced with longer delay) const regionRef = useRef({ start: regionStart, end: regionEnd }) useEffect(() => { regionRef.current = { start: regionStart, end: regionEnd } }, [regionStart, regionEnd]) useEffect(() => { if (!hasRegion || !sessionId) return if (regionEnd - regionStart < 3) return const timer = setTimeout(async () => { // Only extract if region hasn't changed during the delay if (regionRef.current.start === regionStart && regionRef.current.end === regionEnd) { setIsExtracting(true) await doExtractSeed(regionStart, regionEnd) setIsExtracting(false) } }, 1000) return () => clearTimeout(timer) // eslint-disable-next-line react-hooks/exhaustive-deps }, [regionStart, regionEnd, hasRegion, sessionId]) const handleGenerate = useCallback(async () => { if (!hasRegion) return await startGeneration(regionStart, regionEnd) }, [hasRegion, regionStart, regionEnd, startGeneration]) const handleRegenerate = useCallback(async () => { // Set a new random seed before regenerating if (selectedModel === 'musicgen') { setModelParam('musicgen', 'seed', Math.floor(Math.random() * 999999)) } else if (selectedModel === 'ace-step') { setModelParam('ace-step', 'seed', Math.floor(Math.random() * 999999)) } // Small delay for state to update setTimeout(() => handleGenerate(), 50) }, [selectedModel, setModelParam, handleGenerate]) const handleUseAsSource = useCallback(() => { // The generated continuation is already stored in the session. // Clear the current result so the user can generate again. setGenerationResult(null) }, [setGenerationResult]) const canGenerate = hasRegion && !isGenerating && (regionEnd - regionStart >= 3) return (
{/* Header */} {!isCollapsed && (
{/* Model selector tabs */} {/* Seed region info */} {/* Task type selector (per model) */} {/* Model-specific parameters */}
{selectedModel === 'musicgen' && ( )} {selectedModel === 'ace-step' && ( )}
{/* Generate button */} {/* Progress */} {/* Output */}
)}
) }