Spaces:
Sleeping
Sleeping
Analyze API Spec (λ¨μΌ μ€νν / v1)
μ΄ λ¬Έμλ **λ¨μΌ μ§μ€ 곡κΈμ(SSOT)**μ΄λ€. ꡬνΒ·ν μ€νΈΒ·νλ‘ νΈ κ³μ½μ μ¬κΈ° μ μν μ€ν€λ§μ μλ―Έλ₯Ό λ°λ₯Έλ€.
- μλν¬μΈνΈ:
POST /analyze - μΆλ ₯: λͺ¨λ°μΌ/μΉμμ λ°λ‘ μΈ μ μλ JSON ν λ©μ΄λ¦¬(MusicXML λ±μ HTTP μλ΅μ ν¬ν¨νμ§ μμ; μλ² λ΄λΆ μ μ© κ°λ₯).
- μμ μλ΅ λ¬Άμ:
docs/analyze-response-format-examples.json
1) μ ν λ²μ (μ¬ν λͺ¨λ)
1.1 μ λ ₯ μ΄λ―Έμ§μ λν κ°μ
- ν μ΄λ―Έμ§ = μ€μ (staff) μ νν ν μ€λ§ μλ€κ³ κ°μ νλ€.
- 볡μ μ€(μ: νΌμλ Έ λ보ν), ν©μ°½ λ€μ€ μ€νν λ±μ μ΄ μ€νμ λ²μ λ°μ΄λ€.
- μ¬μ§μ μΈμ μ
보λ₯Ό μΉ΄λ©λΌλ‘ μ°μ λ€ ν¬λ‘ν κ²μΌ μ μλ€.
- μ’ μ΄ νμ΄μ§, κΈ°μΈκΈ°, μ‘°λͺ , μκΈμ¨ λμ λ±μ΄ μμ μ μμΌλ©°, μλ²λ μ μ²λ¦¬(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) ꡬνΒ·νμ§ λ‘λλ§΅ (μμ½)
- λ¨μΌ μ€νν ROI μ κ·ν(곑μ μ€μ 보μ μ λ¨κ³μ λμ κ°λ₯).
- λ ΈνΈΒ·μΌνΒ·beam λ± μΈμ(λ₯λ¬λ + κ·μΉ ν΄λ°±).
- νμ β μ΅κ³ μ 리λμ .
- λ€μ€ μ΄λ―Έμ§ μμ λ³ν© λ°
segment_map/segment_orderμ±μ°κΈ°. - νκ· ν
μ€νΈ:
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 λ³κ²½ μ μ°¨
μ€ν€λ§Β·μλ―Έ λ³κ²½ μ λ°λμ λ€μμ ν¨κ» κ°±μ νλ€.
- μ΄ λ¬Έμ (
docs/analyze-api-spec.md) docs/frontend-integration-guide.mddocs/analyze-response-format-examples.json