stella-score-reader / docs /analyze-api-spec.md
CAY96
update docs
bc8019c

Analyze API Spec (단일 μŠ€νƒœν”„ / v1)

이 λ¬Έμ„œλŠ” **단일 μ§„μ‹€ 곡급원(SSOT)**이닀. κ΅¬ν˜„Β·ν…ŒμŠ€νŠΈΒ·ν”„λ‘ νŠΈ 계약은 μ—¬κΈ° μ •μ˜ν•œ μŠ€ν‚€λ§ˆμ™€ 의미λ₯Ό λ”°λ₯Έλ‹€.

  • μ—”λ“œν¬μΈνŠΈ: POST /analyze
  • 좜λ ₯: λͺ¨λ°”일/μ›Ήμ—μ„œ λ°”λ‘œ μ“Έ 수 μžˆλŠ” JSON ν•œ 덩어리(MusicXML 등은 HTTP 응닡에 ν¬ν•¨ν•˜μ§€ μ•ŠμŒ; μ„œλ²„ λ‚΄λΆ€ μ „μš© κ°€λŠ₯).
  • μ˜ˆμ‹œ 응닡 묢음: docs/analyze-response-format-examples.json

1) μ œν’ˆ λ²”μœ„ (μ‹¬ν”Œ λͺ¨λ“œ)

1.1 μž…λ ₯ 이미지에 λŒ€ν•œ κ°€μ •

  1. ν•œ 이미지 = μ˜€μ„ (staff) μ •ν™•νžˆ ν•œ μ€„λ§Œ μžˆλ‹€κ³  κ°€μ •ν•œλ‹€.
    • 볡수 쀄(예: ν”Όμ•„λ…Έ λŒ€λ³΄ν‘œ), ν•©μ°½ 닀쀑 μŠ€νƒœν”„ 등은 이 μŠ€νŽ™μ˜ λ²”μœ„ 밖이닀.
  2. 사진은 인쇄 악보λ₯Ό μΉ΄λ©”λΌλ‘œ 찍은 λ’€ ν¬λ‘­ν•œ 것일 수 μžˆλ‹€.
    • 쒅이 νœ˜μ–΄μ§, 기울기, μ‘°λͺ…, 손글씨 λ‚™μ„œ 등이 μžˆμ„ 수 있으며, μ„œλ²„λŠ” μ „μ²˜λ¦¬(OpenCV λ“±) + ν•„μš” μ‹œ λ”₯λŸ¬λ‹ 기반 OMR으둜 이에 λŒ€μ‘ν•œλ‹€(κ΅¬ν˜„ λ””ν…ŒμΌμ€ μ½”λ“œΒ·λ³„λ„ λ¬Έμ„œ; μ—¬κΈ°μ„œλŠ” μž…μΆœλ ₯ κ³„μ•½λ§Œ κ³ μ •ν•œλ‹€).

1.2 음ν–₯ λ‚΄μš©μ— λŒ€ν•œ κ°€μ •

  • λ‹¨μ„ μœ¨(λ‹¨μŒ) λ˜λŠ” **ν™”μŒ(λ™μ‹œμ— μšΈλ¦¬λŠ” 음, μ΅œλŒ€ 2μ„±λΆ€)**이 올 수 μžˆλ‹€.
  • ν™”μŒμΈ 경우, κ²°κ³Ό λ©œλ‘œλ”” μ‹œν€€μŠ€λŠ” 항상 β€œκ°€μž₯ 높은 μŒν‘œβ€λ§Œ μ‚¬μš©ν•œλ‹€(2μ„±λΆ€λ₯Ό ν•œ 음으둜 μ€„μ΄λŠ” κ·œμΉ™).
  • μŒμžλ¦¬ν‘œ(clef) 와 μ‘°ν‘œ(key signature) λŠ” 이미지 맨 μ•žμ—μ„œ 잘렀 λ‚˜κ°”μ„ 수 μžˆλ‹€. 이 두 μ •λ³΄λŠ” 항상 ν΄λΌμ΄μ–ΈνŠΈκ°€ μš”μ²­κ³Ό ν•¨κ»˜ μ œκ³΅ν•œλ‹€(μ•„λž˜ score_context).

