| import { useState, useCallback, useRef, useEffect } from 'react' |
|
|
| const DEFAULT_PARAMS = { |
| musicgen: { |
| prompt: '', |
| duration: 15, |
| seed: -1, |
| }, |
| 'ace-step': { |
| task_type: 'repaint', |
| caption: '', |
| lyrics: '[Instrumental]', |
| bpm: null, |
| duration: 30, |
| audio_cover_strength: 0.8, |
| model_variant: 'xl-turbo', |
| inference_steps: 15, |
| seed: -1, |
| scheduler: 'ode', |
| cfg_scale: null, |
| timestep_shift: null, |
| }, |
| } |
|
|
| export function useGeneration({ |
| sessionId, |
| generate, |
| extractSeed, |
| generateAceStep, |
| checkModels, |
| }) { |
| const [selectedModel, setSelectedModel] = useState('musicgen') |
| const [modelParams, setModelParams] = useState(() => JSON.parse(JSON.stringify(DEFAULT_PARAMS))) |
| const [isGenerating, setIsGenerating] = useState(false) |
| const [generationResult, setGenerationResult] = useState(null) |
| const [generationProgress, setGenerationProgress] = useState(null) |
| const [modelAvailability, setModelAvailability] = useState(null) |
| const [seedData, setSeedData] = useState(null) |
| const abortRef = useRef(null) |
|
|
| |
| useEffect(() => { |
| |
| setGenerationResult(null) |
| setSeedData(null) |
| setGenerationProgress(null) |
|
|
| if (checkModels) { |
| checkModels().then(data => { |
| if (data?.models) { |
| const avail = {} |
| data.models.forEach(m => { avail[m.name] = m }) |
| setModelAvailability(avail) |
| } |
| }) |
| } |
| }, [sessionId, checkModels]) |
|
|
| const setModelParam = useCallback((model, key, value) => { |
| setModelParams(prev => ({ |
| ...prev, |
| [model]: { ...prev[model], [key]: value }, |
| })) |
| }, []) |
|
|
| const resetParams = useCallback((model) => { |
| setModelParams(prev => ({ |
| ...prev, |
| [model]: JSON.parse(JSON.stringify(DEFAULT_PARAMS[model])), |
| })) |
| }, []) |
|
|
| |
| const doExtractSeed = useCallback(async (regionStart, regionEnd) => { |
| if (!extractSeed) return null |
| const result = await extractSeed(regionStart, regionEnd) |
| if (result) { |
| setSeedData(result) |
| |
| if (result.analysis?.bpm) { |
| setModelParams(prev => ({ |
| ...prev, |
| 'ace-step': { ...prev['ace-step'], bpm: result.analysis.bpm }, |
| })) |
| } |
| } |
| return result |
| }, [extractSeed]) |
|
|
| |
| const startGeneration = useCallback(async (regionStart, regionEnd) => { |
| setIsGenerating(true) |
| setGenerationResult(null) |
| setGenerationProgress({ status: 'starting' }) |
|
|
| try { |
| let result = null |
|
|
| if (selectedModel === 'musicgen') { |
| const params = modelParams.musicgen |
| result = await generate(regionStart, regionEnd, params.duration, params.prompt || null) |
| } else if (selectedModel === 'ace-step') { |
| if (!seedData?.seed_id) { |
| |
| const extracted = await doExtractSeed(regionStart, regionEnd) |
| if (!extracted) throw new Error('Failed to extract seed') |
| } |
| const params = { ...modelParams['ace-step'] } |
| params.seed_id = seedData.seed_id |
| result = await generateAceStep(params) |
| } |
|
|
| if (result) { |
| setGenerationResult({ ...result, model: selectedModel }) |
| setGenerationProgress({ status: 'done' }) |
| } else { |
| setGenerationProgress({ status: 'error' }) |
| } |
|
|
| return result |
| } catch (err) { |
| setGenerationProgress({ status: 'error', message: err.message }) |
| return null |
| } finally { |
| setIsGenerating(false) |
| } |
| }, [selectedModel, modelParams, seedData, generate, generateAceStep, doExtractSeed]) |
|
|
| const cancelGeneration = useCallback(() => { |
| if (abortRef.current) { |
| abortRef.current.abort() |
| abortRef.current = null |
| } |
| setIsGenerating(false) |
| setGenerationProgress(null) |
| }, []) |
|
|
| return { |
| selectedModel, |
| setSelectedModel, |
| modelParams, |
| setModelParam, |
| resetParams, |
| isGenerating, |
| generationResult, |
| setGenerationResult, |
| generationProgress, |
| modelAvailability, |
| seedData, |
| setSeedData, |
| doExtractSeed, |
| startGeneration, |
| cancelGeneration, |
| } |
| } |
|
|