""" Local MusicGen Provider — Windows AI 서버(MusicGen)를 통한 음악 생성 기존 _run_generation 로직을 그대로 분리. """ import os import time import logging import requests from .db import update_task, add_track logger = logging.getLogger(__name__) MUSIC_AI_SERVER_URL = os.getenv("MUSIC_AI_SERVER_URL", "") MUSIC_DATA_DIR = "/app/data" MUSIC_MEDIA_BASE = os.getenv("MUSIC_MEDIA_BASE", "/media/music") def run_local_generation(task_id: str, params: dict) -> None: """BackgroundTask: Windows AI 서버(MusicGen)에 생성 요청 → 파일 저장 → 라이브러리 등록""" try: update_task(task_id, "processing", 10, "AI 서버에 연결 중...") if not MUSIC_AI_SERVER_URL: update_task(task_id, "failed", 0, "", error="MUSIC_AI_SERVER_URL이 설정되지 않았습니다") return update_task(task_id, "processing", 30, "음악 생성 중... (수 분 소요될 수 있습니다)") # 1단계: 생성 요청 → ai_task_id 반환 resp = requests.post( f"{MUSIC_AI_SERVER_URL}/generate", json=params, 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초 간격) 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 = 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, "파일 저장 중...") filename = f"{task_id}.mp3" file_path = os.path.join(MUSIC_DATA_DIR, filename) # 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 = f"{MUSIC_MEDIA_BASE}/{filename}" # 라이브러리 자동 등록 genre = params.get("genre", "") moods = params.get("moods", []) mood_str = moods[0] if moods else "Original" title = params.get("title") or ( f"{genre} — {mood_str} Mix" if genre else f"{mood_str} Mix" ) add_track({ "title": title, "genre": genre, "moods": params.get("moods", []), "instruments": params.get("instruments", []), "duration_sec": params.get("duration_sec"), "bpm": params.get("bpm"), "key": params.get("key", ""), "scale": params.get("scale", ""), "prompt": params.get("prompt", ""), "audio_url": audio_url, "file_path": file_path, "task_id": task_id, "provider": "local", }) update_task(task_id, "succeeded", 100, "생성 완료", audio_url=audio_url) except requests.Timeout: update_task(task_id, "failed", 0, "", error="AI 서버 타임아웃 (10분 초과)") except Exception as e: logger.exception("Local generation error for task %s", task_id) update_task(task_id, "failed", 0, "", error=str(e))