Files
Aislo/resources/knowledge/original/_pipeline/fix_law_images.py
T
eomsangdonandClaude Opus 5 4cb9b15939 style: 저장소 전체 포맷터 일괄 적용 (prettier·biome·ruff)
파일마다 포맷 폭이 달라(≈80 대 100) 한 줄만 고쳐도 포맷터가 무관한 줄을 대량
재포맷했음. 사용자 지시로 전체를 한 번에 맞춤. 코드 동작 변경 없음 — 포맷만.

- 프론트엔드 `.ts/.css/.html` → 저장소 prettier (`.prettierrc`, printWidth 100)
- `B07_DesignDetail/openwebcad/**` → 자체 biome (tab 들여쓰기·single quote·lineWidth 100).
  `biome format` 만 사용 — `biome lint --write` 는 포맷 아닌 코드 수정까지 하므로 제외
- 파이썬 → `ruff format` (엔진 코드는 이미 정합, resources·scratch 스크립트 24개만 변경)

두 포맷터가 서로 되돌리지 않도록 `.prettierignore` 신규 — openwebcad 와 빌드·산출물
폴더를 prettier 대상에서 뺌. `.prettierrc` 에 `endOfLine: "auto"` 추가 — 기본값 `lf` 가
`core.autocrlf=true` 로 받은 CRLF 파일을 매번 전부 다시 써서 `--list-different` 가
실제 포맷 차이를 가리고 있었음.

검증: `tsc --noEmit` 통과(루트·openwebcad 둘 다), pytest 349 passed / 17 skipped /
0 failed, CAD vitest 87건 중 81 passed / 6 failed(laptop-sub 기준선과 동일, 회귀 없음).
포맷터 재실행 시 prettier·biome 모두 변경 0건.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 07:08:24 +09:00

99 lines
3.1 KiB
Python

# -*- coding: utf-8 -*-
"""법령 본문 md의 원시 <img src="law.go.kr/..."> 태그를 pic/로 내려받아 md 이미지 참조로 교체.
법령 XML 조문·개정문에 인라인으로 박힌 수식·그림 이미지 처리.
이미지는 각 명칭 폴더의 pic/ 에 저장하고 md에서 ../pic 상대참조.
"""
import re, sys, time, urllib.request
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
UA = {"User-Agent": "Mozilla/5.0"}
# src="URL" 형식과 id="flSeq" 형식(내부 이미지) 모두 처리
IMG = re.compile(r"<img\b([^>]*?)/?>")
SRC = re.compile(r'src="([^"]+)"')
IID = re.compile(r'id="(\d+)"')
EXT = {
b"\x89PNG": ".png",
b"\xff\xd8\xff": ".jpg",
b"GIF8": ".gif",
b"BM": ".bmp",
b"II*\x00": ".tif",
b"MM\x00*": ".tif",
}
def sniff(b):
for sig, ext in EXT.items():
if b.startswith(sig):
return ext
return ".png"
def download(url):
u = url.replace("http://", "https://")
for _ in range(3):
try:
with urllib.request.urlopen(urllib.request.Request(u, headers=UA), timeout=40) as r:
b = r.read()
if b and len(b) > 100:
return b
except Exception:
time.sleep(1.5)
return None
def fix(md_path):
"""md 파일: <img> → pic/ 저장 + ![그림](../pic/..) 참조. 폴더는 명칭 폴더의 pic/."""
text = md_path.read_text(encoding="utf-8")
if "<img" not in text and "</img" not in text:
return 0
# 명칭 폴더 = md가 명칭폴더 바로 아래(현행_/교본시점_/CHANGELOG)면 그 폴더, 별표/첨부면 상위
folder = md_path.parent
picdir = folder / "pic"
seq = [0]
def repl(m):
attrs = m.group(1)
ms = SRC.search(attrs)
mi = IID.search(attrs)
if ms:
url = ms.group(1)
elif mi:
url = f"https://www.law.go.kr/LSW/flDownload.do?flSeq={mi.group(1)}"
else:
return m.group(0)
blob = download(url)
if not blob:
return "〔그림: 다운로드 실패〕"
seq[0] += 1
picdir.mkdir(parents=True, exist_ok=True)
fn = f"{md_path.stem}_img{seq[0]}{sniff(blob)}"
(picdir / fn).write_bytes(blob)
return f"![그림](<pic/{fn}>)"
new = IMG.sub(repl, text)
# 부칙 등에서 여는 태그와 분리돼 남은 고아 닫는 태그 제거(단독 줄/인용줄 포함)
new = re.sub(r"^>?\s*</img>\s*$", ">", new, flags=re.M)
new = new.replace("</img>", "")
if new != text:
md_path.write_text(new, encoding="utf-8")
return seq[0]
if __name__ == "__main__":
mds = (
list(ROOT.rglob("현행_*.md"))
+ list(ROOT.rglob("교본시점_*.md"))
+ list(ROOT.rglob("CHANGELOG.md"))
)
mds = [m for m in mds if "임도기술교본" not in str(m) and "_pipeline" not in str(m)]
tot = 0
for md in sorted(mds):
n = fix(md)
if n:
tot += n
print(f" {n}{md.parent.parent.name[:30]}/{md.name}")
print(f"\n법령 본문 이미지 {tot}장 → pic/ 로컬화")