Files
web-page-backend/docs/superpowers/specs/2026-04-08-music-lab-suno-enhancement-design.md
gahusb 6ffa04f847 docs: music-lab Suno API 전체 기능 확장 설계 스펙
Suno API 미사용 기능 분석 후 3단계 점진 확장 설계.
Phase 1(생성 강화), Phase 2(후처리), Phase 3(리믹스) 구조.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-08 03:13:41 +09:00

15 KiB
Raw Blame History

Music Lab Suno API 전체 기능 확장 설계

작성일: 2026-04-08 범위: 백엔드 (web-backend/music-lab) + 프론트엔드 (web-ui/src/pages/music)


1. 목표

Suno API의 미사용 기능을 전부 활용하여 music-lab을 완전한 AI 음악 프로덕션 스튜디오로 업그레이드한다. 실용도 기준 3단계로 점진 확장.

2. 단계별 기능 목록

Phase 1: 핵심 생성 강화

# 기능 설명
1-1 크레딧 잔액 상시 표시 헤더에 실시간 크레딧 배지, 10 이하 경고
1-2 보컬 성별 선택 Male / Female / Auto 3버튼
1-3 negativeTags 제외 스타일 텍스트 + 프리셋 칩
1-4 V5_5 모델 추가 SUNO_MODELS 딕셔너리에 추가
1-5 styleWeight / audioWeight 0~1.0 슬라이더 2개
1-6 커버 이미지 생성 라이브러리 카드에서 앨범아트 2장 생성

Phase 2: 후처리 파워업

# 기능 설명
2-1 WAV 고음질 변환 MP3→WAV 변환 다운로드
2-2 12스템 분리 드럼/베이스/기타 등 12개 개별 추출
2-3 타임스탬프 가사 가라오케 스타일 싱크 재생
2-4 스타일 부스트 AI로 최적 스타일 프롬프트 자동 생성

Phase 3: 고급 크리에이티브

# 기능 설명
3-1 오디오 업로드 + 커버 외부 음원을 Suno 스타일로 리메이크
3-2 오디오 업로드 + 확장 외부 음원 이어서 만들기
3-3 보컬 추가 인스트루멘탈에 AI 보컬 입히기
3-4 인스트루멘탈 추가 보컬에 AI 반주 입히기
3-5 뮤직비디오 생성 MP4 자동 생성

3. 백엔드 API 설계

3.1 기존 엔드포인트 수정

GenerateRequest 스키마 확장 (main.py)

class GenerateRequest(BaseModel):
    # 기존 필드 유지
    provider: str = "suno"
    model: str = "V4"
    title: str = ""
    genre: str = ""
    moods: list[str] = []
    instruments: list[str] = []
    duration_sec: int | None = None
    bpm: int | None = None
    key: str = ""
    scale: str = ""
    prompt: str = ""
    lyrics: str = ""
    instrumental: bool = False
    
    # Phase 1 추가
    vocal_gender: str | None = None      # "m" | "f" | None(auto)
    negative_tags: str | None = None     # 제외 스타일
    style_weight: float | None = None    # 0.0~1.0
    audio_weight: float | None = None    # 0.0~1.0

SUNO_MODELS 확장 (suno_provider.py)

SUNO_MODELS = {
    "V4":       {"name": "V4",      "max_duration": 240},
    "V4_5":     {"name": "V4.5",    "max_duration": 480},
    "V4_5PLUS": {"name": "V4.5+",   "max_duration": 480},
    "V4_5ALL":  {"name": "V4.5 All","max_duration": 480},
    "V5":       {"name": "V5",      "max_duration": 480},
    "V5_5":     {"name": "V5.5",    "max_duration": 480},  # 추가
}

_build_suno_payload 확장

새 파라미터를 Suno API 페이로드에 매핑:

  • vocal_gendervocalGender
  • negative_tagsnegativeTags
  • style_weightstyleWeight
  • audio_weightaudioWeight

None이 아닌 경우에만 페이로드에 포함.

3.2 신규 엔드포인트

Phase 1

POST /api/music/cover-image
Request:  { "task_id": str, "suno_id": str }
Response: { "task_id": str }  → 폴링 → { "images": [url1, url2] }

Phase 2

POST /api/music/wav
Request:  { "task_id": str, "suno_id": str }
Response: { "task_id": str }  → 폴링 → { "wav_url": str }

