2026년 8월 19일 수요일 오늘의 개발과 자동화 실험을 기록한다.

회사에서 보고서나 발표 자료를 만들 때 가장 피곤한 일 중 하나는 바로 '사내 템플릿 양식 맞추기'다. 컬러 팔레트, 폰트 종류, 제목 크기, 줄 간격, 카드 박스 여백 등 CI/BI 가이드라인은 깐깐한데, 매번 사람이 일일이 수작업으로 맞추다 보면 시간이 훌쩍 지나간다. 😫

"요즘 AI가 PPT도 잘 만든다는데, 왜 회사 템플릿만 들어가면 디자인이 제멋대로 깨질까?"

AI에게 "우리 회사 스타일로 만들어줘"라고 말로 설명하는 것은 한계가 있다. 가장 확실한 해결책은 기존 사내 PPTX 템플릿을 역공학(Reverse-Engineering)하여 정확한 디자인 토큰과 레이아웃 규칙을 담은 'JSON 스타일 가이드'로 추출해 두는 것이다.


1. 왜 PPT 템플릿을 JSON 스타일 가이드로 뽑아야 할까?

AI 기반 슬라이드 생성 도구를 써본 사람이라면 누구나 공감할 것이다. 텍스트 초안은 그럴듯하게 나오지만, 회사 공식 템플릿에 옮겨 담는 순간 레이아웃이 어그러지고 폰트와 컬러가 제각각으로 튄다.

PPTX to JSON 스타일 가이드 추출 파이프라인 개념도
▲ 사내 PPT 템플릿 JSON 스타일가이드 추출 아키텍처

시각적 모호성을 기계 가독형 데이터로 변환

사람은 PPT를 눈으로 보고 "여백이 넉넉하고 짙은 네이비 톤이네"라고 감각적으로 이해하지만, 코드와 LLM은 수치화된 데이터가 필요하다. 슬라이드 크기(16:9 = 960x540pt), 안전 여백(Safe Margin), 주요 테마 컬러의 HEX 코드, 헤딩과 본문의 pt 단위 글꼴 크기를 JSON 형태로 규격화하면 AI가 디자인 규칙을 100% 오차 없이 지킬 수 있게 된다. 💡


2. 하이브리드 추출 파이프라인: Code + Vision AI

PPTX 파일은 사실상 XML 파일들이 압축된 zip 아카이브다. 따라서 가장 정밀한 방법은 코드(python-pptx)를 통한 정밀 수치 추출과 멀티모달 Vision AI를 통한 시각적 컴포넌트 분석을 결합하는 '하이브리드 방식'이다.

python-pptx XML 테마 및 레이아웃 파싱 흐름 슬라이드
▲ python-pptx 및 OpenXML 파싱을 통한 테마/좌표 추출 흐름

1단계: python-pptx로 테마 XML 정밀 파싱

우선 python-pptx 라이브러리를 활용해 PPTX 내부에 내장된 슬라이드 마스터와 테마 XML(ppt/theme/theme1.xml)을 직접 읽어온다.

  • 테마 색상 팔레트: a:clrScheme 태그를 파싱하여 기본 텍스트, 배경색, Accent 1~6의 정확한 16진수 HEX 컬러를 추출한다.
  • 폰트 체계: a:fontScheme에서 라틴/한글 제목 및 본문 기본 폰트 패밀리를 가져온다.
  • 슬라이드 마스터 레이아웃: 각 레이아웃(표지, 본문 1단, 본문 2단, 비교표 등)의 Placeholder 좌표(left, top, width, height)를 추출한다.

2단계: Vision AI로 디자인 뉘앙스 및 컴포넌트 규칙 역공학

XML만으로는 "카드 박스의 테두리 둥글기", "배지의 강조 스타일", "슬라이드당 적정 글자 수" 같은 고차원 디자인 의도를 완벽히 파악하기 어렵다. 이때 슬라이드를 고화질 이미지로 변환한 뒤 멀티모달 LLM(Gemini / Claude)에 전달하여 세부 뉘앙스를 JSON으로 정제한다.


3. 표준 JSON 스타일 가이드 스키마 구조

이렇게 추출된 데이터를 하나로 통합하면, 프론트엔드의 디자인 시스템(Design Tokens)과 완벽하게 호환되는 style_guide.json이 완성된다.

