From e3ed840d12b803ecf0633afe71ab6e613c1bc81a Mon Sep 17 00:00:00 2001 From: hbyang Date: Wed, 21 Jan 2026 16:19:58 +0900 Subject: [PATCH] =?UTF-8?q?db=20status=20=EC=A1=B0=ED=9A=8C=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/Dashboard/SoundStudioContent.tsx | 23 ++++---- src/types/api.ts | 18 +------ src/utils/api.ts | 61 +++++++++------------- 3 files changed, 37 insertions(+), 65 deletions(-) diff --git a/src/pages/Dashboard/SoundStudioContent.tsx b/src/pages/Dashboard/SoundStudioContent.tsx index 6b1a348..0670a59 100755 --- a/src/pages/Dashboard/SoundStudioContent.tsx +++ b/src/pages/Dashboard/SoundStudioContent.tsx @@ -22,7 +22,6 @@ type GenerationStatus = 'idle' | 'generating_lyric' | 'generating_song' | 'polli interface SavedGenerationState { taskId: string; - songId: string; lyrics: string; status: GenerationStatus; timestamp: number; @@ -71,10 +70,9 @@ const SoundStudioContent: React.FC = ({ const audioRef = useRef(null); const languageDropdownRef = useRef(null); - const saveToStorage = (taskId: string, songId: string, currentLyrics: string, currentStatus: GenerationStatus) => { + const saveToStorage = (taskId: string, currentLyrics: string, currentStatus: GenerationStatus) => { const data: SavedGenerationState = { taskId, - songId, lyrics: currentLyrics, status: currentStatus, timestamp: Date.now(), @@ -114,7 +112,7 @@ const SoundStudioContent: React.FC = ({ } setStatus('polling'); setStatusMessage('노래를 생성하고 있습니다... (새로고침 후 복구됨)'); - resumePolling(savedState.taskId, savedState.songId, savedState.lyrics, 0); + resumePolling(savedState.taskId, savedState.lyrics, 0); } }, []); @@ -146,16 +144,15 @@ const SoundStudioContent: React.FC = ({ } }, [videoGenerationStatus, songTaskId, onNext]); - const resumePolling = async (taskId: string, songId: string, currentLyrics: string, currentRetryCount: number = 0) => { + const resumePolling = async (taskId: string, currentLyrics: string, currentRetryCount: number = 0) => { try { const downloadResponse = await waitForSongComplete( taskId, - songId, (pollStatus: string) => { - if (pollStatus === 'pending') { - setStatusMessage('노래를 생성하고 있습니다...'); - } else if (pollStatus === 'processing') { + if (pollStatus === 'processing') { setStatusMessage('노래를 생성하고 있습니다...'); + } else if (pollStatus === 'uploading') { + setStatusMessage('노래를 업로드하고 있습니다...'); } } ); @@ -221,8 +218,8 @@ const SoundStudioContent: React.FC = ({ throw new Error(songResponse.error_message || '음악 생성 요청에 실패했습니다.'); } - saveToStorage(songResponse.task_id, songResponse.song_id, currentLyrics, 'polling'); - await resumePolling(songResponse.task_id, songResponse.song_id, currentLyrics, currentRetryCount); + saveToStorage(songResponse.task_id, currentLyrics, 'polling'); + await resumePolling(songResponse.task_id, currentLyrics, currentRetryCount); } catch (error) { console.error('Song regeneration failed:', error); @@ -396,9 +393,9 @@ const SoundStudioContent: React.FC = ({ setStatus('polling'); setStatusMessage('노래를 생성하고 있습니다...'); - saveToStorage(songResponse.task_id, songResponse.song_id, lyricDetailResponse.lyric_result, 'polling'); + saveToStorage(songResponse.task_id, lyricDetailResponse.lyric_result, 'polling'); - await resumePolling(songResponse.task_id, songResponse.song_id, lyricDetailResponse.lyric_result, 0); + await resumePolling(songResponse.task_id, lyricDetailResponse.lyric_result, 0); } catch (error) { console.error('Music generation failed:', error); diff --git a/src/types/api.ts b/src/types/api.ts index fa9fab3..7737e27 100644 --- a/src/types/api.ts +++ b/src/types/api.ts @@ -83,23 +83,7 @@ export interface SongGenerateResponse { error_message: string | null; } -// 노래 상태 확인 응답 -export interface SongStatusResponse { - success: boolean; - status: string; - message?: string; - clips?: Array<{ - id: string; - audio_url: string; - stream_audio_url: string; - image_url: string; - title: string; - status: string | null; - duration: number; - }>; -} - -// 노래 다운로드 응답 +// 노래 다운로드 상태 조회 응답 (DB Polling) export interface SongDownloadResponse { success: boolean; status: string; diff --git a/src/utils/api.ts b/src/utils/api.ts index f85b293..e1d17a8 100644 --- a/src/utils/api.ts +++ b/src/utils/api.ts @@ -6,7 +6,6 @@ import { LyricDetailResponse, SongGenerateRequest, SongGenerateResponse, - SongStatusResponse, SongDownloadResponse, VideoGenerateResponse, VideoStatusResponse, @@ -154,21 +153,9 @@ export async function generateSong(taskId: string, request: SongGenerateRequest) return response.json(); } -// 노래 상태 확인 API (song_id 사용) -export async function getSongStatus(songId: string): Promise { - const response = await fetch(`${API_URL}/song/status/${songId}`, { - method: 'GET', - }); - - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`); - } - - return response.json(); -} - -// 노래 다운로드 API -export async function downloadSong(taskId: string): Promise { +// 노래 다운로드 상태 조회 API (DB Polling) +// task_id를 기반으로 Song 테이블의 상태를 조회하고, completed인 경우 Project 정보와 노래 URL을 반환 +export async function getSongDownloadStatus(taskId: string): Promise { const response = await fetch(`${API_URL}/song/download/${taskId}`, { method: 'GET', }); @@ -180,40 +167,44 @@ export async function downloadSong(taskId: string): Promise void ): Promise { const startTime = Date.now(); - // 재귀적으로 폴링하는 방식으로 변경 (async/await 제대로 동작) const poll = async (): Promise => { - // 2분 타임아웃 체크 - if (Date.now() - startTime > POLL_TIMEOUT) { + // 5분 타임아웃 체크 + if (Date.now() - startTime > SONG_POLL_TIMEOUT) { throw new Error('TIMEOUT'); } try { - // 상태 확인은 song_id 사용 - const statusResponse = await getSongStatus(songId); - onStatusChange?.(statusResponse.status); + const response = await getSongDownloadStatus(taskId); + onStatusChange?.(response.status); - // status가 "SUCCESS" (대문자)인 경우 완료 - if (statusResponse.status === 'SUCCESS' && statusResponse.success) { - // 다운로드는 task_id 사용 - const downloadResponse = await downloadSong(taskId); - return downloadResponse; - } else if (statusResponse.status === 'FAILED' || statusResponse.status === 'failed') { - throw new Error('Song generation failed'); + // completed: 모든 작업 완료, Blob URL 사용 가능 + if (response.status === 'completed' && response.success) { + return response; } - // PENDING, PROCESSING 등은 대기 후 재시도 - await new Promise(resolve => setTimeout(resolve, POLL_INTERVAL)); + // failed: 노래 생성 또는 업로드 실패 + if (response.status === 'failed' || response.status === 'error') { + throw new Error(response.error_message || '노래 생성에 실패했습니다.'); + } + + // not_found: task_id에 해당하는 Song 없음 + if (response.status === 'not_found') { + throw new Error('노래를 찾을 수 없습니다.'); + } + + // processing, uploading 등은 대기 후 재시도 + await new Promise(resolve => setTimeout(resolve, SONG_POLL_INTERVAL)); return poll(); } catch (error) { throw error;