1.3 μ—¬λŸ¬ μž₯ 이미지

  • ν•œ μš”μ²­μ— μ—¬λŸ¬ 이미지λ₯Ό 보낼 수 μžˆλ‹€. 파일 **μ—…λ‘œλ“œ μˆœμ„œ = 악보 μ½λŠ” μˆœμ„œ(μ™Όμͺ½β†’μ˜€λ₯Έμͺ½ 이어짐)**이닀.
  • μ„œλ²„λŠ” μ΄λ―Έμ§€λ§ˆλ‹€ λ…λ¦½μ μœΌλ‘œ 인식 νŒŒμ΄ν”„λΌμΈμ„ 돌릴 수 μžˆλ‹€.
  • μ‘λ‹΅μ˜ λ©œλ‘œλ”” νƒ€μž„λΌμΈμ€ ν•˜λ‚˜λ‘œ λ³‘ν•©ν•œλ‹€. 즉, onset_div / duration_div λŠ” 마치 ν•œ μž₯짜리 μž…λ ₯μ΄μ—ˆλ˜ κ²ƒμ²˜λŸΌ 이어진 단일 μ‹œν€€μŠ€λ‹€.

2) μš”μ²­ (Request)

2.1 전솑 ν˜•μ‹

  • Content-Type: multipart/form-data

2.2 ν•„λ“œ

ν•„λ“œ ν•„μˆ˜ μ„€λͺ…
score_context 예 JSON λ¬Έμžμ—΄. μŒλ†’μ΄ 해석에 ν•„μš”ν•œ clefΒ·μ‘°ν‘œ(및 선택 ν•„λ“œ). ν˜•μ‹μ€ Β§2.3.
file 쑰건뢀 단일 이미지 (jpg, jpeg, png, webp).
files 쑰건뢀 동일 ν‚€ 반볡으둜 μ—¬λŸ¬ 이미지. 예: -F "files=@a.png" -F "files=@b.png"
options μ•„λ‹ˆμ˜€ JSON λ¬Έμžμ—΄. ν˜•μ‹μ€ Β§2.4.

κ·œμΉ™:

  • file κ³Ό files 쀑 ν•˜λ‚˜λŠ” λ°˜λ“œμ‹œ μ‘΄μž¬ν•΄μ•Ό ν•œλ‹€.
  • λ‘˜ λ‹€ 있으면 files μš°μ„ ν•œλ‹€.
  • score_context κ°€ μ—†κ±°λ‚˜ JSON νŒŒμ‹± μ‹€νŒ¨ μ‹œ 400.

2.3 score_context (JSON 객체)

ν•„μˆ˜:

ν‚€ νƒ€μž… μ„€λͺ…
clef string μŒμžλ¦¬ν‘œ. ν—ˆμš© κ°’: treble, bass. (μΆ”ν›„ alto, tenor λ“± ν™•μž₯ κ°€λŠ₯ν•˜λ‚˜ v1 κ΅¬ν˜„μ€ treble/bass μš°μ„ .)
key_signature object μ‘°ν‘œ.
key_signature.fifths integer μž₯μ‘° κΈ°μ€€ μ‘°ν‘œμ˜ 샡/ν”Œλž« 개수. λ²”μœ„ -6 ~ 6. 음수=ν”Œλž«, μ–‘μˆ˜=샡, 0=λ‹€μž₯μ‘°.

선택 (v1μ—μ„œ ꢌμž₯Β·κΈ°λ³Έκ°’ 있음):

ν‚€ νƒ€μž… κΈ°λ³Έ μ„€λͺ…
time_signature string "4/4" "<beats>/<beat-type>" ν˜•μ‹. 예: "3/4", "6/8".
tempo_bpm_reference number | null null UI·클릭 νŠΈλž™μš© μ°Έκ³  ν…œν¬. λ―Έμ§€μ • μ‹œ ν”„λ‘ νŠΈκ°€ 자체 κΈ°λ³Έκ°’ μ‚¬μš©.
divisions integer 4 ν•œε››εˆ†ιŸ³η¬¦(4λΆ„μŒν‘œ)λ₯Ό λͺ‡ 개의 division λ‹¨μœ„λ‘œ μͺΌκ°€μ§€. 응닡 timeline.divisions 와 동일해야 ν•œλ‹€.

적용 λ²”μœ„:

  • v1μ—μ„œλŠ” score_context λ₯Ό ν•΄λ‹Ή μš”μ²­μ˜ λͺ¨λ“  이미지에 동일 μ μš©ν•œλ‹€.
  • μž₯μ°¨ β€œμ΄λ―Έμ§€λ§ˆλ‹€ λ‹€λ₯Έ clef/key”가 ν•„μš”ν•˜λ©΄ score_context λ°°μ—΄(파일 μˆœμ„œμ™€ 동일 길이) λ“±μœΌλ‘œ 버전 μ—…ν•œλ‹€.