POST /api/music/stem-split
Request:  { "task_id": str, "suno_id": str }
Response: { "task_id": str }  → 폴링 → { "stems": { vocal: url, drums: url, ... } }

GET /api/music/timestamped-lyrics?task_id=...&suno_id=...
Response: { "aligned_words": [...], "waveform_data": [...] }

POST /api/music/style-boost
Request:  { "content": str }
Response: { "result": str, "credits_consumed": float }

Phase 3

POST /api/music/upload-cover
Request:  { "upload_url": str, "model": str, "custom_mode": bool,
            "instrumental": bool, "prompt"?: str, "style"?: str, "title"?: str,
            "vocal_gender"?: str, "negative_tags"?: str,
            "style_weight"?: float, "audio_weight"?: float }
Response: { "task_id": str }

POST /api/music/upload-extend
Request:  { "upload_url": str, "model": str, "continue_at"?: float,
            "default_param_flag": bool, "prompt"?: str, "style"?: str, "title"?: str,
            "vocal_gender"?: str, "negative_tags"?: str }
Response: { "task_id": str }

POST /api/music/add-vocals
Request:  { "upload_url": str, "prompt": str, "title": str, "style": str,
            "negative_tags": str, "vocal_gender"?: str, "model"?: str,
            "style_weight"?: float, "audio_weight"?: float }
Response: { "task_id": str }

POST /api/music/add-instrumental
Request:  { "upload_url": str, "title": str, "tags": str, "negative_tags": str,
            "vocal_gender"?: str, "model"?: str,
            "style_weight"?: float, "audio_weight"?: float }
Response: { "task_id": str }

POST /api/music/video
Request:  { "task_id": str, "suno_id": str, "author"?: str, "domain_name"?: str }
Response: { "task_id": str }  → 폴링 → { "video_url": str }

3.3 suno_provider.py 리팩토링

공통 폴링 헬퍼 추출:

def _poll_suno_task(
    record_info_url: str,
    task_id: str,
    max_attempts: int = 40,
    interval: int = 8,
    success_extractor: Callable[[dict], Any] = None
) -> dict:
    """
    범용 Suno 작업 폴링.
    record_info_url: 예) "/api/v1/generate/record-info"
    success_extractor: SUCCESS 상태일 때 결과 추출 함수
    """

기존 run_suno_generation, run_suno_extend, run_vocal_removal도 이 헬퍼를 사용하도록 리팩토링.

신규 함수 목록:

함수 Phase Suno 엔드포인트 비동기
run_cover_image 1 POST /api/v1/suno/cover/generate 폴링
run_wav_convert 2 POST /api/v1/wav/generate 폴링
run_stem_split 2 POST /api/v1/vocal-removal/generate (type=split_stem) 폴링
get_timestamped_lyrics 2 POST /api/v1/generate/get-timestamped-lyrics 동기
generate_style_boost 2 POST /api/v1/style/generate 동기
run_upload_cover 3 POST /api/v1/generate/upload-cover 폴링
run_upload_extend 3 POST /api/v1/generate/upload-extend 폴링
run_add_vocals 3 POST /api/v1/generate/add-vocals 폴링
run_add_instrumental 3 POST /api/v1/generate/add-instrumental 폴링
run_video_generate 3 POST /api/v1/mp4/generate 폴링

3.4 DB 스키마 변경

music_library 테이블 컬럼 추가 (ALTER TABLE 마이그레이션):

ALTER TABLE music_library ADD COLUMN cover_images TEXT NOT NULL DEFAULT '[]';
ALTER TABLE music_library ADD COLUMN wav_url TEXT NOT NULL DEFAULT '';
ALTER TABLE music_library ADD COLUMN video_url TEXT NOT NULL DEFAULT '';
ALTER TABLE music_library ADD COLUMN stem_urls TEXT NOT NULL DEFAULT '{}';

db.py 함수 추가:

def update_track_cover_images(track_id: int, images: list[str])
def update_track_wav_url(track_id: int, wav_url: str)
def update_track_video_url(track_id: int, video_url: str)
def update_track_stem_urls(track_id: int, stems: dict)

4. 프론트엔드 UI/UX 설계

4.1 파일 구조 (컴포넌트 분할)