표준 JSON 스타일 가이드 스키마 구조 인포그래픽
▲ 표준 JSON 스타일가이드 스키마 및 디자인 토큰 구성
{
  "meta": {
    "template_name": "Acme_Corporate_2026",
    "aspect_ratio": "16:9",
    "slide_size": { "width_pt": 960, "height_pt": 540 }
  },
  "colors": {
    "primary": "#0F172A",
    "secondary": "#2563EB",
    "accent": "#38BDF8",
    "surface": "#F8FAFC",
    "text": { "primary": "#1E293B", "muted": "#64748B" },
    "border": "#E2E8F0"
  },
  "typography": {
    "title": { "fontFamily": "Pretendard", "sizePt": 36, "weight": 700, "color": "#0F172A" },
    "section": { "fontFamily": "Pretendard", "sizePt": 24, "weight": 700, "color": "#2563EB" },
    "body": { "fontFamily": "Pretendard", "sizePt": 14, "weight": 400, "lineHeight": 1.5, "color": "#1E293B" },
    "caption": { "fontFamily": "Pretendard", "sizePt": 11, "weight": 400, "color": "#64748B" }
  },
  "layout_grid": {
    "safe_margin": { "top": 48, "bottom": 48, "left": 56, "right": 56 },
    "card_gap": 16
  },
  "content_rules": {
    "max_bullets_per_slide": 4,
    "max_words_per_bullet": 15,
    "title_max_chars": 28
  }
}

4. 추출한 JSON 스타일 가이드로 AI 보고서 자동 생성하기

완성된 JSON 스타일 가이드는 AI 보고서 파이프라인의 핵심 두뇌 역할을 한다.

JSON 기반 AI 슬라이드 자동 생성 워크플로우 인포그래픽
▲ LLM 프롬프트 제약 및 python-pptx 렌더링 파이프라인

1) AI 에이전트 텍스트 초안 제어 (텍스트 오버플로 방지)

LLM에게 보고서 슬라이드 본문을 작성시킬 때 content_rules를 시스템 프롬프트로 주입한다. "슬라이드당 불릿은 최대 4개, 각 불릿은 15단어 이내로 요약할 것"이라는 명확한 제약이 들어가기 때문에, 텍스트가 박스 바깥으로 넘쳐 흘러내리는 현상을 사전에 100% 방지할 수 있다.

2) python-pptx 렌더러와 1:1 매핑

파이썬 스크립트는 원시 데이터를 읽어 슬라이드를 만들 때 style_guide.json의 수치(색상 HEX, 폰트 pt, 여백 좌표)를 그대로 적용한다. 사내 템플릿과 한 픽셀의 오차도 없는 완벽한 공식 보고서 PPTX가 단 몇 초 만에 자동으로 렌더링된다. 🚀


5. 그대로 따라하는 실전 코드 & 프롬프트 예제

이제 여러분의 환경에서 바로 복사해 실행할 수 있는 전체 실무 코드를 공유한다.

사전 준비

pip install python-pptx lxml

예제 1. PPTX 템플릿에서 스타일 가이드 추출하기 (extract_style.py)

사내 PPTX 파일을 읽어 테마 색상(HEX)과 폰트, 슬라이드 크기를 JSON으로 추출하는 파이썬 스크립트다.

import json
from pptx import Presentation
from pptx.opc.constants import RELATIONSHIP_TYPE as RT
from pptx.oxml import parse_xml

def extract_pptx_style_guide(pptx_path: str, output_json: str):
    prs = Presentation(pptx_path)
    
    style_guide = {
        "meta": {
            "template_name": pptx_path.split("/")[-1].replace(".pptx", ""),
            "slide_size": {
                "width_pt": prs.slide_width.pt,
                "height_pt": prs.slide_height.pt
            }
        },
        "colors": {},
        "typography": {},
        "layouts": []
    }
    
    # 1. 테마 XML 파싱 (색상 및 폰트)
    theme_part = prs.part.part_related_by(RT.THEME)
    theme_root = parse_xml(theme_part.blob)
    
    # 테마 색상 추출 (a:clrScheme)
    for clr in theme_root.xpath('.//a:clrScheme/*'):
        tag_name = clr.tag.split('}')[-1]
        srgb = clr.xpath('.//a:srgbClr/@val')
        if srgb:
            style_guide["colors"][tag_name] = f"#{srgb[0]}"
            
    # 테마 폰트 추출 (a:fontScheme)
    major_font = theme_root.xpath('.//a:fontScheme/a:majorFont/a:latin/@typeface')
    minor_font = theme_root.xpath('.//a:fontScheme/a:minorFont/a:latin/@typeface')
    if major_font:
        style_guide["typography"]["major_font"] = major_font[0]
    if minor_font:
        style_guide["typography"]["minor_font"] = minor_font[0]
        
    # 2. 마스터 레이아웃 Placeholder 좌표 추출
    for idx, layout in enumerate(prs.slide_layouts):
        layout_item = {"index": idx, "name": layout.name, "placeholders": []}
        for ph in layout.placeholders:
            layout_item["placeholders"].append({
                "name": ph.name,
                "type": str(ph.ph_type),
                "left_pt": ph.left.pt,
                "top_pt": ph.top.pt,
                "width_pt": ph.width.pt,
                "height_pt": ph.height.pt
            })
        style_guide["layouts"].append(layout_item)
        
    with open(output_json, "w", encoding="utf-8") as f:
        json.dump(style_guide, f, indent=2, ensure_ascii=False)
    print(f"✅ 스타일 가이드 추출 성공: {output_json}")

