Update handlers/template/doc_template_analyzer.py
This commit is contained in:
@@ -1,3 +1,148 @@
|
|||||||
# 문서 템플릿 분석기
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
문서 템플릿 분석기 v5.1 (오픈 레이어)
|
||||||
|
|
||||||
|
역할: tools/ 모듈들을 조합하여 HWPX → 템플릿 정보 추출
|
||||||
|
- 특정 영역 파싱 로직은 없음 (모두 tools에 위임)
|
||||||
|
- 디폴트값 생성 없음 (tools가 None 반환하면 결과에서 제외)
|
||||||
|
- 사용자 추가 사항(config.json) → 템플릿에도 반영
|
||||||
|
|
||||||
|
구조:
|
||||||
|
tools/
|
||||||
|
page_setup.py 짠7 용지/여백
|
||||||
|
font.py 짠3 글꼴
|
||||||
|
char_style.py 짠4 글자 모양
|
||||||
|
para_style.py 짠5 문단 모양
|
||||||
|
border_fill.py 짠2 테두리/배경
|
||||||
|
table.py 짠6 표
|
||||||
|
header_footer.py 짠8 머릿말/꼬릿말 스타일 및 매기기/글머리표
|
||||||
|
image.py 이미지
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from .tools import (
|
||||||
|
page_setup,
|
||||||
|
font,
|
||||||
|
char_style,
|
||||||
|
para_style,
|
||||||
|
border_fill,
|
||||||
|
table,
|
||||||
|
header_footer,
|
||||||
|
section,
|
||||||
|
style_def,
|
||||||
|
numbering,
|
||||||
|
image,
|
||||||
|
content_order,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class DocTemplateAnalyzer:
|
class DocTemplateAnalyzer:
|
||||||
pass
|
"""HWPX → 템플릿 추출 오픈 레이어"""
|
||||||
|
|
||||||
|
# ================================================================
|
||||||
|
# Phase 1: 추출 (모든 tools 호출)
|
||||||
|
# ================================================================
|
||||||
|
|
||||||
|
def analyze(self, parsed: dict) -> dict:
|
||||||
|
"""HWPX parsed 결과에서 템플릿 구조 추출.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
parsed: processor.py가 HWPX를 분석한 결과 dict.
|
||||||
|
raw_xml, section_xml, header_xml, footer_xml,
|
||||||
|
tables, paragraphs 등 포함.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
추출된 항목만 포함하는 dict (None항목은 제외).
|
||||||
|
"""
|
||||||
|
raw_xml = parsed.get("raw_xml", {})
|
||||||
|
|
||||||
|
extractors = {
|
||||||
|
"page": lambda: page_setup.extract(raw_xml, parsed),
|
||||||
|
"fonts": lambda: font.extract(raw_xml, parsed),
|
||||||
|
"char_styles": lambda: char_style.extract(raw_xml, parsed),
|
||||||
|
"para_styles": lambda: para_style.extract(raw_xml, parsed),
|
||||||
|
"border_fills": lambda: border_fill.extract(raw_xml, parsed),
|
||||||
|
"tables": lambda: table.extract(raw_xml, parsed),
|
||||||
|
"header": lambda: header_footer.extract_header(raw_xml, parsed),
|
||||||
|
"footer": lambda: header_footer.extract_footer(raw_xml, parsed),
|
||||||
|
"section": lambda: section.extract(raw_xml, parsed),
|
||||||
|
"styles": lambda: style_def.extract(raw_xml, parsed),
|
||||||
|
"numbering": lambda: numbering.extract(raw_xml, parsed),
|
||||||
|
"images": lambda: image.extract(raw_xml, parsed),
|
||||||
|
"content_order":lambda: content_order.extract(raw_xml, parsed),
|
||||||
|
}
|
||||||
|
|
||||||
|
result = {}
|
||||||
|
for key, extractor in extractors.items():
|
||||||
|
try:
|
||||||
|
value = extractor()
|
||||||
|
if value is not None:
|
||||||
|
result[key] = value
|
||||||
|
except Exception as e:
|
||||||
|
# 개별 tool 실패 시 로그만, 전체 중단 안 함
|
||||||
|
result.setdefault("_errors", []).append(
|
||||||
|
f"{key}: {type(e).__name__}: {e}"
|
||||||
|
)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
# ================================================================
|
||||||
|
# Phase 2: 사용자 추가 사항 병합
|
||||||
|
# ================================================================
|
||||||
|
|
||||||
|
def merge_user_config(self, template_info: dict,
|
||||||
|
config: dict) -> dict:
|
||||||
|
"""config.json의 사용자 요청 사항을 template_info에 병합.
|
||||||
|
|
||||||
|
사용자 문서 유형 추가 시 지정된 커스텀 사항 반영:
|
||||||
|
- 강조 색상 오버라이드
|
||||||
|
- 글꼴 오버라이드
|
||||||
|
- 제목 크기 오버라이드
|
||||||
|
- 기타 레이아웃 커스텀
|
||||||
|
|
||||||
|
이 병합 결과는 style.json에 저장되고,
|
||||||
|
이후 template.html 생성 시에도 반영됨.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
template_info: analyze()의 결과
|
||||||
|
config: config.json 내용
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
병합된 template_info (원본 수정됨)
|
||||||
|
"""
|
||||||
|
user_overrides = config.get("user_overrides", {})
|
||||||
|
if not user_overrides:
|
||||||
|
return template_info
|
||||||
|
|
||||||
|
# 모든 사용자 설정을 template_info에 기록
|
||||||
|
template_info["user_overrides"] = user_overrides
|
||||||
|
|
||||||
|
return template_info
|
||||||
|
|
||||||
|
|
||||||
|
# ================================================================
|
||||||
|
# Phase 3: template_info → style.json 저장
|
||||||
|
# ================================================================
|
||||||
|
|
||||||
|
def save_style(self, template_info: dict,
|
||||||
|
save_path: Path) -> Path:
|
||||||
|
"""template_info를 style.json으로 저장.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
template_info: analyze() + merge_user_config() 결과
|
||||||
|
save_path: 저장 경로 (예: templates/user/{doc_type}/style.json)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
저장된 파일 경로
|
||||||
|
"""
|
||||||
|
save_path = Path(save_path)
|
||||||
|
save_path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
with open(save_path, 'w', encoding='utf-8') as f:
|
||||||
|
json.dump(template_info, f, ensure_ascii=False, indent=2)
|
||||||
|
|
||||||
|
return save_path
|
||||||
|
|||||||
Reference in New Issue
Block a user