Spaces:
Sleeping
Sleeping
| import { useState, useCallback } from 'react' | |
| export function useSession() { | |
| const [sessionId, setSessionId] = useState(null) | |
| const [stems, setStems] = useState([]) | |
| const [detection, setDetection] = useState(null) | |
| const [chordsData, setChordsData] = useState(null) | |
| const [loading, setLoading] = useState(false) | |
| const [error, setError] = useState(null) | |
| const clearError = useCallback(() => { | |
| setError(null) | |
| }, []) | |
| // Upload files and automatically run detection | |
| const upload = useCallback(async (formData) => { | |
| setLoading(true) | |
| setError(null) | |
| try { | |
| // Step 1: Upload files (formData already prepared by FileUpload component) | |
| const uploadResponse = await fetch('/api/upload', { | |
| method: 'POST', | |
| body: formData | |
| }) | |
| if (!uploadResponse.ok) { | |
| const data = await uploadResponse.json().catch(() => ({})) | |
| throw new Error(data.detail || `Upload failed: ${uploadResponse.status}`) | |
| } | |
| const uploadData = await uploadResponse.json() | |
| console.log('Upload response:', uploadData) | |
| setSessionId(uploadData.session_id) | |
| setStems(uploadData.stems) | |
| // Step 2: Automatically run detection with the session_id we just got | |
| const detectResponse = await fetch(`/api/detect/${uploadData.session_id}`, { | |
| method: 'POST' | |
| }) | |
| if (!detectResponse.ok) { | |
| const data = await detectResponse.json().catch(() => ({})) | |
| throw new Error(data.detail || `Detection failed: ${detectResponse.status}`) | |
| } | |
| const detectData = await detectResponse.json() | |
| console.log('Detection response:', detectData) | |
| setDetection(detectData) | |
| // Auto-fetch chord progression and scale suggestions | |
| fetch(`/api/chords/${uploadData.session_id}`) | |
| .then(r => r.ok ? r.json() : null) | |
| .then(data => { if (data) setChordsData(data) }) | |
| .catch(() => {}) | |
| return { upload: uploadData, detection: detectData } | |
| } catch (err) { | |
| console.error('Error:', err) | |
| setError(err.message) | |
| return null | |
| } finally { | |
| setLoading(false) | |
| } | |
| }, []) | |
| // Manual detect (if needed separately) | |
| const detect = useCallback(async (sid = null) => { | |
| const id = sid || sessionId | |
| if (!id) { | |
| setError('No session to detect') | |
| return null | |
| } | |
| setLoading(true) | |
| setError(null) | |
| try { | |
| const response = await fetch(`/api/detect/${id}`, { | |
| method: 'POST' | |
| }) | |
| if (!response.ok) { | |
| const data = await response.json().catch(() => ({})) | |
| throw new Error(data.detail || `Detection failed: ${response.status}`) | |
| } | |
| const data = await response.json() | |
| setDetection(data) | |
| return data | |
| } catch (err) { | |
| setError(err.message) | |
| return null | |
| } finally { | |
| setLoading(false) | |
| } | |
| }, [sessionId]) | |
| const process = useCallback(async (semitones, targetBpm = null, regionStart = null, regionEnd = null) => { | |
| if (!sessionId) { | |
| setError('No session to process') | |
| return null | |
| } | |
| setLoading(true) | |
| setError(null) | |
| try { | |
| const body = { semitones, target_bpm: targetBpm } | |
| if (regionStart !== null && regionEnd !== null) { | |
| body.region_start = regionStart | |
| body.region_end = regionEnd | |
| } | |
| const response = await fetch(`/api/process/${sessionId}`, { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json' | |
| }, | |
| body: JSON.stringify(body) | |
| }) | |
| if (!response.ok) { | |
| const data = await response.json().catch(() => ({})) | |
| throw new Error(data.detail || `Processing failed: ${response.status}`) | |
| } | |
| const data = await response.json() | |
| return data | |
| } catch (err) { | |
| setError(err.message) | |
| return null | |
| } finally { | |
| setLoading(false) | |
| } | |
| }, [sessionId]) | |
| const getStems = useCallback(async () => { | |
| if (!sessionId) return null | |
| try { | |
| const response = await fetch(`/api/stems/${sessionId}`) | |
| if (!response.ok) { | |
| throw new Error('Failed to get stems') | |
| } | |
| const data = await response.json() | |
| return data | |
| } catch (err) { | |
| setError(err.message) | |
| return null | |
| } | |
| }, [sessionId]) | |
| const loadPreset = useCallback(async (presetName) => { | |
| setLoading(true) | |
| setError(null) | |
| try { | |
| const uploadResponse = await fetch(`/api/preset/${presetName}`, { method: 'POST' }) | |
| if (!uploadResponse.ok) { | |
| const data = await uploadResponse.json().catch(() => ({})) | |
| throw new Error(data.detail || `Failed to load preset: ${uploadResponse.status}`) | |
| } | |
| const uploadData = await uploadResponse.json() | |
| setSessionId(uploadData.session_id) | |
| setStems(uploadData.stems) | |
| const detectResponse = await fetch(`/api/detect/${uploadData.session_id}`, { method: 'POST' }) | |
| if (!detectResponse.ok) { | |
| const data = await detectResponse.json().catch(() => ({})) | |
| throw new Error(data.detail || `Detection failed: ${detectResponse.status}`) | |
| } | |
| const detectData = await detectResponse.json() | |
| setDetection(detectData) | |
| // Auto-fetch chord progression and scale suggestions | |
| fetch(`/api/chords/${uploadData.session_id}`) | |
| .then(r => r.ok ? r.json() : null) | |
| .then(data => { if (data) setChordsData(data) }) | |
| .catch(() => {}) | |
| return { upload: uploadData, detection: detectData } | |
| } catch (err) { | |
| setError(err.message) | |
| return null | |
| } finally { | |
| setLoading(false) | |
| } | |
| }, []) | |
| const fetchChords = useCallback(async (sid = null) => { | |
| const id = sid || sessionId | |
| if (!id) return null | |
| try { | |
| const response = await fetch(`/api/chords/${id}`) | |
| if (response.ok) { | |
| const data = await response.json() | |
| setChordsData(data) | |
| return data | |
| } | |
| } catch (err) { | |
| console.warn('Chord detection failed:', err.message) | |
| } | |
| return null | |
| }, [sessionId]) | |
| const generate = useCallback(async (regionStart, regionEnd, duration = 15.0, prompt = null) => { | |
| if (!sessionId) { | |
| setError('No session to generate') | |
| return null | |
| } | |
| setLoading(true) | |
| setError(null) | |
| try { | |
| const body = { region_start: regionStart, region_end: regionEnd, duration } | |
| if (prompt) { | |
| body.prompt = prompt | |
| } | |
| const response = await fetch(`/api/generate/${sessionId}`, { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json' | |
| }, | |
| body: JSON.stringify(body) | |
| }) | |
| if (!response.ok) { | |
| const data = await response.json().catch(() => ({})) | |
| throw new Error(data.detail || `Generation failed: ${response.status}`) | |
| } | |
| const data = await response.json() | |
| return data | |
| } catch (err) { | |
| setError(err.message) | |
| return null | |
| } finally { | |
| setLoading(false) | |
| } | |
| }, [sessionId]) | |
| // Extract and analyze a seed from a selected region | |
| const extractSeed = useCallback(async (regionStart, regionEnd) => { | |
| if (!sessionId) { | |
| setError('No session') | |
| return null | |
| } | |
| try { | |
| const response = await fetch('/api/seed/extract', { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify({ | |
| session_id: sessionId, | |
| start_time: regionStart, | |
| end_time: regionEnd, | |
| }), | |
| }) | |
| if (!response.ok) { | |
| const data = await response.json().catch(() => ({})) | |
| throw new Error(data.detail || `Seed extraction failed: ${response.status}`) | |
| } | |
| return await response.json() | |
| } catch (err) { | |
| setError(err.message) | |
| return null | |
| } | |
| }, [sessionId]) | |
| // Generate with ACE-Step | |
| const generateAceStep = useCallback(async (params) => { | |
| if (!sessionId) { | |
| setError('No session') | |
| return null | |
| } | |
| setLoading(true) | |
| setError(null) | |
| try { | |
| const response = await fetch('/api/generate/acestep', { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify({ session_id: sessionId, ...params }), | |
| }) | |
| if (!response.ok) { | |
| const data = await response.json().catch(() => ({})) | |
| throw new Error(data.detail || `ACE-Step generation failed: ${response.status}`) | |
| } | |
| return await response.json() | |
| } catch (err) { | |
| setError(err.message) | |
| return null | |
| } finally { | |
| setLoading(false) | |
| } | |
| }, [sessionId]) | |
| // Check available models | |
| const checkModels = useCallback(async () => { | |
| try { | |
| const response = await fetch('/api/models') | |
| if (response.ok) return await response.json() | |
| } catch (err) { | |
| console.warn('Model check failed:', err.message) | |
| } | |
| return null | |
| }, []) | |
| return { | |
| sessionId, | |
| stems, | |
| detection, | |
| chordsData, | |
| loading, | |
| error, | |
| upload, | |
| detect, | |
| process, | |
| generate, | |
| extractSeed, | |
| generateAceStep, | |
| checkModels, | |
| fetchChords, | |
| getStems, | |
| loadPreset, | |
| clearError | |
| } | |
| } | |