jam-tracks / frontend /src /hooks /useSession.js
Mina Emadi
added the music generation functionality
59dcfdf
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
}
}