2.4 options (JSON 객체)

κΈ°λ³Έκ°’ μ˜ˆμ‹œ:

{
  "return_debug": false,
  "quantization": "1/8"
}
ν‚€ νƒ€μž… κΈ°λ³Έ μ„€λͺ…
return_debug boolean false true 이면 meta.debug λ“± 디버그 μ „μš© ν•„λ“œ 포함 κ°€λŠ₯.
quantization string "1/8" 리듬 μ–‘μžν™” κ·Έλ¦¬λ“œ. ν—ˆμš©: "1/4", "1/8", "1/16".

2.5 μš©λŸ‰Β·ν¬λ§· μ œν•œ (λΉ„κΈ°λŠ₯)

  • 이미지 1μž₯ μ΅œλŒ€ 10MB, μš”μ²­ 합계 μ΅œλŒ€ 30MB (κ΅¬ν˜„μ€ κΈ°μ‘΄ μƒμˆ˜μ™€ 맞좜 수 있음).
  • 지원 ν™•μž₯자: jpg, jpeg, png, webp.
  • ꢌμž₯: κΈ΄ λ³€ 4096px μ΄ν•˜ λ“±(κ΅¬ν˜„μ²΄ ꢌ고).

3) 응닡 (Response) β€” HTTP 200

Content-Type: application/json

3.1 μ΅œμƒμœ„ ꡬ쑰

{
  "request_id": "uuid",
  "source": { "total_images": 2, "filenames": ["oneline_0.png", "oneline_1.png"] },
  "score_context": { "clef": "treble", "key_signature": { "fifths": -1 }, "time_signature": "4/4", "tempo_bpm_reference": null, "divisions": 4, "source": "client" },
  "timeline": { "divisions": 4, "time_signature": "4/4", "tempo_bpm_reference": null },
  "melody": {
    "voice_id": "melody1",
    "reduction_rule": "top_note_max_two_parts",
    "events": []
  },
  "segment_map": [],
  "warnings": [],
  "meta": {}
}

3.2 ν•„λ“œ μ„€λͺ…

  • request_id: μΆ”μ Β·λ‘œκ·Έμš© UUID.
  • source: μž…λ ₯ μš”μ•½. filenames λŠ” μ—…λ‘œλ“œ μˆœμ„œμ™€ λ™μΌν•œ 원본 파일λͺ…(μ—†μœΌλ©΄ μ„œλ²„κ°€ λΆ€μ—¬ν•œ placeholder κ°€λŠ₯).
  • score_context: μš”μ²­μ„ μ •κ·œν™”Β·μ—μ½”ν•œ κ°’. source: "client" κ³ μ •(μ„œλ²„κ°€ 쑰성을 μ΄λ―Έμ§€μ—μ„œ 읽지 μ•ŠμŒμ„ λͺ…μ‹œ).
  • timeline: μ „μ—­ 리듬 해석 κΈ°μ€€. divisions λŠ” ν•œ 4λΆ„μŒν‘œ = divisions λ””λΉ„μ „ (MusicXML 관둀와 동일).
  • melody: λ³‘ν•©λœ 단일 μ„±λΆ€ κ²°κ³Ό.
    • reduction_rule: ν™”μŒ 처리 κ·œμΉ™. v1 κ³ μ • λ¬Έμžμ—΄ top_note_max_two_parts (μ΅œλŒ€ 2성뢀일 λ•Œ 졜고음만 채택).
  • segment_map: 각 μž…λ ₯ 이미지가 병합 events 의 μ–΄λŠ ꡬ간에 λŒ€μ‘ν•˜λŠ”μ§€(νŽΈμ§‘Β·ν•˜μ΄λΌμ΄νŠΈμš©). Β§3.4.
  • warnings: μΈμ‹Β·ν’ˆμ§ˆ κ²½κ³  μ½”λ“œ λ¬Έμžμ—΄ λ°°μ—΄.
  • meta: νŒŒμ΄ν”„λΌμΈ λͺ¨λ“œ, 이미지별 μ „μ²˜λ¦¬ μš”μ•½, return_debug μ‹œ 디버그 λ“±.

3.3 melody.events[] (Event)

μ‹œκ°„ μˆœμ„œλ‘œ μ •λ ¬. onset_div λŠ” 병합 ν›„ μ „μ—­ νƒ€μž„λΌμΈ κΈ°μ€€.