if __name__ == "__main__":
    # 회사 템플릿 경로를 넣고 실행하세요
    extract_pptx_style_guide("company_template.pptx", "style_guide.json")

예제 2. Vision AI에게 시각 디자인 규칙 보강 요청하기

슬라이드 대표 페이지 캡처 이미지와 위에서 추출한 style_guide.json을 함께 멀티모달 LLM(Gemini / Claude)에 전달하는 프롬프트다.

[역할] 당신은 프레젠테이션 디자인 시스템 분석 전문가입니다.
[입력] 첨부된 회사 PPT 대표 슬라이드 캡처 이미지와 기초 style_guide.json
[요청사항]
1. 이미지에 나타난 '카드(Card)' 컴포넌트의 배경색, 테두리 색상, 모서리 둥글기(radius), 안쪽 패딩(padding)을 분석해 components.card 객체로 정의해 주세요.
2. 텍스트 박스가 넘치지 않도록 불릿당 최대 권장 글자 수와 불릿 개수를 content_rules에 추가해 주세요.
3. 완벽하게 구조화된 최종 style_guide.json만 JSON 코드 블록으로 출력해 주세요.

예제 3. JSON 스타일 가이드로 새 슬라이드 자동 생성하기 (generate_slide.py)

정제된 style_guide.json을 읽어 회사 CI/BI 컬러와 폰트 크기가 100% 적용된 새 보고서 슬라이드를 자동 생성하는 코드다.

import json
from pptx import Presentation
from pptx.util import Pt, Inches
from pptx.dml.color import RGBColor

def hex_to_rgb(hex_str: str) -> RGBColor:
    hex_str = hex_str.lstrip("#")
    return RGBColor(*(int(hex_str[i:i+2], 16) for i in (0, 2, 4)))

def generate_report_from_style_guide(guide_path: str, output_pptx: str):
    with open(guide_path, "r", encoding="utf-8") as f:
        guide = json.load(f)
        
    prs = Presentation()
    prs.slide_width = Pt(guide["meta"]["slide_size"]["width_pt"])
    prs.slide_height = Pt(guide["meta"]["slide_size"]["height_pt"])
    
    # 1. 빈 슬라이드 추가
    blank_layout = prs.slide_layouts[6]
    slide = prs.slides.add_slide(blank_layout)
    
    # 2. 스타일 가이드 색상 및 폰트 적용
    primary_color = hex_to_rgb(guide["colors"].get("accent1", "#0F172A"))
    font_name = guide["typography"].get("major_font", "Pretendard")
    
    # 3. 제목 상자 배치
    title_box = slide.shapes.add_textbox(Inches(0.8), Inches(0.8), Inches(11.7), Inches(1.0))
    tf = title_box.text_frame
    p = tf.paragraphs[0]
    p.text = "2026년 3분기 AI 사업 성과 보고서"
    p.font.name = font_name
    p.font.size = Pt(32)
    p.font.bold = True
    p.font.color.rgb = primary_color
    
    prs.save(output_pptx)
    print(f"🎉 회사 규격 맞춤 보고서 생성 완료: {output_pptx}")

if __name__ == "__main__":
    generate_report_from_style_guide("style_guide.json", "quarterly_report.pptx")

총평

  • 정확도: XML 직접 파싱과 Vision AI를 조합해 회사 템플릿의 색상 코드와 폰트 규격을 100% 무손실로 복제할 수 있다.
  • 자동화 편의성: JSON 표준 스키마 형태로 한 번 뽑아두면 어떤 AI 프롬프트나 파이썬 스크립트에도 손쉽게 재사용이 가능하다.
  • 실무 활용도: 디자이너에게 매번 템플릿 서식을 문의할 필요 없이, 엔지니어링 단계에서 기업 CI/BI를 엄격하게 지키는 보고서 생성 파이프라인을 구축할 수 있다.

기존에 수작업으로 PPT 서식을 복사하고 붙여넣던 비효율을 완전히 끝낼 수 있는 가장 깔끔한 방법이다. 회사 템플릿이 변경되더라도 추출 스크립트 한 번만 돌려 JSON만 갱신하면 모든 자동화 파이프라인이 즉시 동기화되니, 사내 보고서 자동화를 준비 중이라면 반드시 도입해 볼 만하다.