diff --git a/music-lab/app/main.py b/music-lab/app/main.py index 5118319..e36a1a8 100644 --- a/music-lab/app/main.py +++ b/music-lab/app/main.py @@ -1,4 +1,5 @@ import os +import time import uuid import requests from typing import List, Optional @@ -51,40 +52,57 @@ def _run_generation(task_id: str, params: dict) -> None: update_task(task_id, "processing", 30, "음악 생성 중... (수 분 소요될 수 있습니다)") + # 1단계: 생성 요청 → ai_task_id 반환 resp = requests.post( f"{MUSIC_AI_SERVER_URL}/generate", json=params, - timeout=600, # 10분 - stream=True, + timeout=30, ) if resp.status_code != 200: update_task(task_id, "failed", 0, "", error=f"AI 서버 오류: {resp.status_code} {resp.text[:200]}") return + ai_task_id = resp.json().get("task_id") + if not ai_task_id: + update_task(task_id, "failed", 0, "", error="AI 서버 응답에 task_id가 없습니다") + return + + # 2단계: 상태 폴링 (최대 10분, 5초 간격) — AI 서버 progress/message 그대로 반영 + remote_url = None + for _ in range(120): + time.sleep(5) + status_resp = requests.get(f"{MUSIC_AI_SERVER_URL}/status/{ai_task_id}", timeout=10) + status_data = status_resp.json() + ai_status = status_data.get("status") + + # AI 서버의 progress/message를 로컬 task에 전달 (30~79 범위로 스케일) + ai_progress = status_data.get("progress", 0) + ai_message = status_data.get("message", "음악 생성 중...") + scaled = 30 + int(ai_progress * 0.49) # 30% ~ 79% + update_task(task_id, "processing", scaled, ai_message) + + if ai_status == "succeeded": + remote_url = status_data.get("audio_url") + break + elif ai_status == "failed": + update_task(task_id, "failed", 0, "", error=status_data.get("error", "AI 서버 생성 실패")) + return + + if not remote_url: + update_task(task_id, "failed", 0, "", error="AI 서버 타임아웃 (10분 초과)") + return + update_task(task_id, "processing", 80, "파일 저장 중...") - # AI 서버 응답: binary audio 또는 JSON {"audio_url": "..."} - content_type = resp.headers.get("content-type", "") filename = f"{task_id}.mp3" file_path = os.path.join(MUSIC_DATA_DIR, filename) - if "application/json" in content_type: - result = resp.json() - remote_url = result.get("audio_url") or result.get("url") - if not remote_url: - update_task(task_id, "failed", 0, "", error="AI 서버 응답에 audio_url이 없습니다") - return - # 원격 URL에서 파일 다운로드 - dl = requests.get(remote_url, timeout=120, stream=True) - with open(file_path, "wb") as f: - for chunk in dl.iter_content(chunk_size=8192): - f.write(chunk) - else: - # binary audio 직접 저장 - with open(file_path, "wb") as f: - for chunk in resp.iter_content(chunk_size=8192): - f.write(chunk) + # 3단계: 오디오 파일 다운로드 + dl = requests.get(remote_url, timeout=120, stream=True) + with open(file_path, "wb") as f: + for chunk in dl.iter_content(chunk_size=8192): + f.write(chunk) # audio_url은 항상 Nginx 상대경로 (Mixed Content 방지) audio_url = f"/media/music/{filename}"