harness/plugins/zioinfo/skills/proposal-builder-orchestrator/scripts/build_deck.py
DESKTOP-TKLFCPR\ython 6caf43e1ed feat!: v2.0.0 — 4개 플러그인 zioinfo 단일 통합 + 최신 플러그인 기술 적용
- harness·zio-harness·proposal-builder·zioinfo → plugins/zioinfo (git mv 히스토리 보존)
- 스킬 4·커맨드 3(/zioinfo:pmo·proposal·wiki)·에이전트 15·graphify 훅·knowledge 통합
- 신규: /zioinfo:wiki (graphify LLM wiki — graphify-out/wiki/ 커뮤니티별 아티클)
- 신규: ZIO WISE 테마 (themes/zioinfo.json, experimental)
- manifest 최신화: $schema·displayName(ZIO INFOTECH Suite)·experimental.themes
- marketplace.json 단일 엔트리, 루트 plugin.json 제거
- CLAUDE.md·PROJECT_MAP·docs/plugins.md·README 3종·CHANGELOG·설치가이드 pptx 재구성

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 20:16:36 +09:00

92 lines
4.2 KiB
Python

#!/usr/bin/env python3
"""
build_deck.py — 템플릿 스타일 + 제안서 콘텐츠(JSON) → proposal.pptx 생성.
deck-designer가 프로젝트별 콘텐츠 JSON만 주입해 재생성 가능한 골격 스크립트.
디자인 시스템(색/폰트)·선 아이콘(SVG는 사전 PNG/EMF 변환 또는 도형)·도식은 deck-designer가 채운다.
사용: python build_deck.py --content content.json [--template template.pptx] --out proposal.pptx
content.json 예:
{
"design": {"primary":"1F4E79","accent":"2E9BD6","text":"222222","font_ko":"맑은 고딕"},
"slides": [
{"layout":"title", "title":"○○시스템 구축 제안서", "subtitle":"제안사 / 2026"},
{"layout":"section", "title":"1. 사업 이해"},
{"layout":"content", "title":"추진 전략", "bullets":["...","..."]},
{"layout":"diagram", "title":"추진 체계도", "note":"도형은 deck-designer가 보강"}
]
}
의존: pip install python-pptx · 외부 호출 없음.
"""
import sys, json, argparse
def hex_color(s):
from pptx.dml.color import RGBColor
return RGBColor.from_string(s)
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--content", required=True)
ap.add_argument("--template")
ap.add_argument("--out", default="proposal.pptx")
a = ap.parse_args()
try:
from pptx import Presentation
from pptx.util import Inches, Pt
from pptx.enum.text import PP_ALIGN
except ImportError:
print("python-pptx 미설치 → pip install python-pptx", file=sys.stderr); sys.exit(2)
with open(a.content, encoding="utf-8") as f:
data = json.load(f)
design = data.get("design", {})
primary = design.get("primary", "1F4E79")
accent = design.get("accent", "2E9BD6")
text_c = design.get("text", "222222")
font_ko = design.get("font_ko", "맑은 고딕")
prs = Presentation(a.template) if a.template else Presentation()
blank = prs.slide_layouts[6] if len(prs.slide_layouts) > 6 else prs.slide_layouts[-1]
W, H = prs.slide_width, prs.slide_height
def add_text(slide, txt, left, top, width, height, size, color, bold=False, align=PP_ALIGN.LEFT):
tb = slide.shapes.add_textbox(left, top, width, height)
tf = tb.text_frame; tf.word_wrap = True
p = tf.paragraphs[0]; p.alignment = align
r = p.add_run(); r.text = txt
r.font.size = Pt(size); r.font.bold = bold
r.font.name = font_ko; r.font.color.rgb = hex_color(color)
return tb
for s in data.get("slides", []):
slide = prs.slides.add_slide(blank)
layout = s.get("layout", "content")
title = s.get("title", "")
if layout == "title":
# 상단 컬러 바
bar = slide.shapes.add_shape(1, 0, 0, W, Inches(2.2))
bar.fill.solid(); bar.fill.fore_color.rgb = hex_color(primary); bar.line.fill.background()
add_text(slide, title, Inches(0.8), Inches(0.7), W - Inches(1.6), Inches(1.2), 36, "FFFFFF", True)
if s.get("subtitle"):
add_text(slide, s["subtitle"], Inches(0.8), Inches(2.5), W - Inches(1.6), Inches(0.8), 18, text_c)
elif layout == "section":
bar = slide.shapes.add_shape(1, 0, Inches(2.6), W, Inches(1.6))
bar.fill.solid(); bar.fill.fore_color.rgb = hex_color(accent); bar.line.fill.background()
add_text(slide, title, Inches(0.8), Inches(2.9), W - Inches(1.6), Inches(1.0), 30, "FFFFFF", True)
else:
# 제목 + 강조 underline
add_text(slide, title, Inches(0.7), Inches(0.5), W - Inches(1.4), Inches(0.9), 26, primary, True)
ul = slide.shapes.add_shape(1, Inches(0.7), Inches(1.35), Inches(2.2), Pt(3))
ul.fill.solid(); ul.fill.fore_color.rgb = hex_color(accent); ul.line.fill.background()
top = Inches(1.8)
for b in s.get("bullets", []):
add_text(slide, "" + b, Inches(0.9), top, W - Inches(1.8), Inches(0.6), 16, text_c)
top += Inches(0.55)
if s.get("note"):
add_text(slide, s["note"], Inches(0.9), H - Inches(0.8), W - Inches(1.8), Inches(0.5), 11, "888888")
prs.save(a.out)
print(f"생성: {a.out} (slides={len(data.get('slides', []))})")
if __name__ == "__main__":
main()