"""Local MusicGen Provider — Windows AI 머신의 native MusicGen 서버(:8765) 호출. NAS music-lab/app/local_provider.py 이식. DB 호출만 webhook으로 변환. """ from __future__ import annotations import logging import os import time import requests from nas_client import webhook_update_task, webhook_add_track logger = logging.getLogger(__name__) MUSIC_AI_SERVER_URL = os.getenv("MUSIC_AI_SERVER_URL", "") MUSIC_MEDIA_ROOT = os.getenv("MUSIC_MEDIA_ROOT", "/mnt/nas/webpage/data/music") MUSIC_MEDIA_BASE = os.getenv("MUSIC_MEDIA_URL_PREFIX", "/media/music") def run_local_generation(task_id: str, params: dict) -> None: """MusicGen 생성 → /mnt/nas/.../music/{task_id}.mp3 저장 → add_track.""" try: webhook_update_task(task_id, "processing", 10, "AI 서버에 연결 중...") if not MUSIC_AI_SERVER_URL: webhook_update_task(task_id, "failed", 0, "", error="MUSIC_AI_SERVER_URL 미설정") return webhook_update_task(task_id, "processing", 30, "음악 생성 중...") resp = requests.post(f"{MUSIC_AI_SERVER_URL}/generate", json=params, timeout=30) if resp.status_code != 200: webhook_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: webhook_update_task(task_id, "failed", 0, "", error="AI 서버 응답에 task_id 없음") return remote_url = None for _ in range(120): time.sleep(5) sr = requests.get(f"{MUSIC_AI_SERVER_URL}/status/{ai_task_id}", timeout=10) sd = sr.json() st = sd.get("status") prog = sd.get("progress", 0) msg = sd.get("message", "음악 생성 중...") scaled = 30 + int(prog * 0.49) webhook_update_task(task_id, "processing", scaled, msg) if st == "succeeded": remote_url = sd.get("audio_url") break elif st == "failed": webhook_update_task(task_id, "failed", 0, "", error=sd.get("error", "AI 서버 생성 실패")) return if not remote_url: webhook_update_task(task_id, "failed", 0, "", error="AI 서버 타임아웃 (10분)") return webhook_update_task(task_id, "processing", 80, "파일 저장 중...") filename = f"{task_id}.mp3" os.makedirs(MUSIC_MEDIA_ROOT, exist_ok=True) file_path = os.path.join(MUSIC_MEDIA_ROOT, filename) dl = requests.get(remote_url, timeout=120, stream=True) dl.raise_for_status() 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" ) track = { "title": title, "genre": genre, "moods": 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": f"/app/data/{filename}", "task_id": task_id, "provider": "local", } webhook_add_track(task_id, "succeeded", 100, "생성 완료", audio_url=audio_url, track=track) except requests.Timeout: webhook_update_task(task_id, "failed", 0, "", error="AI 서버 타임아웃") except Exception as e: logger.exception("local generation error task=%s", task_id) webhook_update_task(task_id, "failed", 0, "", error=str(e))