# Frontend Integration Guide — 단일 스태프 Analyze API (v1) `POST /analyze` 를 호출해 **한 줄 오선** 악보 사진(1장 또는 여러 장)을 보내고, **병합된 단일 멜로디 JSON**을 받는다. 이전 다중 스태프·합창 스펙과 **호환되지 않는다**(필드 구조가 단순화됨). 상세 계약: **`docs/analyze-api-spec.md`** (SSOT). --- ## 1) 한 줄 요약 | 항목 | 내용 | |------|------| | 입력 이미지 | **한 장당 staff 한 줄**만 있다고 가정 | | Clef / 조표 | 이미지에 없을 수 있음 → **`score_context` 로 필수 전달** | | 화음 | 최대 2성부; 응답 멜로디는 **항상 최고음**만 | | 여러 장 | **업로드 순서 = 악보 진행 순서**; 서버는 장별 분석 후 **`melody.events` 하나로 병합** | | 재생 핵심 | `timeline` + `melody.events` + (표시용) `score_context` | --- ## 2) 요청 만들기 ### 2.1 `multipart/form-data` - **`score_context` (필수):** JSON **문자열** 한 덩어리. - 최소: `{ "clef": "treble", "key_signature": { "fifths": 0 } }` - 선택: `time_signature`, `tempo_bpm_reference`, `divisions` (기본 `4/4`, `null`, `4`) - **`files`:** 같은 필드명으로 여러 번 붙이거나, 단일 `file` 사용. - **`options`:** JSON 문자열. 보통 `{ "return_debug": false, "quantization": "1/8" }`. ### 2.2 `fetch` 예시 (브라우저) ```javascript const scoreContext = { clef: "treble", key_signature: { fifths: -1 }, time_signature: "4/4", tempo_bpm_reference: 72, divisions: 4, }; const form = new FormData(); form.append("score_context", JSON.stringify(scoreContext)); form.append("options", JSON.stringify({ return_debug: false, quantization: "1/8" })); for (const file of fileListFromInput) { form.append("files", file, file.name); } const res = await fetch("/analyze", { method: "POST", body: form }); const data = await res.json(); if (!res.ok) throw new Error(JSON.stringify(data)); ``` ### 2.3 `curl` 예시 ```bash curl -X POST http://localhost:8000/analyze \ -F 'score_context={"clef":"treble","key_signature":{"fifths":-1},"time_signature":"4/4","divisions":4}' \ -F 'options={"return_debug":false,"quantization":"1/8"}' \ -F "files=@sample_imgs/sample_oneline_0.png" \ -F "files=@sample_imgs/sample_oneline_chord.png" ``` --- ## 3) 응답 읽기 ### 3.1 최소 구독 필드 - **`melody.events`:** 재생·편집의 본체. 시간 순. - **`timeline.divisions`:** `duration_div` / `onset_div` 의 척도(한 4분음표 = `divisions`). - **`timeline.time_signature`:** 마디 길이 해석·UI용. - **`score_context`:** 조표·clef 표시(서버 에코; 클라이언트가 보낸 값이 정답). ### 3.2 이벤트 타입 - **`note`:** `step`, `octave`, `alter`, `duration_div`, `onset_div` 필수. `pitch_midi` 가 있으면 재생에 사용 가능. - **`rest`:** `duration_div`, `onset_div` 만으로 충분. **시간 계산:** - 절대 시각(초)은 서버가 강제하지 않는다. - `beat = onset_div / divisions` 로 마디 내 위치를 계산할 수 있다. ### 3.3 여러 장 이미지 UI 연동 - **`segment_map`:** 각 원본 이미지가 `melody.events` 의 어느 인덱스 구간에 해당하는지. - **`events[].segment_order` / `bbox`:** 특정 음을 원본 크롭 위에 하이라이트할 때 사용(없을 수 있음). ### 3.4 `warnings` - 치명적이지 않아도 **품질 저하**를 나타낼 수 있다. - UI에서는 토스트/배지로 노출하고, 사용자에게 “자동 인식이 불안정할 수 있음”을 안내하는 용도를 권장. --- ## 4) 오류 처리 | 코드 | 프론트 액션 예시 | |------|------------------| | `400` | `score_context` / `options` / 파일 필드 검증 | | `413` | 업로드 전 클라이언트에서 용량 사전 차단 | | `415` | 확장자 필터 | | `422` | “이 사진은 한 줄 악보로 인식되지 않았습니다” + 재촬영 안내 | --- ## 5) 마이그레이션 메모 (기존 프론트 대비) - **`detection.staffs[].voices[]`** 구조 **제거** → **`melody` 단일 블록**으로 통합. - **`score_type_estimate`**, **`is_accompaniment`**, **`include_accompaniment`** 옵션: v1 스펙 없음. - Clef/key 는 더 이상 “서버 추정”이 아니라 **클라이언트가 `score_context` 로 제공**해야 함. --- ## 6) 참고 파일 - `docs/analyze-api-spec.md` — 필드·의미·경고 코드 전체 - `docs/analyze-response-format-examples.json` — 복붙 가능한 예시 JSON