곡톡:

ν•„λ“œ νƒ€μž… ν•„μˆ˜ μ„€λͺ…
event_id string 예 ν΄λΌμ΄μ–ΈνŠΈ νŽΈμ§‘Β·ν‚€ μ•ˆμ •μš© 고유 ID.
type string 예 "note" | "rest"
duration_div integer 예 길이(division). μ–‘μ˜ μ •μˆ˜.
onset_div integer 예 μ‹œμž‘ μ‹œκ°(division). 0 이상 μ •μˆ˜.

type === "note" 일 λ•Œ μΆ”κ°€:

ν•„λ“œ νƒ€μž… ν•„μˆ˜ μ„€λͺ…
step string 예 C, D, …, B
octave integer 예 Scientific pitch octave.
alter integer 예 μž„μ‹œν‘œ: -1 ν”Œλž«, 0 μ—†μŒ, 1 샡, 2 더블샡 λ“±.
pitch_midi integer μ•„λ‹ˆμ˜€ 0–127. 있으면 μž¬μƒκΈ°κ°€ μš°μ„  μ‚¬μš© κ°€λŠ₯.
confidence number μ•„λ‹ˆμ˜€ 0–1 근사.
segment_order integer μ•„λ‹ˆμ˜€ 이 μ΄λ²€νŠΈκ°€ κΈ°μ›ν•œ μž…λ ₯ 이미지 순번(1-based).
bbox array μ•„λ‹ˆμ˜€ ν•΄λ‹Ή 이미지 원본 ν”½μ…€ μ’Œν‘œκ³„ [x, y, width, height] .

type === "rest" 일 λ•Œ:

  • step / octave / alter λŠ” ν¬ν•¨ν•˜μ§€ μ•ŠλŠ”λ‹€(λ˜λŠ” λͺ¨λ‘ μƒλž΅).

병합 κ·œμΉ™ (논리):

  • 이미지 k 의 첫 이벀트의 onset_div λŠ”, 직전 μ΄λ―Έμ§€λ“€μ—μ„œ κ³„μ‚°λœ λˆ„μ  길이(λ˜λŠ” μΈμ‹λœ λ§ˆλ”” 경계) 직후뢀터 이어진닀.
  • κ΅¬ν˜„μ²΄λŠ” ν”½μ…€Β·OMR 기반으둜 간격을 μΆ”μ •ν•  수 μžˆμœΌλ―€λ‘œ, λ§ˆμ§€λ§‰ 음과 λ‹€μŒ 이미지 첫 음 사이에 μž‘μ€ gap 이 생기면 warnings 에 μ½”λ“œλ‘œ 남길 수 μžˆλ‹€.

3.4 segment_map[]

각 μž…λ ₯ μ„Έκ·Έλ¨ΌνŠΈλ³„ 메타:

ν•„λ“œ νƒ€μž… μ„€λͺ…
segment_id string 예: seg1
order integer 1-based, μ—…λ‘œλ“œ μˆœμ„œ.
filename string 원본 파일λͺ….
width integer 원본 이미지 λ„ˆλΉ„.
height integer 원본 이미지 높이.
event_index_range object start / end (inclusive) β€” melody.events λ°°μ—΄ 인덱슀. 병합 κ²°κ³Όκ°€ λΉ„μ–΄ 있으면 동일 인덱슀둜 ν‘œν˜„ κ°€λŠ₯.

3.5 warnings (μ˜ˆμ‹œ μ½”λ“œ)

μ„œλ²„λŠ” ν•„μš”ν•œ 만큼 μΆ”κ°€ν•  수 μžˆλ‹€. 예:

  • staff_count_mismatch_expected_one: ν•œ μ΄λ―Έμ§€μ—μ„œ κ²€μΆœλœ staff 후보가 1이 μ•„λ‹˜.
  • line_break_between_images: 닀쀑 이미지 병합 μ‹œ 경계 νœ΄λ¦¬μŠ€ν‹± μ‚¬μš©.
  • timing_from_pixel_gaps_heuristic: 리듬이 ν”½μ…€ 간격 좔정에 의쑴.
  • annotation_overlap_detected: λ‚™μ„œΒ·μ› 등이 μŒν‘œμ™€ κ²ΉμΉ  κ°€λŠ₯.
  • neural_omr_model_unavailable: 신경망 λΉ„ν™œμ„±/μ‹€νŒ¨ ν›„ 폴백.
  • large_deskew_correction_applied: 큰 기울기 보정.