web-ui/src/pages/music/
├── MusicStudio.jsx              -- 메인 (탭 라우팅 + 공유 상태)
├── MusicStudio.css              -- 전체 스타일
├── components/
│   ├── CreateTab.jsx            -- 생성 폼 (6단계 + Phase 1 확장)
│   ├── LyricsTab.jsx            -- 가사 관리
│   ├── LibraryTab.jsx           -- 라이브러리 + 카드
│   ├── RemixTab.jsx             -- Phase 3: 업로드/리믹스
│   ├── AudioPlayer.jsx          -- 오디오 플레이어
│   ├── LibraryCard.jsx          -- 트랙 카드 + 액션 메뉴
│   ├── StemModal.jsx            -- 12스템 결과 모달
│   ├── CoverArtModal.jsx        -- 커버 이미지 선택 모달
│   ├── SyncedLyricsPlayer.jsx   -- 타임스탬프 가사 오버레이
│   └── CreditsBadge.jsx         -- 크레딧 잔액 배지

4.2 Phase 1 UI 변경

크레딧 배지 (CreditsBadge)

  • 위치: 헤더 우측 상단, 탭 옆
  • 표시: ⚡ 127 credits
  • 10 이하: 빨간색 + pulse 애니메이션
  • 갱신 시점: 페이지 로드, 생성 완료 후, 30초 자동 갱신

Create 탭 Step 4 확장

Vocal Gender (Suno 전용):

  • 3버튼 토글: ♂ Male | ♀ Female | Auto
  • 기본값: Auto
  • 스타일: .ms-gender-toggle (기존 duration-rail과 유사)

Negative Tags:

  • 텍스트 입력 필드 + 프리셋 칩
  • 프리셋: screaming, autotune, distortion, whisper, falsetto, rap
  • 칩 클릭 시 텍스트에 추가/제거
  • 스타일: .ms-negative-tags (기존 mood-rack과 유사)

Style Weight / Audio Weight:

  • range 슬라이더 2개 (기존 BPM 슬라이더와 동일 스타일)
  • 레이블: "Prompt ↔ Style Balance" / "Original ↔ AI Balance"
  • 0100 표시, API 전송 시 0.01.0 변환
  • 기본값: 미설정 (슬라이더 중앙, 값 전송 안 함)

Library 카드 액션 메뉴 확장

기존 5개 버튼 → 6개 (Cover Art 추가) 4개 초과 시 ••• 더보기 드롭다운 메뉴로 분기:

  • 기본 노출: Play, Download, Delete
  • 더보기: Extend, Vocal Split, Cover Art (+ Phase 2/3 추가분)

CoverArtModal

  • 2장 이미지 좌우 비교 표시
  • 각 이미지 아래 "이 이미지 사용" 버튼
  • 선택 시 라이브러리 카드 썸네일 업데이트

4.3 Phase 2 UI 변경

Library 카드 더보기 메뉴 추가

  • WAV 다운로드
  • Stem Split (12스템)
  • Synced Lyrics
  • Style Boost (Create 탭 프롬프트로 전달)

StemModal

  • 3×4 그리드 카드 레이아웃
  • 각 스템: 이름 아이콘 + 미니 재생 버튼 + 다운로드 버튼
  • 12개 스템: vocal, backing_vocals, drums, bass, guitar, keyboard, strings, brass, woodwinds, percussion, synth, fx
  • 스타일: 기존 라이브러리 카드의 축소 버전

SyncedLyricsPlayer

  • AudioPlayer 교체/오버레이 모드
  • 재생 중 현재 단어를 accent 컬러로 하이라이트
  • 하단에 waveformData 기반 파형 바
  • 닫기 버튼으로 일반 플레이어 복귀

Style Boost 버튼

  • Create 탭 장르 선택 영역에 ✨ Style Boost 버튼
  • 클릭 시: 현재 genre + moods 조합 → API 호출 → 결과를 프롬프트에 삽입
  • 로딩 중 버튼 스피너

4.4 Phase 3 UI 변경

Remix 탭 (신규 4번째 탭)

  • 탭 레이블: REMIX
  • 상단: 오디오 URL 입력 필드 (또는 라이브러리에서 선택)
  • 4개 액션 카드 그리드 (2×2):
    • AI Cover: 아이콘 + 설명 + 파라미터 폼 (펼침)
    • Extend: 아이콘 + 설명 + continue_at 입력
    • Add Vocals: 아이콘 + 설명 + prompt/style 입력
    • Add Instrumental: 아이콘 + 설명 + tags 입력
  • 선택한 카드만 펼쳐서 세부 옵션 표시
  • 하단: 뮤직비디오 생성 버튼 (라이브러리에서 선택한 곡 대상)

