"""입 박스 민감도 스윕 — 문서에 실린 범위를 **한 커맨드로** 재현한다.

왜 스크립트로 박나: "박스를 ±0.02 씩 상하좌우로 민 5판" 이라는 **산문 설명이 재현자마다 다르게
해석됐다**(독립 verifier 가 다른 5판을 만들어 다른 끝값을 얻었다 · 2026-08-08). 방법이 문장인 한
같은 일이 반복된다 ⇒ 이동 벡터를 코드에 고정한다.

5판 = 원위치 · +x · −x · +y · −y (정규화 좌표에서 +y = 화면 아래쪽). 박스 크기는 안 바꾼다
(확대/축소를 섞으면 "민 것" 과 "키운 것" 이 한 범위에 뒤섞인다).
"""
import importlib.util
import json

spec = importlib.util.spec_from_file_location("lr", "lipsync_ratio.py")
lr = importlib.util.module_from_spec(spec)
spec.loader.exec_module(lr)

D = 0.02
SHIFTS = [(0, 0), (D, 0), (-D, 0), (0, D), (0, -D)]

# ★박스·skip·end·가창 구간은 **`mouth_boxes.json` 에서 읽는다** — 여기 하드코딩하면 SoT 가 둘이 되고,
#   한쪽만 고쳤을 때 조용히 갈린다(정확히 이 실험이 계측 함정으로 세 번 겪은 실패 모드다).
BOXES = json.load(open("mouth_boxes.json"))
SUNG = [tuple(w) for w in BOXES["_singing_windows"]["sung"]]
CASES = [
    ("LTX_5a", "out_5a_ltx_j26512.mp4", None),
    ("H3_5a", "out_5a_h3_j26509.mp4", None),
    ("H3_5c", "out_5c_h3_j26511.mp4", SUNG),
    ("LTX_5c", "out_5c_ltx_j26514.mp4", SUNG),
]

if __name__ == "__main__":
    out = {}
    for name, video, win in CASES:
        cfg = BOXES[video]
        base, skip, end = tuple(cfg["mouth"]), cfg["skip"], cfg["end"]
        pairs, boxes = [], []
        for dx, dy in SHIFTS:
            b = tuple(round(v + (dx if i % 2 == 0 else dy), 4) for i, v in enumerate(base))
            r, _ = lr.ratio(video, b, skip, windows=win, end_s=end)
            rr, _ = lr.ratio(video, b, skip, reverse=True, windows=win, end_s=end)
            pairs.append([round(r, 2), round(rr, 2)])
            boxes.append(list(b))
        real = [p[0] for p in pairs]
        rev = [p[1] for p in pairs]
        out[name] = {
            "boxes": boxes, "pairs": pairs,
            "실제": f"{min(real):.2f}~{max(real):.2f}",
            "역전": f"{min(rev):.2f}~{max(rev):.2f}",
            "실제우위": f"{sum(1 for a, c in pairs if a > c)}/5",
        }
        print(f"{name}: 실제 {out[name]['실제']} · 역전 {out[name]['역전']} · "
              f"실제우위 {out[name]['실제우위']}  쌍={pairs}")
    json.dump(out, open("box_sweep.json", "w"), ensure_ascii=False, indent=1)
    print("→ box_sweep.json")