3.6 meta (ꢌμž₯ ν•˜μœ„ ν•„λ“œ)

  • pipeline_mode: string β€” 예: single_staff_v1.
  • preprocess.segments[]: 이미지별 μ „μ²˜λ¦¬ μš”μ•½(원본/μž‘μ—… 해상도, deskew 각도, μ‘°λͺ… μ •κ·œν™” μ—¬λΆ€ λ“±). κΈ°μ‘΄ κ΅¬ν˜„κ³Ό λ™μΌν•œ 정보 성격을 μœ μ§€ν•˜λ˜, ν•„λ“œλŠ” κ΅¬ν˜„μ— 맞게 μ±„μš΄λ‹€.
  • debug: options.return_debug === true 일 λ•Œλ§Œ.

4) 였λ₯˜ 응닡

HTTP 쑰건
400 파일 λˆ„λ½, score_context λˆ„λ½/νŒŒμ‹± μ‹€νŒ¨, 잘λͺ»λœ options
413 μš©λŸ‰ 초과
415 미지원 ν™•μž₯자
422 μ΄λ―Έμ§€λŠ” μžˆμœΌλ‚˜ μ‹ λ’°ν•  λ§Œν•œ 단일 μŠ€νƒœν”„λ₯Ό λ§Œλ“€ 수 μ—†μŒ, λ˜λŠ” μœ νš¨ν•œ μ΄λ²€νŠΈκ°€ μ—†μŒ
500 μ„œλ²„ λ‚΄λΆ€ 였λ₯˜

였λ₯˜ λ°”λ””λŠ” FastAPI κΈ°λ³Έ detail λ˜λŠ” μ•„λž˜ ν˜•νƒœμ˜ JSON 쀑 ν•˜λ‚˜λ‘œ 톡일할 수 μžˆλ‹€(κ΅¬ν˜„ μ‹œ ν•œ κ°€μ§€λ‘œ κ³ μ • ꢌμž₯):

{
  "error": {
    "code": "UNPROCESSABLE_STAFF_LAYOUT",
    "message": "Expected exactly one staff per image.",
    "details": { "segment_order": 2, "detected_staff_candidates": 2 }
  }
}

5) κ΅¬ν˜„Β·ν’ˆμ§ˆ λ‘œλ“œλ§΅ (μš”μ•½)

  1. 단일 μŠ€νƒœν”„ ROI μ •κ·œν™”(곑선 μ˜€μ„  보정은 단계적 λ„μž… κ°€λŠ₯).
  2. λ…ΈνŠΈΒ·μ‰Όν‘œΒ·beam λ“± 인식(λ”₯λŸ¬λ‹ + κ·œμΉ™ 폴백).
  3. ν™”μŒ β†’ 졜고음 λ¦¬λ•μ…˜.
  4. 닀쀑 이미지 μˆœμ„œ 병합 및 segment_map / segment_order μ±„μš°κΈ°.
  5. νšŒκ·€ ν…ŒμŠ€νŠΈ: sample_imgs/sample_oneline_0.png, sample_imgs/sample_oneline_chord.png 및 연속 두 μž₯ μ‹œλ‚˜λ¦¬μ˜€.

6) λͺ…μ‹œμ μœΌλ‘œ ν•˜μ§€ μ•ŠλŠ” 것 (v1)

  • 닀쀑 μŠ€νƒœν”„ 악보 νƒ€μž… μΆ”μ •(a/b/c λ“±) 및 반주 뢄리.
  • μ„±λΆ€ 라벨 soprano/alto λ“± μžλ™ μΆ”μ •.
  • MusicXML을 HTTP 응닡 본문으둜 λ°˜ν™˜.
  • μ΄λ―Έμ§€μ—μ„œ clef/key μžλ™ νŒλ…(ν΄λΌμ΄μ–ΈνŠΈ 제곡이 SSOT).

7) SSOT λ³€κ²½ 절차

μŠ€ν‚€λ§ˆΒ·μ˜λ―Έ λ³€κ²½ μ‹œ λ°˜λ“œμ‹œ λ‹€μŒμ„ ν•¨κ»˜ κ°±μ‹ ν•œλ‹€.

  1. 이 λ¬Έμ„œ (docs/analyze-api-spec.md)
  2. docs/frontend-integration-guide.md
  3. docs/analyze-response-format-examples.json