4.5 디자인 토큰 추가

/* Phase 1 추가 토큰 */
--ms-danger:   #e74c3c;     /* 크레딧 경고 빨간색 */
--ms-male:     #4a9eff;     /* 남성 보컬 파란색 */
--ms-female:   #ff6b9d;     /* 여성 보컬 분홍색 */

5. api.js 추가 함수

// Phase 1
export const generateCoverImage = (payload) => apiPost('/api/music/cover-image', payload);

// Phase 2
export const convertToWav = (payload) => apiPost('/api/music/wav', payload);
export const splitStems = (payload) => apiPost('/api/music/stem-split', payload);
export const getTimestampedLyrics = (taskId, sunoId) =>
    apiGet(`/api/music/timestamped-lyrics?task_id=${taskId}&suno_id=${sunoId}`);
export const generateStyleBoost = (content) => apiPost('/api/music/style-boost', { content });

// Phase 3
export const uploadAndCover = (payload) => apiPost('/api/music/upload-cover', payload);
export const uploadAndExtend = (payload) => apiPost('/api/music/upload-extend', payload);
export const addVocals = (payload) => apiPost('/api/music/add-vocals', payload);
export const addInstrumental = (payload) => apiPost('/api/music/add-instrumental', payload);
export const generateVideo = (payload) => apiPost('/api/music/video', payload);

6. 폴링 패턴

모든 비동기 작업은 기존 음악 생성과 동일한 폴링 패턴:

  1. POST 요청 → { task_id } 반환
  2. 프론트: 3초 간격 GET /api/music/status/{task_id} 폴링
  3. 백엔드: BackgroundTask에서 Suno 폴링 → music_tasks 상태 업데이트
  4. status: succeeded → 결과 반환 + 라이브러리 자동 갱신

동기 API (타임스탬프 가사, 스타일 부스트)는 즉시 응답.


7. 구현 순서

Phase 1 (핵심 생성 강화)

  1. 백엔드: SUNO_MODELS에 V5_5 추가 + 공통 폴링 헬퍼 추출
  2. 백엔드: GenerateRequest 스키마 확장 + _build_suno_payload 매핑
  3. 백엔드: 커버 이미지 생성 엔드포인트 + suno_provider 함수
  4. 백엔드: DB 마이그레이션 (cover_images, wav_url, video_url, stem_urls)
  5. 프론트: 컴포넌트 분할 (MusicStudio → CreateTab, LyricsTab, LibraryTab, etc.)
  6. 프론트: CreditsBadge 구현
  7. 프론트: Create 탭 Step 4 확장 (vocal gender, negative tags, weight 슬라이더)
  8. 프론트: LibraryCard 더보기 메뉴 + CoverArtModal
  9. 프론트: api.js 함수 추가

Phase 2 (후처리 파워업)

  1. 백엔드: WAV/스템/타임스탬프/스타일부스트 엔드포인트
  2. 프론트: StemModal + SyncedLyricsPlayer + Style Boost 버튼
  3. 프론트: Library 카드 Phase 2 액션 추가

Phase 3 (고급 크리에이티브)

  1. 백엔드: upload-cover/upload-extend/add-vocals/add-instrumental/video 엔드포인트
  2. 프론트: RemixTab 구현
  3. 프론트: Library 카드 Phase 3 액션 (Video)

8. 제약사항 및 주의점

  • Suno 파일 보관: 14~15일 후 자동 삭제 → 로컬 다운로드 필수 (기존 패턴 유지)
  • 동시 요청 제한: 10초당 20건 → 배치 작업 시 rate limiting 고려
  • 12스템 분리 비용: 50크레딧 → UI에 비용 경고 표시
  • WAV 중복 변환: 409 에러 → 이미 변환된 경우 기존 URL 반환
  • 뮤직비디오: taskId + audioId 필요 → 라이브러리에 task_id 저장 필수
  • V5_5 모델: 커스텀 모델 → 문서상 제한사항 추가 확인 필요
  • 크레딧 조회 엔드포인트: 기존 /api/v1/get-credits vs 문서 /api/v1/generate/credit → 두 엔드포인트 폴백 시도
  • upload 계열 API: upload_url은 외부 접근 가능한 URL이어야 함 → 로컬 파일은 NAS nginx URL로 변환