feat(music-lab): Phase 2 백엔드 — WAV 변환, 12스템 분리, 타임스탬프 가사, 스타일 부스트
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -15,8 +15,8 @@ from .db import (
|
||||
from .local_provider import run_local_generation
|
||||
from .suno_provider import (
|
||||
run_suno_generation, run_suno_extend, run_vocal_removal,
|
||||
run_cover_image,
|
||||
generate_lyrics, get_credits,
|
||||
run_cover_image, run_wav_convert, run_stem_split,
|
||||
generate_lyrics, get_credits, get_timestamped_lyrics, generate_style_boost,
|
||||
SUNO_API_KEY, SUNO_MODELS,
|
||||
)
|
||||
|
||||
@@ -428,6 +428,76 @@ def cover_image(req: CoverImageRequest, background_tasks: BackgroundTasks):
|
||||
return {"task_id": task_id, "provider": "suno"}
|
||||
|
||||
|
||||
# ── WAV 변환 API ────────────────────────────────────────────────────────────
|
||||
|
||||
class WavRequest(BaseModel):
|
||||
suno_task_id: str
|
||||
suno_id: str
|
||||
track_id: Optional[int] = None
|
||||
|
||||
|
||||
@app.post("/api/music/wav")
|
||||
def wav_convert(req: WavRequest, background_tasks: BackgroundTasks):
|
||||
"""곡을 WAV 포맷으로 변환."""
|
||||
if not SUNO_API_KEY:
|
||||
raise HTTPException(status_code=400, detail="Suno API 키가 설정되지 않았습니다")
|
||||
task_id = str(uuid.uuid4())
|
||||
params = req.model_dump()
|
||||
create_task(task_id, params, provider="suno")
|
||||
background_tasks.add_task(run_wav_convert, task_id, params)
|
||||
return {"task_id": task_id, "provider": "suno"}
|
||||
|
||||
|
||||
# ── 12스템 분리 API ─────────────────────────────────────────────────────────
|
||||
|
||||
class StemSplitRequest(BaseModel):
|
||||
suno_task_id: str
|
||||
suno_id: str
|
||||
track_id: Optional[int] = None
|
||||
|
||||
|
||||
@app.post("/api/music/stem-split")
|
||||
def stem_split(req: StemSplitRequest, background_tasks: BackgroundTasks):
|
||||
"""곡을 12개 스템으로 분리 (50 크레딧). 보컬, 드럼, 베이스, 기타 등."""
|
||||
if not SUNO_API_KEY:
|
||||
raise HTTPException(status_code=400, detail="Suno API 키가 설정되지 않았습니다")
|
||||
task_id = str(uuid.uuid4())
|
||||
params = req.model_dump()
|
||||
create_task(task_id, params, provider="suno")
|
||||
background_tasks.add_task(run_stem_split, task_id, params)
|
||||
return {"task_id": task_id, "provider": "suno"}
|
||||
|
||||
|
||||
# ── 타임스탬프 가사 API ─────────────────────────────────────────────────────
|
||||
|
||||
@app.get("/api/music/timestamped-lyrics")
|
||||
def timestamped_lyrics(task_id: str, suno_id: str):
|
||||
"""타임스탬프 가사 조회 (가라오케 스타일 싱크용)."""
|
||||
if not SUNO_API_KEY:
|
||||
raise HTTPException(status_code=400, detail="Suno API 키가 설정되지 않았습니다")
|
||||
result = get_timestamped_lyrics(task_id, suno_id)
|
||||
if not result:
|
||||
raise HTTPException(status_code=502, detail="타임스탬프 가사 조회 실패")
|
||||
return result
|
||||
|
||||
|
||||
# ── 스타일 부스트 API ───────────────────────────────────────────────────────
|
||||
|
||||
class StyleBoostRequest(BaseModel):
|
||||
content: str
|
||||
|
||||
|
||||
@app.post("/api/music/style-boost")
|
||||
def style_boost(req: StyleBoostRequest):
|
||||
"""AI로 최적 스타일 프롬프트 생성."""
|
||||
if not SUNO_API_KEY:
|
||||
raise HTTPException(status_code=400, detail="Suno API 키가 설정되지 않았습니다")
|
||||
result = generate_style_boost(req.content)
|
||||
if not result:
|
||||
raise HTTPException(status_code=502, detail="스타일 부스트 생성 실패")
|
||||
return result
|
||||
|
||||
|
||||
# ── 저장된 가사 CRUD API ────────────────────────────────────────────────────
|
||||
|
||||
class LyricsSave(BaseModel):
|
||||
|
||||
Reference in New Issue
Block a user