From f1e72e282979e97bd6f50e36720f65e6fffb0757 Mon Sep 17 00:00:00 2001 From: gahusb Date: Sat, 21 Mar 2026 09:40:37 +0900 Subject: [PATCH] =?UTF-8?q?music-lab=20=ED=94=84=EB=A1=A0=ED=8A=B8?= =?UTF-8?q?=EC=97=94=EB=93=9C=20=EB=8C=80=EC=A1=B0=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?(=EC=9D=B4=EC=A4=91=EC=A0=80=EC=9E=A5=C2=B7title=C2=B7audio=5Fu?= =?UTF-8?q?rl=C2=B7status=20shape)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 이중 저장 방지: auto-register 유지, Save 버튼 제거는 프론트 담당 (방식 A) - title 자동 생성: "{genre} — {mood} Mix" 형식으로 개선 - audio_url 절대경로 제거: 항상 /media/music/{task_id}.mp3 상대경로 반환 - status succeeded 시 track 메타데이터 포함 (프론트 Save 버튼 없이 즉시 UI 반영 가능) - get_track_by_task_id() 함수 추가 Co-Authored-By: Claude Sonnet 4.6 --- music-lab/app/db.py | 6 ++++++ music-lab/app/main.py | 24 +++++++++++++++++++----- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/music-lab/app/db.py b/music-lab/app/db.py index ca54e97..f04dc6c 100644 --- a/music-lab/app/db.py +++ b/music-lab/app/db.py @@ -171,6 +171,12 @@ def delete_track(track_id: int) -> bool: return True +def get_track_by_task_id(task_id: str) -> Optional[Dict[str, Any]]: + with _conn() as conn: + row = conn.execute("SELECT * FROM music_library WHERE task_id = ?", (task_id,)).fetchone() + return _track_row_to_dict(row) if row else None + + def get_track_file_path(track_id: int) -> Optional[str]: with _conn() as conn: row = conn.execute("SELECT file_path FROM music_library WHERE id = ?", (track_id,)).fetchone() diff --git a/music-lab/app/main.py b/music-lab/app/main.py index afe696e..db90af4 100644 --- a/music-lab/app/main.py +++ b/music-lab/app/main.py @@ -10,7 +10,7 @@ from pydantic import BaseModel from .db import ( init_db, create_task, update_task, get_task, - get_all_tracks, add_track, delete_track, get_track_file_path, + get_all_tracks, add_track, delete_track, get_track_file_path, get_track_by_task_id, ) app = FastAPI() @@ -86,11 +86,15 @@ def _run_generation(task_id: str, params: dict) -> None: for chunk in resp.iter_content(chunk_size=8192): f.write(chunk) - audio_url = f"{MUSIC_MEDIA_BASE}/{filename}" + # audio_url은 항상 Nginx 상대경로 (Mixed Content 방지) + audio_url = f"/media/music/{filename}" - # 라이브러리 자동 등록 + # 라이브러리 자동 등록 — title 자동 생성 genre = params.get("genre", "") - title = f"{genre} {task_id[:8]}" if genre else task_id[:8] + moods = params.get("moods", []) + mood_str = moods[0] if moods else "Original" + title = f"{genre} — {mood_str} Mix" if genre else f"{mood_str} Mix" + add_track({ "title": title, "genre": genre, @@ -145,11 +149,13 @@ def get_status(task_id: str): """ 생성 작업 상태 조회. 프론트는 succeeded 또는 failed가 될 때까지 폴링. status: queued | processing | succeeded | failed + succeeded 시 track 메타데이터 포함 (라이브러리 별도 저장 불필요). """ task = get_task(task_id) if not task: raise HTTPException(status_code=404, detail="Task not found") - return { + + resp = { "status": task["status"], "progress": task["progress"], "message": task["message"], @@ -157,6 +163,14 @@ def get_status(task_id: str): "error": task["error"], } + # succeeded 시 라이브러리에 저장된 트랙 메타데이터 포함 + # 프론트는 이 track 객체로 UI를 바로 업데이트하면 됨 (Save 버튼 불필요) + if task["status"] == "succeeded": + track = get_track_by_task_id(task_id) + resp["track"] = track + + return resp + # ── 라이브러리 API ────────────────────────────────────────────────────────────