Spaces:
Sleeping
Sleeping
Download frontend/src/components/generation/GenerationPanel.jsx from MusoraProductDepartment/jam-tracks: direct link, hf CLI and curl.
- Browser
- Download file 6.55 kB
-
https://huggingface.co/spaces/MusoraProductDepartment/jam-tracks/resolve/main/frontend/src/components/generation/GenerationPanel.jsx
- Command line
-
hf download hf://spaces/MusoraProductDepartment/jam-tracks/frontend/src/components/generation/GenerationPanel.jsx
-
curl -L -o GenerationPanel.jsx https://huggingface.co/spaces/MusoraProductDepartment/jam-tracks/resolve/main/frontend/src/components/generation/GenerationPanel.jsx
6.55 kB
| 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 ( | |
| <div className="card rounded-xl p-4 animate-fade-in"> | |
| {/* Header */} | |
| <button | |
| onClick={() => setIsCollapsed(!isCollapsed)} | |
| className="w-full flex items-center justify-between mb-3" | |
| > | |
| <div className="flex items-center gap-2"> | |
| <span className="text-[10px] uppercase tracking-widest text-accent-500 font-medium"> | |
| AI Generation | |
| </span> | |
| </div> | |
| <span className={`text-gray-500 text-xs transition-transform ${isCollapsed ? '' : 'rotate-180'}`}> | |
| ▼ | |
| </span> | |
| </button> | |
| {!isCollapsed && ( | |
| <div className="space-y-4"> | |
| {/* Model selector tabs */} | |
| <ModelSelector | |
| selectedModel={selectedModel} | |
| onModelChange={setSelectedModel} | |
| availability={modelAvailability} | |
| /> | |
| {/* Seed region info */} | |
| <SeedRegionInfo | |
| seedData={seedData} | |
| regionStart={regionStart} | |
| regionEnd={regionEnd} | |
| hasRegion={hasRegion} | |
| onPreviewRegion={onPlaySection} | |
| isExtracting={isExtracting} | |
| /> | |
| {/* Task type selector (per model) */} | |
| <TaskTypeSelector | |
| model={selectedModel} | |
| taskType={taskType} | |
| onTaskTypeChange={handleTaskTypeChange} | |
| /> | |
| {/* Model-specific parameters */} | |
| <div className="transition-all"> | |
| {selectedModel === 'musicgen' && ( | |
| <MusicGenParams | |
| params={currentParams} | |
| onParamChange={handleParamChange} | |
| /> | |
| )} | |
| {selectedModel === 'ace-step' && ( | |
| <ACEStepParams | |
| params={currentParams} | |
| onParamChange={handleParamChange} | |
| detection={detection} | |
| /> | |
| )} | |
| </div> | |
| {/* Generate button */} | |
| <button | |
| onClick={handleGenerate} | |
| disabled={!canGenerate} | |
| className={`w-full py-2.5 rounded-lg text-sm font-medium transition-all ${ | |
| canGenerate | |
| ? 'bg-accent-500 hover:bg-accent-400 text-white' | |
| : 'bg-white/[0.04] text-gray-600 cursor-not-allowed' | |
| }`} | |
| > | |
| {isGenerating | |
| ? 'Generating...' | |
| : `\u25B6 Generate with ${selectedModel === 'musicgen' ? 'MusicGen' : 'ACE-Step'}` | |
| } | |
| </button> | |
| {/* Progress */} | |
| <GenerationProgress | |
| model={selectedModel} | |
| progress={generationProgress} | |
| isGenerating={isGenerating} | |
| /> | |
| {/* Output */} | |
| <GenerationOutput | |
| sessionId={sessionId} | |
| generationResult={generationResult} | |
| onRegenerate={handleRegenerate} | |
| onUseAsSource={handleUseAsSource} | |
| onPlaySection={onPlaySection} | |
| /> | |
| </div> | |
| )} | |
| </div> | |
| ) | |
| } | |