knowledge (구 Aislo-law 독립 저장소 → resources/knowledge 이관, 저장소 폐지): - 법령·행정규칙·표준시방서·교본 원문 + 기술문서 55건 + 실무 분석·종합비교 - 루트 지침 체계: README(지도)·00_운영지침·01_수집지침·02_분석지침· 03_미결_및_확인사항(교본 충돌 리스트 포함)·04_참조_법령기준_목록 - 기술문서 55건 원문 전수 검증 완료 (사방 설계홍수량 법정 기준 등 반영) - 정리: CAD·오피스 잔재 142건, 중복 zip 7건(413MB), 빈 폴더 30개 제거 resources 그룹 재편 (이름순 그룹핑): - app_branding(구 prog_icon.jpg)·app_policies(구 legal)· data_global_contours(구 grobal_contours)·data_rainfall_idf_cache(구 wamis_contours)· template_2dDrawing(구 dwg_analysis/templete — 오타 교정, 상수·경로 동기화) - dwg_analysis(분석 완료 1.8GB)·templates(빈 폴더)·templete_calc_cost.xlsx 삭제 - 참조 코드 5파일 경로 수정 + 프론트 재빌드 (구 경로 잔존 0) - .gitignore: resources 추적 전환, national_contours.gpkg(22GB) 영구 제외 - .env: knowledge 수집용 API 정보 주석 통합 (KCSC·법령센터·조달청 제비율) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
82 lines
3.0 KiB
Python
82 lines
3.0 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/."""
|
|
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""
|
|
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/ 로컬화")
|