From 49f2d35571ba0c22bf2ec256623d320e20a3d0fc Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Fri, 14 Aug 2026 14:10:15 +0000 Subject: [PATCH] =?UTF-8?q?=EC=84=B1=EB=8A=A5=20=EA=B0=9C=EC=84=A0:=20sect?= =?UTF-8?q?ion=5Fharmony=EC=97=90=EC=84=9C=20zip=EC=9D=84=20=ED=99=9C?= =?UTF-8?q?=EC=9A=A9=ED=95=9C=20=EC=A4=91=EA=B0=84=20=EB=A6=AC=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=ED=95=A0=EB=8B=B9=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .jules/bolt.md | 3 + package-lock.json | 26 --------- patch.diff | 56 +++++++++++++++++++ .../chords/section_harmony.py | 14 ++--- 4 files changed, 65 insertions(+), 34 deletions(-) create mode 100644 patch.diff diff --git a/.jules/bolt.md b/.jules/bolt.md index d54cf10fc..24d3ae177 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -61,3 +61,6 @@ ## 2026-07-13 - Array.from mapping optimization **Learning:** Using `Array.from({ length: N }).map(...)` creates an intermediate array of `undefined` values which requires memory allocation and garbage collection, adding O(N) unnecessary overhead in frequently re-rendered UI components. **Action:** Use `Array.from({ length: N }, (_, index) => ...)` to map elements directly during array creation, avoiding intermediate allocations. +## 2026-08-14 - Replace zip(lst, lst[1:]) with inline tracking +**Learning:** Using `zip(lst, lst[1:])` to compute sequential changes in Python creates an intermediate sliced list and requires memory allocation, slowing down analysis of many segments in `section_harmony.py`. +**Action:** Replace `zip()` with an inline check that tracks `previous_chord` during the main iteration loop. This results in O(1) memory overhead and avoids O(N) list slicing. diff --git a/package-lock.json b/package-lock.json index cf1c991c1..2fc0f2024 100644 --- a/package-lock.json +++ b/package-lock.json @@ -955,7 +955,6 @@ "os": [ "aix" ], - "peer": true, "engines": { "node": ">=18" } @@ -973,7 +972,6 @@ "os": [ "android" ], - "peer": true, "engines": { "node": ">=18" } @@ -991,7 +989,6 @@ "os": [ "android" ], - "peer": true, "engines": { "node": ">=18" } @@ -1009,7 +1006,6 @@ "os": [ "android" ], - "peer": true, "engines": { "node": ">=18" } @@ -1027,7 +1023,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": ">=18" } @@ -1045,7 +1040,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": ">=18" } @@ -1063,7 +1057,6 @@ "os": [ "freebsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -1081,7 +1074,6 @@ "os": [ "freebsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -1099,7 +1091,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -1117,7 +1108,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -1135,7 +1125,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -1153,7 +1142,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -1171,7 +1159,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -1189,7 +1176,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -1207,7 +1193,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -1225,7 +1210,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -1243,7 +1227,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -1261,7 +1244,6 @@ "os": [ "netbsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -1279,7 +1261,6 @@ "os": [ "netbsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -1297,7 +1278,6 @@ "os": [ "openbsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -1315,7 +1295,6 @@ "os": [ "openbsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -1333,7 +1312,6 @@ "os": [ "openharmony" ], - "peer": true, "engines": { "node": ">=18" } @@ -1351,7 +1329,6 @@ "os": [ "sunos" ], - "peer": true, "engines": { "node": ">=18" } @@ -1369,7 +1346,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">=18" } @@ -1387,7 +1363,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">=18" } @@ -1405,7 +1380,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">=18" } diff --git a/patch.diff b/patch.diff new file mode 100644 index 000000000..1069c68c9 --- /dev/null +++ b/patch.diff @@ -0,0 +1,56 @@ +<<<<<<< SEARCH + durations: dict[str, float] = {} + overlapping_chords: list[str] = [] + + for seg_start, seg_end, chord in segments: + overlap = min(seg_end, section_end) - max(seg_start, section_start) + if overlap <= 0.0: + continue + durations[chord] = durations.get(chord, 0.0) + overlap + overlapping_chords.append(chord) + + chords: list[ChordDuration] = [ + {"chord": chord, "duration": duration} + for chord, duration in sorted(durations.items(), key=lambda item: (-item[1], item[0])) + ] + + main_chord = "" + for entry in chords: + if entry["chord"] != _NO_CHORD_LABEL: + main_chord = entry["chord"] + break + + chord_changes = sum( + 1 + for previous, current in zip(overlapping_chords, overlapping_chords[1:], strict=False) + if previous != current + ) + + return { +======= + durations: dict[str, float] = {} + chord_changes = 0 + previous_chord = None + + for seg_start, seg_end, chord in segments: + overlap = min(seg_end, section_end) - max(seg_start, section_start) + if overlap <= 0.0: + continue + durations[chord] = durations.get(chord, 0.0) + overlap + if previous_chord is not None and previous_chord != chord: + chord_changes += 1 + previous_chord = chord + + chords: list[ChordDuration] = [ + {"chord": chord, "duration": duration} + for chord, duration in sorted(durations.items(), key=lambda item: (-item[1], item[0])) + ] + + main_chord = "" + for entry in chords: + if entry["chord"] != _NO_CHORD_LABEL: + main_chord = entry["chord"] + break + + return { +>>>>>>> REPLACE diff --git a/services/analysis-engine/src/bandscope_analysis/chords/section_harmony.py b/services/analysis-engine/src/bandscope_analysis/chords/section_harmony.py index a61a7d001..436fb921a 100644 --- a/services/analysis-engine/src/bandscope_analysis/chords/section_harmony.py +++ b/services/analysis-engine/src/bandscope_analysis/chords/section_harmony.py @@ -84,14 +84,18 @@ def _summarize_one_section( the portion of their duration that overlaps the window. """ durations: dict[str, float] = {} - overlapping_chords: list[str] = [] + chord_changes = 0 + previous_chord = None for seg_start, seg_end, chord in segments: overlap = min(seg_end, section_end) - max(seg_start, section_start) if overlap <= 0.0: continue durations[chord] = durations.get(chord, 0.0) + overlap - overlapping_chords.append(chord) + + if previous_chord is not None and previous_chord != chord: + chord_changes += 1 + previous_chord = chord chords: list[ChordDuration] = [ {"chord": chord, "duration": duration} @@ -104,12 +108,6 @@ def _summarize_one_section( main_chord = entry["chord"] break - chord_changes = sum( - 1 - for previous, current in zip(overlapping_chords, overlapping_chords[1:], strict=False) - if previous != current - ) - return { "start_time": section_start, "end_time": section_end,