1210 lines
57 KiB
Python
1210 lines
57 KiB
Python
from __future__ import annotations
|
||
|
||
from dataclasses import dataclass
|
||
from pathlib import Path
|
||
from typing import Iterable, Sequence
|
||
|
||
from pptx import Presentation
|
||
from pptx.dml.color import RGBColor
|
||
from pptx.enum.shapes import MSO_AUTO_SHAPE_TYPE
|
||
from pptx.enum.text import PP_ALIGN
|
||
from pptx.util import Inches, Pt
|
||
|
||
|
||
@dataclass(frozen=True)
|
||
class Theme:
|
||
navy: RGBColor
|
||
navy_2: RGBColor
|
||
bg: RGBColor
|
||
white: RGBColor
|
||
text: RGBColor
|
||
muted: RGBColor
|
||
line: RGBColor
|
||
accent_yellow: RGBColor
|
||
accent_blue: RGBColor
|
||
accent_red: RGBColor
|
||
accent_green: RGBColor
|
||
|
||
font: str
|
||
font_bold: str
|
||
|
||
|
||
T = Theme(
|
||
navy=RGBColor(0x10, 0x1D, 0x2E),
|
||
navy_2=RGBColor(0x14, 0x2A, 0x45),
|
||
bg=RGBColor(0xF6, 0xF7, 0xFB),
|
||
white=RGBColor(0xFF, 0xFF, 0xFF),
|
||
text=RGBColor(0x1F, 0x29, 0x37),
|
||
muted=RGBColor(0x6B, 0x72, 0x80),
|
||
line=RGBColor(0xE5, 0xE7, 0xEB),
|
||
accent_yellow=RGBColor(0xF0, 0xB4, 0x3B),
|
||
accent_blue=RGBColor(0x3B, 0x82, 0xF6),
|
||
accent_red=RGBColor(0xEF, 0x44, 0x44),
|
||
accent_green=RGBColor(0x22, 0xC5, 0x5E),
|
||
font="Apple SD Gothic Neo",
|
||
font_bold="Apple SD Gothic Neo",
|
||
)
|
||
|
||
|
||
SLIDE_W = Inches(13.333)
|
||
SLIDE_H = Inches(7.5)
|
||
|
||
|
||
def _rgb(hex6: str) -> RGBColor:
|
||
h = hex6.lstrip("#")
|
||
return RGBColor(int(h[0:2], 16), int(h[2:4], 16), int(h[4:6], 16))
|
||
|
||
|
||
def set_slide_bg(slide, color: RGBColor) -> None:
|
||
fill = slide.background.fill
|
||
fill.solid()
|
||
fill.fore_color.rgb = color
|
||
|
||
|
||
def add_rect(slide, x, y, w, h, *, fill: RGBColor | None, line: RGBColor | None, radius: bool = False):
|
||
shape_type = MSO_AUTO_SHAPE_TYPE.ROUNDED_RECTANGLE if radius else MSO_AUTO_SHAPE_TYPE.RECTANGLE
|
||
shp = slide.shapes.add_shape(shape_type, x, y, w, h)
|
||
if fill is None:
|
||
shp.fill.background()
|
||
else:
|
||
shp.fill.solid()
|
||
shp.fill.fore_color.rgb = fill
|
||
if line is None:
|
||
shp.line.fill.background()
|
||
else:
|
||
shp.line.color.rgb = line
|
||
shp.line.width = Pt(1)
|
||
return shp
|
||
|
||
|
||
def add_textbox(
|
||
slide,
|
||
x,
|
||
y,
|
||
w,
|
||
h,
|
||
text: str,
|
||
*,
|
||
size: int,
|
||
bold: bool = False,
|
||
color: RGBColor | None = None,
|
||
align: int = PP_ALIGN.LEFT,
|
||
line_spacing: float | None = None,
|
||
):
|
||
tb = slide.shapes.add_textbox(x, y, w, h)
|
||
tf = tb.text_frame
|
||
tf.clear()
|
||
p = tf.paragraphs[0]
|
||
run = p.add_run()
|
||
run.text = text
|
||
f = run.font
|
||
f.name = T.font_bold if bold else T.font
|
||
f.size = Pt(size)
|
||
f.bold = bold
|
||
f.color.rgb = color or T.text
|
||
p.alignment = align
|
||
if line_spacing is not None:
|
||
p.line_spacing = line_spacing
|
||
return tb
|
||
|
||
|
||
def add_bullets(
|
||
slide,
|
||
x,
|
||
y,
|
||
w,
|
||
h,
|
||
bullets: Sequence[str],
|
||
*,
|
||
size: int = 18,
|
||
color: RGBColor | None = None,
|
||
bullet_color: RGBColor | None = None,
|
||
line_spacing: float = 1.15,
|
||
):
|
||
tb = slide.shapes.add_textbox(x, y, w, h)
|
||
tf = tb.text_frame
|
||
tf.clear()
|
||
tf.word_wrap = True
|
||
for i, b in enumerate(bullets):
|
||
p = tf.paragraphs[0] if i == 0 else tf.add_paragraph()
|
||
p.text = b
|
||
p.level = 0
|
||
p.font.name = T.font
|
||
p.font.size = Pt(size)
|
||
p.font.color.rgb = color or T.text
|
||
p.line_spacing = line_spacing
|
||
p.space_after = Pt(6)
|
||
p.bullet = True
|
||
if bullet_color is not None:
|
||
# python-pptx doesn't support bullet color directly; keep as text color.
|
||
pass
|
||
return tb
|
||
|
||
|
||
def add_pill(slide, x, y, w, h, text: str, *, fill: RGBColor, fg: RGBColor):
|
||
pill = add_rect(slide, x, y, w, h, fill=fill, line=None, radius=True)
|
||
tf = pill.text_frame
|
||
tf.clear()
|
||
p = tf.paragraphs[0]
|
||
p.alignment = PP_ALIGN.CENTER
|
||
run = p.add_run()
|
||
run.text = text
|
||
run.font.name = T.font
|
||
run.font.size = Pt(12)
|
||
run.font.color.rgb = fg
|
||
return pill
|
||
|
||
|
||
def add_footer(slide, slide_no: int, *, dark: bool) -> None:
|
||
y = SLIDE_H - Inches(0.35)
|
||
add_rect(slide, Inches(0), y, SLIDE_W, Inches(0.35), fill=(T.navy if dark else T.bg), line=None, radius=False)
|
||
fg = _rgb("#D1D5DB") if dark else T.muted
|
||
add_textbox(
|
||
slide,
|
||
Inches(0.5),
|
||
y + Inches(0.06),
|
||
Inches(6),
|
||
Inches(0.25),
|
||
"윤도상 | 2026.03",
|
||
size=11,
|
||
bold=False,
|
||
color=fg,
|
||
align=PP_ALIGN.LEFT,
|
||
)
|
||
add_textbox(
|
||
slide,
|
||
SLIDE_W - Inches(2.0),
|
||
y + Inches(0.06),
|
||
Inches(1.5),
|
||
Inches(0.25),
|
||
f"Slide {slide_no:02d}" if dark else f"{slide_no:02d}",
|
||
size=11,
|
||
bold=False,
|
||
color=fg,
|
||
align=PP_ALIGN.RIGHT,
|
||
)
|
||
|
||
|
||
def add_title_block(
|
||
slide,
|
||
title: str,
|
||
subtitle: str | None = None,
|
||
*,
|
||
dark: bool,
|
||
y: float = 0.6,
|
||
pretitle: str | None = None,
|
||
):
|
||
fg = T.white if dark else T.text
|
||
if pretitle:
|
||
add_textbox(
|
||
slide,
|
||
Inches(0.7),
|
||
Inches(y),
|
||
Inches(12),
|
||
Inches(0.3),
|
||
pretitle,
|
||
size=14,
|
||
bold=True,
|
||
color=T.accent_yellow if dark else T.accent_yellow,
|
||
)
|
||
y += 0.35
|
||
add_textbox(
|
||
slide,
|
||
Inches(0.7),
|
||
Inches(y),
|
||
Inches(12),
|
||
Inches(0.8),
|
||
title,
|
||
size=40 if len(title) <= 18 else 34,
|
||
bold=True,
|
||
color=fg,
|
||
)
|
||
if subtitle:
|
||
add_textbox(
|
||
slide,
|
||
Inches(0.7),
|
||
Inches(y + 0.85),
|
||
Inches(12),
|
||
Inches(0.4),
|
||
subtitle,
|
||
size=18,
|
||
bold=True,
|
||
color=T.accent_yellow if dark else T.muted,
|
||
)
|
||
|
||
|
||
def add_card(
|
||
slide,
|
||
x,
|
||
y,
|
||
w,
|
||
h,
|
||
*,
|
||
title: str,
|
||
body: Sequence[str],
|
||
accent: RGBColor,
|
||
dark_text: bool = True,
|
||
):
|
||
add_rect(slide, x, y, w, h, fill=T.white, line=T.line, radius=True)
|
||
add_rect(slide, x, y, w, Inches(0.08), fill=accent, line=None, radius=False)
|
||
add_textbox(
|
||
slide,
|
||
x + Inches(0.25),
|
||
y + Inches(0.4),
|
||
w - Inches(0.5),
|
||
Inches(0.4),
|
||
title,
|
||
size=18,
|
||
bold=True,
|
||
color=T.text if dark_text else T.white,
|
||
)
|
||
add_bullets(
|
||
slide,
|
||
x + Inches(0.25),
|
||
y + Inches(0.9),
|
||
w - Inches(0.5),
|
||
h - Inches(1.1),
|
||
list(body),
|
||
size=14,
|
||
color=T.muted,
|
||
line_spacing=1.2,
|
||
)
|
||
|
||
|
||
def slide_01_cover(prs: Presentation) -> None:
|
||
s = prs.slides.add_slide(prs.slide_layouts[6])
|
||
set_slide_bg(s, T.navy)
|
||
add_pill(
|
||
s,
|
||
Inches(4.2),
|
||
Inches(0.35),
|
||
Inches(4.9),
|
||
Inches(0.42),
|
||
"LLM AI 툴 활용 교육",
|
||
fill=_rgb("#24364D"),
|
||
fg=_rgb("#E5E7EB"),
|
||
)
|
||
add_textbox(s, Inches(3.6), Inches(2.1), Inches(6.2), Inches(0.9), "AI에게", size=54, bold=True, color=T.white, align=PP_ALIGN.CENTER)
|
||
add_textbox(s, Inches(2.9), Inches(3.05), Inches(7.6), Inches(0.9), "잘 시키는 법", size=54, bold=True, color=T.white, align=PP_ALIGN.CENTER)
|
||
add_rect(s, Inches(6.1), Inches(4.1), Inches(1.2), Inches(0.05), fill=T.accent_yellow, line=None)
|
||
add_textbox(
|
||
s,
|
||
Inches(2.4),
|
||
Inches(4.35),
|
||
Inches(8.6),
|
||
Inches(0.5),
|
||
"실무자를 위한 LLM 프롬프트 & 워크플로우 완전 가이드",
|
||
size=18,
|
||
bold=True,
|
||
color=T.accent_yellow,
|
||
align=PP_ALIGN.CENTER,
|
||
)
|
||
add_footer(s, 1, dark=True)
|
||
|
||
|
||
def slide_02_core_assumptions(prs: Presentation) -> None:
|
||
s = prs.slides.add_slide(prs.slide_layouts[6])
|
||
set_slide_bg(s, T.bg)
|
||
add_textbox(s, Inches(0.7), Inches(0.55), Inches(12), Inches(0.3), "AI 활용의 핵심 전제 3가지", size=14, bold=True, color=T.accent_yellow)
|
||
add_textbox(s, Inches(0.7), Inches(0.9), Inches(12), Inches(0.7), "이것만 알아도 80%다", size=40, bold=True, color=T.text)
|
||
add_pill(s, Inches(10.1), Inches(1.1), Inches(2.6), Inches(0.38), "Chapter 1. AI는 어떻게 생각하는가?", fill=_rgb("#EEF2F7"), fg=T.muted)
|
||
|
||
cw = Inches(3.95)
|
||
ch = Inches(2.7)
|
||
y = Inches(2.05)
|
||
gap = Inches(0.4)
|
||
x1 = Inches(0.7)
|
||
add_card(
|
||
s,
|
||
x1,
|
||
y,
|
||
cw,
|
||
ch,
|
||
title="AI는 당신이 준\n정보만큼 답한다",
|
||
body=["입력(Prompt)의 질이 곧", "출력(Output)의 질을 결정합니다.", "맥락이 없으면 답도 없습니다."],
|
||
accent=T.accent_blue,
|
||
)
|
||
add_card(
|
||
s,
|
||
x1 + cw + gap,
|
||
y,
|
||
cw,
|
||
ch,
|
||
title="AI는 틀린 답을\n자신 있게 말한다",
|
||
body=["환각(Hallucination) 현상은", "AI의 구조적 특성입니다.", "절대 맹신하지 마세요."],
|
||
accent=T.accent_red,
|
||
)
|
||
add_card(
|
||
s,
|
||
x1 + (cw + gap) * 2,
|
||
y,
|
||
cw,
|
||
ch,
|
||
title="AI는 도구이지,\n판단자가 아니다",
|
||
body=["결과물에 대한 최종 검증과", "책임은 항상 사람(나)에게", "있습니다."],
|
||
accent=T.accent_green,
|
||
)
|
||
|
||
bar_y = Inches(5.55)
|
||
add_rect(s, Inches(0.7), bar_y, Inches(11.93), Inches(0.85), fill=T.navy_2, line=None, radius=True)
|
||
add_pill(s, Inches(0.95), bar_y + Inches(0.18), Inches(1.15), Inches(0.42), "실제 사례", fill=T.accent_yellow, fg=T.navy)
|
||
add_pill(s, Inches(2.2), bar_y + Inches(0.18), Inches(3.1), Inches(0.42), "\"세차장에 갑니다\" (중의적)", fill=_rgb("#2B3E59"), fg=_rgb("#E5E7EB"))
|
||
add_textbox(s, Inches(5.35), bar_y + Inches(0.18), Inches(0.4), Inches(0.42), "→", size=22, bold=True, color=T.accent_yellow, align=PP_ALIGN.CENTER)
|
||
add_pill(s, Inches(5.7), bar_y + Inches(0.18), Inches(3.2), Inches(0.42), "\"세차하러 갑니다\" (명확)", fill=_rgb("#2B3E59"), fg=_rgb("#E5E7EB"))
|
||
add_textbox(
|
||
s,
|
||
Inches(9.1),
|
||
bar_y + Inches(0.18),
|
||
Inches(3.3),
|
||
Inches(0.42),
|
||
"정보 단 하나(목적) 차이로\nAI의 답변 품질이 완전히 달라집니다!",
|
||
size=12,
|
||
bold=True,
|
||
color=_rgb("#E5E7EB"),
|
||
align=PP_ALIGN.RIGHT,
|
||
)
|
||
add_footer(s, 2, dark=False)
|
||
|
||
|
||
def slide_03_llm(prs: Presentation) -> None:
|
||
s = prs.slides.add_slide(prs.slide_layouts[6])
|
||
set_slide_bg(s, T.navy)
|
||
add_title_block(s, "LLM이란 무엇인가?", "Large Language Model — 대규모 언어 모델", dark=True, y=0.5)
|
||
add_pill(s, Inches(11.5), Inches(0.6), Inches(1.4), Inches(0.38), "Chapter 1", fill=_rgb("#24364D"), fg=_rgb("#E5E7EB"))
|
||
|
||
x = Inches(0.7)
|
||
y = Inches(2.0)
|
||
w = Inches(4.8)
|
||
h = Inches(1.05)
|
||
gap = Inches(0.35)
|
||
|
||
def left_item(yy, title, desc):
|
||
add_rect(s, x, yy, w, h, fill=_rgb("#1B2A3F"), line=_rgb("#2B3E59"), radius=True)
|
||
add_textbox(s, x + Inches(0.3), yy + Inches(0.2), w - Inches(0.6), Inches(0.35), title, size=18, bold=True, color=T.white)
|
||
add_textbox(s, x + Inches(0.3), yy + Inches(0.55), w - Inches(0.6), Inches(0.45), desc, size=13, bold=False, color=_rgb("#D1D5DB"))
|
||
|
||
left_item(y, "확률 기반 언어 예측", "다음에 올 단어를 통계적으로\n예측하는 '확률 기계'입니다.")
|
||
left_item(y + h + gap, "\"지식\"이 아닌 \"패턴\"", "사전처럼 정답을 저장한 것이 아니라,\n수많은 문장의 패턴을 학습했습니다.")
|
||
left_item(y + (h + gap) * 2, "확률적 답변 생성", "같은 질문에도 매번 확률적으로\n가장 자연스러운 답을 생성합니다.")
|
||
|
||
# Right diagram card
|
||
rx = Inches(5.8)
|
||
ry = Inches(2.05)
|
||
rw = Inches(7.0)
|
||
rh = Inches(4.25)
|
||
add_rect(s, rx, ry, rw, rh, fill=_rgb("#1B2A3F"), line=_rgb("#2B3E59"), radius=True)
|
||
add_textbox(s, rx + Inches(0.35), ry + Inches(0.25), Inches(4), Inches(0.35), "LLM 작동 프로세스 예시", size=13, bold=True, color=_rgb("#9CA3AF"))
|
||
|
||
# INPUT box
|
||
add_textbox(s, rx + Inches(0.55), ry + Inches(0.8), Inches(1.5), Inches(0.3), "INPUT (입력)", size=11, bold=True, color=_rgb("#9CA3AF"))
|
||
add_rect(s, rx + Inches(0.55), ry + Inches(1.15), Inches(2.2), Inches(0.85), fill=_rgb("#132236"), line=_rgb("#2B3E59"), radius=True)
|
||
add_textbox(
|
||
s,
|
||
rx + Inches(0.7),
|
||
ry + Inches(1.28),
|
||
Inches(1.9),
|
||
Inches(0.55),
|
||
"\"대한민국의\n수도는\"",
|
||
size=16,
|
||
bold=True,
|
||
color=T.white,
|
||
align=PP_ALIGN.CENTER,
|
||
)
|
||
# Prediction circle
|
||
add_textbox(s, rx + Inches(3.0), ry + Inches(0.8), Inches(2.5), Inches(0.3), "PREDICTION (예측)", size=11, bold=True, color=T.accent_yellow, align=PP_ALIGN.CENTER)
|
||
circ = s.shapes.add_shape(MSO_AUTO_SHAPE_TYPE.OVAL, rx + Inches(3.2), ry + Inches(1.05), Inches(2.55), Inches(2.55))
|
||
circ.fill.background()
|
||
circ.line.color.rgb = T.accent_yellow
|
||
circ.line.width = Pt(2)
|
||
# Prob bars inside
|
||
add_textbox(s, rx + Inches(3.35), ry + Inches(1.45), Inches(2.25), Inches(0.25), "서울 92%", size=11, bold=True, color=_rgb("#E5E7EB"))
|
||
add_rect(s, rx + Inches(3.35), ry + Inches(1.72), Inches(2.1), Inches(0.08), fill=T.accent_yellow, line=None)
|
||
add_textbox(s, rx + Inches(3.35), ry + Inches(1.95), Inches(2.25), Inches(0.25), "부산 5%", size=11, bold=False, color=_rgb("#9CA3AF"))
|
||
add_rect(s, rx + Inches(3.35), ry + Inches(2.22), Inches(0.55), Inches(0.08), fill=_rgb("#64748B"), line=None)
|
||
add_textbox(s, rx + Inches(3.35), ry + Inches(2.45), Inches(2.25), Inches(0.25), "평양 1%", size=11, bold=False, color=_rgb("#9CA3AF"))
|
||
add_rect(s, rx + Inches(3.35), ry + Inches(2.72), Inches(0.25), Inches(0.08), fill=_rgb("#64748B"), line=None)
|
||
|
||
# OUTPUT box
|
||
add_textbox(s, rx + Inches(5.85), ry + Inches(0.8), Inches(1.5), Inches(0.3), "OUTPUT (출력)", size=11, bold=True, color=_rgb("#9CA3AF"), align=PP_ALIGN.RIGHT)
|
||
add_rect(s, rx + Inches(5.6), ry + Inches(1.25), Inches(2.15), Inches(0.85), fill=_rgb("#0F2C2A"), line=_rgb("#34D399"), radius=True)
|
||
add_textbox(
|
||
s,
|
||
rx + Inches(5.75),
|
||
ry + Inches(1.38),
|
||
Inches(1.85),
|
||
Inches(0.55),
|
||
"\"서울입니다.\"",
|
||
size=18,
|
||
bold=True,
|
||
color=_rgb("#A7F3D0"),
|
||
align=PP_ALIGN.CENTER,
|
||
)
|
||
|
||
# Arrows
|
||
add_textbox(s, rx + Inches(2.85), ry + Inches(1.45), Inches(0.3), Inches(0.3), "›", size=28, bold=True, color=_rgb("#9CA3AF"), align=PP_ALIGN.CENTER)
|
||
add_textbox(s, rx + Inches(5.45), ry + Inches(1.45), Inches(0.3), Inches(0.3), "›", size=28, bold=True, color=_rgb("#9CA3AF"), align=PP_ALIGN.CENTER)
|
||
|
||
add_rect(s, rx + Inches(0.45), ry + Inches(3.8), rw - Inches(0.9), Inches(0.55), fill=_rgb("#24364D"), line=None, radius=True)
|
||
add_textbox(
|
||
s,
|
||
rx + Inches(0.7),
|
||
ry + Inches(3.92),
|
||
rw - Inches(1.4),
|
||
Inches(0.3),
|
||
"ChatGPT, Claude, Gemini 등은 모두 이와 같은 원리로 작동합니다.",
|
||
size=12,
|
||
bold=True,
|
||
color=_rgb("#D1D5DB"),
|
||
align=PP_ALIGN.CENTER,
|
||
)
|
||
add_footer(s, 3, dark=True)
|
||
|
||
|
||
def slide_04_good_vs_bad(prs: Presentation) -> None:
|
||
s = prs.slides.add_slide(prs.slide_layouts[6])
|
||
set_slide_bg(s, T.bg)
|
||
add_textbox(s, Inches(0.7), Inches(0.55), Inches(12), Inches(0.3), "효율적인 AI 활용을 위한 첫걸음", size=14, bold=True, color=T.muted)
|
||
add_textbox(s, Inches(0.7), Inches(0.9), Inches(12), Inches(0.7), "AI가 잘하는 것 vs 못하는 것", size=40, bold=True, color=T.text)
|
||
add_pill(s, Inches(9.9), Inches(1.1), Inches(2.95), Inches(0.38), "Chapter 1. AI의 본질 이해", fill=_rgb("#EEF2F7"), fg=T.muted)
|
||
|
||
left_x = Inches(0.8)
|
||
col_y = Inches(2.0)
|
||
col_w = Inches(6.05)
|
||
col_h = Inches(4.25)
|
||
right_x = Inches(6.45)
|
||
|
||
add_rect(s, left_x, col_y, col_w, col_h, fill=_rgb("#E9FBF1"), line=None, radius=True)
|
||
add_rect(s, right_x, col_y, col_w, col_h, fill=_rgb("#FDECEC"), line=None, radius=True)
|
||
add_textbox(s, left_x + Inches(0.35), col_y + Inches(0.3), col_w - Inches(0.7), Inches(0.35), "✓ AI가 잘하는 것", size=20, bold=True, color=_rgb("#15803D"))
|
||
add_textbox(s, right_x + Inches(0.35), col_y + Inches(0.3), col_w - Inches(0.7), Inches(0.35), "✕ AI가 못하는 것 / 주의", size=20, bold=True, color=_rgb("#B91C1C"))
|
||
|
||
good = [
|
||
"구조화된 글 작성 및 요약",
|
||
"번역 및 언어 변환",
|
||
"패턴 인식 및 분류",
|
||
"코드 생성 및 디버깅",
|
||
"반복 업무 자동화",
|
||
"대용량 문서 핵심 추출",
|
||
]
|
||
bad = [
|
||
"최신 실시간 정보 확인 (검색 미연동 시)",
|
||
"복잡한 수학 계산·논리적 검증",
|
||
"사용자의 숨겨진 의도 자동 파악",
|
||
"사실 여부 100% 보장 (환각 위험)",
|
||
"인간적 감각·경험 기반의 판단",
|
||
"결과물에 대한 법적 책임",
|
||
]
|
||
|
||
add_bullets(s, left_x + Inches(0.55), col_y + Inches(0.9), col_w - Inches(1.1), col_h - Inches(1.2), good, size=16, color=T.text)
|
||
add_bullets(s, right_x + Inches(0.55), col_y + Inches(0.9), col_w - Inches(1.1), col_h - Inches(1.2), bad, size=16, color=T.text)
|
||
|
||
# Center VS bubble
|
||
vs = s.shapes.add_shape(MSO_AUTO_SHAPE_TYPE.OVAL, Inches(6.1), Inches(3.8), Inches(0.7), Inches(0.7))
|
||
vs.fill.solid()
|
||
vs.fill.fore_color.rgb = _rgb("#EEF2F7")
|
||
vs.line.color.rgb = T.line
|
||
vs.text_frame.text = "VS"
|
||
vs.text_frame.paragraphs[0].alignment = PP_ALIGN.CENTER
|
||
vs.text_frame.paragraphs[0].runs[0].font.name = T.font_bold
|
||
vs.text_frame.paragraphs[0].runs[0].font.bold = True
|
||
vs.text_frame.paragraphs[0].runs[0].font.size = Pt(14)
|
||
vs.text_frame.paragraphs[0].runs[0].font.color.rgb = T.muted
|
||
|
||
# Bottom callout
|
||
add_rect(s, Inches(0.7), Inches(6.55), Inches(11.93), Inches(0.65), fill=T.navy_2, line=None, radius=True)
|
||
add_textbox(
|
||
s,
|
||
Inches(0.95),
|
||
Inches(6.66),
|
||
Inches(11.4),
|
||
Inches(0.42),
|
||
"AI를 \"잘 쓴다\"는 것은, AI가 못하는 영역을 사람이 보완한다는 뜻입니다.",
|
||
size=16,
|
||
bold=True,
|
||
color=_rgb("#E5E7EB"),
|
||
align=PP_ALIGN.CENTER,
|
||
)
|
||
add_footer(s, 4, dark=False)
|
||
|
||
|
||
def slide_05_hallucination(prs: Presentation) -> None:
|
||
s = prs.slides.add_slide(prs.slide_layouts[6])
|
||
set_slide_bg(s, T.bg)
|
||
add_textbox(s, Inches(0.7), Inches(0.55), Inches(12), Inches(0.3), "⚠ 왜 AI는 그럴듯하게 거짓말하는가?", size=14, bold=True, color=T.accent_red)
|
||
add_textbox(s, Inches(0.7), Inches(0.9), Inches(12), Inches(0.7), "AI의 환각(Hallucination) 현상", size=40, bold=True, color=T.text)
|
||
add_pill(s, Inches(11.2), Inches(1.05), Inches(1.55), Inches(0.4), "Critical Issue", fill=_rgb("#FEE2E2"), fg=_rgb("#B91C1C"))
|
||
|
||
# Definition box
|
||
add_rect(s, Inches(0.7), Inches(1.9), Inches(11.93), Inches(1.0), fill=_rgb("#F3F4F6"), line=None, radius=True)
|
||
add_textbox(s, Inches(1.0), Inches(2.05), Inches(11.3), Inches(0.3), "환각(Hallucination)이란?", size=16, bold=True, color=T.text)
|
||
add_textbox(
|
||
s,
|
||
Inches(1.0),
|
||
Inches(2.35),
|
||
Inches(11.3),
|
||
Inches(0.5),
|
||
"AI가 사실이 아닌 내용을 마치 사실인 것처럼 자신 있게 답하는 현상입니다.\n"
|
||
"AI는 확률적으로 '자연스러운 문장'을 생성하는 과정에서 거짓 정보를 유창하게 만들어낼 수 있습니다.",
|
||
size=13,
|
||
bold=False,
|
||
color=T.muted,
|
||
line_spacing=1.2,
|
||
)
|
||
|
||
# Risk cards
|
||
x = Inches(0.7)
|
||
y = Inches(3.1)
|
||
w = Inches(3.82)
|
||
h = Inches(1.55)
|
||
g = Inches(0.35)
|
||
|
||
def risk(xx, title, bullets):
|
||
add_rect(s, xx, y, w, h, fill=_rgb("#FFF1F2"), line=_rgb("#FECACA"), radius=True)
|
||
add_textbox(s, xx + Inches(0.25), y + Inches(0.2), w - Inches(0.5), Inches(0.3), title, size=14, bold=True, color=_rgb("#B91C1C"))
|
||
add_bullets(s, xx + Inches(0.25), y + Inches(0.55), w - Inches(0.5), h - Inches(0.6), bullets, size=12, color=_rgb("#7F1D1D"))
|
||
|
||
risk(x, "가짜 정보 생성 사례", ["존재하지 않는 논문·자료 인용", "역사적 사실을 왜곡하여 설명", "없는 기능을 가진 것처럼 설명"])
|
||
risk(x + w + g, "수치 오류 사례", ["틀린 계산 결과를 정확한 척 제시", "단위(원, 달러) 혼동하여 표기", "최신 통계가 아닌 과거 데이터 인용"])
|
||
risk(x + (w + g) * 2, "법적/규정 위험 사례", ["개정 전 법률이나 규정을 답변", "저작권/라이선스 규정을 무시한 활용", "개인정보 보호 규정을 위반하는 제안"])
|
||
|
||
add_textbox(s, Inches(0.7), Inches(4.85), Inches(12), Inches(0.3), "✅ 환각을 피하는 3가지 습관", size=16, bold=True, color=_rgb("#15803D"))
|
||
|
||
# Habits
|
||
hy = Inches(5.2)
|
||
hw = Inches(3.82)
|
||
hh = Inches(1.1)
|
||
|
||
def habit(xx, title, desc):
|
||
add_rect(s, xx, hy, hw, hh, fill=_rgb("#E9FBF1"), line=_rgb("#BBF7D0"), radius=True)
|
||
add_textbox(s, xx + Inches(0.25), hy + Inches(0.25), hw - Inches(0.5), Inches(0.25), title, size=14, bold=True, color=_rgb("#15803D"), align=PP_ALIGN.CENTER)
|
||
add_textbox(s, xx + Inches(0.25), hy + Inches(0.55), hw - Inches(0.5), Inches(0.4), desc, size=12, bold=False, color=_rgb("#166534"), align=PP_ALIGN.CENTER, line_spacing=1.2)
|
||
|
||
habit(Inches(0.7), "원문 대조 확인", "중요한 수치·법률·사실 관계는\n반드시 원문 문서와 대조하세요.")
|
||
habit(Inches(0.7) + hw + g, "출처 요청하기", "\"이 정보의 출처(URL)를 알려줘\"라고\n요청하여 근거를 확인하세요.")
|
||
habit(Inches(0.7) + (hw + g) * 2, "'초안'으로만 활용", "AI 답변은 최종 결과물이 아닌\n'검토가 필요한 초안'으로 대하세요.")
|
||
|
||
add_footer(s, 5, dark=False)
|
||
|
||
|
||
def slide_06_prompt_definition(prs: Presentation) -> None:
|
||
s = prs.slides.add_slide(prs.slide_layouts[6])
|
||
set_slide_bg(s, T.bg)
|
||
add_textbox(s, Inches(0.7), Inches(0.55), Inches(12), Inches(0.3), "PART 2. 입력의 질이 출력의 질을 결정한다", size=14, bold=True, color=T.muted)
|
||
add_textbox(s, Inches(0.7), Inches(0.9), Inches(12), Inches(0.7), "프롬프트란 무엇인가?", size=40, bold=True, color=T.text)
|
||
add_textbox(s, Inches(0.7), Inches(1.55), Inches(12), Inches(0.35), "AI와 소통하는 \"언어\" — 목적·상황·제약·형식을 한 번에 전달하는 지시서", size=16, bold=True, color=T.muted)
|
||
|
||
add_textbox(s, Inches(0.7), Inches(2.1), Inches(12), Inches(0.3), "나쁜 프롬프트 vs 좋은 프롬프트 (예시 3가지)", size=16, bold=True, color=T.text)
|
||
rows = [
|
||
("보고서 써줘", "대상(누가 읽는지), 목적(왜), 형식(목차/분량)을 포함해서\n\"임원 보고용 1페이지 요약\"으로 작성해줘."),
|
||
("요약해줘", "\"다음 글을 3줄 요약 + 핵심 키워드 5개\" 형식으로 요약해줘."),
|
||
("분석해줘", "\"표로 정리(열: 문제, 원인, 영향, 개선안)\" 하고,\n결론을 먼저 제시한 뒤 근거를 번호로 달아줘."),
|
||
]
|
||
y = Inches(2.5)
|
||
for i, (bad, good) in enumerate(rows):
|
||
yy = y + Inches(1.25) * i
|
||
add_rect(s, Inches(0.7), yy, Inches(5.9), Inches(1.05), fill=_rgb("#FFF1F2"), line=_rgb("#FECACA"), radius=True)
|
||
add_rect(s, Inches(6.75), yy, Inches(5.88), Inches(1.05), fill=_rgb("#E9FBF1"), line=_rgb("#BBF7D0"), radius=True)
|
||
add_textbox(s, Inches(0.95), yy + Inches(0.2), Inches(5.4), Inches(0.25), "❌ 나쁜 프롬프트", size=12, bold=True, color=_rgb("#B91C1C"))
|
||
add_textbox(s, Inches(7.0), yy + Inches(0.2), Inches(5.4), Inches(0.25), "✅ 좋은 프롬프트", size=12, bold=True, color=_rgb("#15803D"))
|
||
add_textbox(s, Inches(0.95), yy + Inches(0.5), Inches(5.4), Inches(0.5), bad, size=18, bold=True, color=_rgb("#7F1D1D"))
|
||
add_textbox(s, Inches(7.0), yy + Inches(0.5), Inches(5.4), Inches(0.6), good, size=14, bold=False, color=_rgb("#166534"), line_spacing=1.15)
|
||
|
||
add_footer(s, 6, dark=False)
|
||
|
||
|
||
def slide_07_language(prs: Presentation) -> None:
|
||
s = prs.slides.add_slide(prs.slide_layouts[6])
|
||
set_slide_bg(s, T.bg)
|
||
add_textbox(s, Inches(0.7), Inches(0.55), Inches(12), Inches(0.3), "PART 2. 프롬프트 설계 원칙", size=14, bold=True, color=T.muted)
|
||
add_textbox(s, Inches(0.7), Inches(0.9), Inches(12), Inches(0.7), "[사례 1] 언어 선택: 한국어 vs 영어", size=34, bold=True, color=T.text)
|
||
|
||
add_rect(s, Inches(0.7), Inches(1.9), Inches(11.93), Inches(2.3), fill=T.white, line=T.line, radius=True)
|
||
add_textbox(s, Inches(1.0), Inches(2.15), Inches(11.3), Inches(0.3), "왜 영어 입력이 더 정확한 경우가 있는가?", size=18, bold=True, color=T.text)
|
||
add_bullets(
|
||
s,
|
||
Inches(1.0),
|
||
Inches(2.55),
|
||
Inches(11.3),
|
||
Inches(1.4),
|
||
["학습 데이터 불균형 (영어 데이터가 압도적으로 많음)", "전문 용어·기술 용어의 영어 표현이 더 풍부", "일부 모델/도구는 영어 지시에서 더 안정적으로 동작"],
|
||
size=16,
|
||
color=T.text,
|
||
)
|
||
add_rect(s, Inches(0.7), Inches(4.45), Inches(11.93), Inches(1.35), fill=_rgb("#24364D"), line=None, radius=True)
|
||
add_textbox(s, Inches(1.0), Inches(4.62), Inches(5.8), Inches(0.3), "실무 팁", size=14, bold=True, color=T.accent_yellow)
|
||
add_textbox(s, Inches(1.0), Inches(4.92), Inches(6.6), Inches(0.7), "영어로 묻고, 한국어로 출력 요청하기\n예) \"Answer in Korean, and format as a table.\"", size=14, bold=True, color=_rgb("#E5E7EB"), line_spacing=1.2)
|
||
add_textbox(s, Inches(8.0), Inches(4.75), Inches(4.4), Inches(0.9), "실습\n동일 질문 한/영 비교 결과 시연", size=16, bold=True, color=_rgb("#E5E7EB"), align=PP_ALIGN.CENTER, line_spacing=1.2)
|
||
add_footer(s, 7, dark=False)
|
||
|
||
|
||
def slide_08_context(prs: Presentation) -> None:
|
||
s = prs.slides.add_slide(prs.slide_layouts[6])
|
||
set_slide_bg(s, T.bg)
|
||
add_textbox(s, Inches(0.7), Inches(0.55), Inches(12), Inches(0.3), "PART 2. 프롬프트 설계 원칙", size=14, bold=True, color=T.muted)
|
||
add_textbox(s, Inches(0.7), Inches(0.9), Inches(12), Inches(0.7), "[사례 2] 정보의 완전성 — 맥락이 없으면 중의성이 생긴다", size=28, bold=True, color=T.text)
|
||
add_textbox(s, Inches(0.7), Inches(1.55), Inches(12), Inches(0.35), "핵심 원리: \"목적 + 상황 + 제약 조건\"을 모두 포함하라", size=16, bold=True, color=T.muted)
|
||
|
||
add_rect(s, Inches(0.7), Inches(2.05), Inches(11.93), Inches(1.9), fill=T.white, line=T.line, radius=True)
|
||
add_rect(s, Inches(0.7), Inches(2.05), Inches(5.8), Inches(1.9), fill=_rgb("#FFF1F2"), line=None, radius=True)
|
||
add_rect(s, Inches(6.83), Inches(2.05), Inches(5.8), Inches(1.9), fill=_rgb("#E9FBF1"), line=None, radius=True)
|
||
add_textbox(s, Inches(1.05), Inches(2.25), Inches(5.2), Inches(0.3), "❌ 중의적", size=14, bold=True, color=_rgb("#B91C1C"))
|
||
add_textbox(s, Inches(7.15), Inches(2.25), Inches(5.2), Inches(0.3), "✅ 명확", size=14, bold=True, color=_rgb("#15803D"))
|
||
add_textbox(s, Inches(1.05), Inches(2.65), Inches(5.2), Inches(0.8), "\"세차장에 갑니다. 걸어갈까요?\"", size=22, bold=True, color=_rgb("#7F1D1D"), line_spacing=1.1)
|
||
add_textbox(s, Inches(7.15), Inches(2.65), Inches(5.2), Inches(0.8), "\"세차하러 갑니다. 걸어갈까요?\"", size=22, bold=True, color=_rgb("#166534"), line_spacing=1.1)
|
||
add_textbox(s, Inches(1.05), Inches(3.35), Inches(5.2), Inches(0.4), "목적이 빠지면 해석이 여러 개로 갈립니다.", size=14, bold=False, color=_rgb("#7F1D1D"))
|
||
add_textbox(s, Inches(7.15), Inches(3.35), Inches(5.2), Inches(0.4), "목적을 넣으면 AI도 명확히 답합니다.", size=14, bold=False, color=_rgb("#166534"))
|
||
|
||
add_rect(s, Inches(0.7), Inches(4.2), Inches(11.93), Inches(1.85), fill=_rgb("#24364D"), line=None, radius=True)
|
||
add_textbox(s, Inches(1.0), Inches(4.35), Inches(11.3), Inches(0.3), "실무 적용", size=14, bold=True, color=T.accent_yellow)
|
||
add_bullets(
|
||
s,
|
||
Inches(1.0),
|
||
Inches(4.7),
|
||
Inches(11.3),
|
||
Inches(1.2),
|
||
["보고서/기획서 요청 시: \"누가 읽는지\"(대상) + \"목적\" + \"형식(분량/목차)\"을 함께 제공", "제약 조건(기간/데이터 범위/금지사항)을 명시하면 결과가 안정적으로 개선"],
|
||
size=15,
|
||
color=_rgb("#E5E7EB"),
|
||
)
|
||
add_footer(s, 8, dark=False)
|
||
|
||
|
||
def slide_09_5w1h(prs: Presentation) -> None:
|
||
s = prs.slides.add_slide(prs.slide_layouts[6])
|
||
set_slide_bg(s, T.bg)
|
||
add_textbox(s, Inches(0.7), Inches(0.55), Inches(12), Inches(0.3), "PART 2. 프롬프트 설계 원칙", size=14, bold=True, color=T.muted)
|
||
add_textbox(s, Inches(0.7), Inches(0.9), Inches(12), Inches(0.7), "5W1H 프롬프트 프레임", size=40, bold=True, color=T.text)
|
||
|
||
frame = [
|
||
("Who", "역할 설정", "예: \"너는 제약업계 10년 경력의 마케터야\""),
|
||
("What", "원하는 산출물", "예: \"임원 보고용 1페이지 요약\""),
|
||
("Why", "목적·배경", "예: \"AX 과제 선정 회의 자료로 사용할 거야\""),
|
||
("When/Where", "상황·컨텍스트", "예: \"지난 분기 데이터 기준, 국내 시장\""),
|
||
("How", "출력 형식", "예: \"표(열: 항목, 근거, 리스크) + 결론 먼저\""),
|
||
]
|
||
y = Inches(2.0)
|
||
row_h = Inches(0.95)
|
||
for i, (k, t, ex) in enumerate(frame):
|
||
yy = y + row_h * i
|
||
add_rect(s, Inches(0.7), yy, Inches(11.93), row_h - Inches(0.12), fill=T.white, line=T.line, radius=True)
|
||
add_rect(s, Inches(0.7), yy, Inches(1.6), row_h - Inches(0.12), fill=_rgb("#24364D"), line=None, radius=True)
|
||
add_textbox(s, Inches(0.7), yy + Inches(0.18), Inches(1.6), Inches(0.3), k, size=16, bold=True, color=T.accent_yellow, align=PP_ALIGN.CENTER)
|
||
add_textbox(s, Inches(2.45), yy + Inches(0.18), Inches(3.2), Inches(0.3), t, size=18, bold=True, color=T.text)
|
||
add_textbox(s, Inches(2.45), yy + Inches(0.5), Inches(9.9), Inches(0.35), ex, size=14, bold=False, color=T.muted)
|
||
add_footer(s, 9, dark=False)
|
||
|
||
|
||
def slide_10_format(prs: Presentation) -> None:
|
||
s = prs.slides.add_slide(prs.slide_layouts[6])
|
||
set_slide_bg(s, T.bg)
|
||
add_textbox(s, Inches(0.7), Inches(0.55), Inches(12), Inches(0.3), "PART 2. 프롬프트 설계 원칙", size=14, bold=True, color=T.muted)
|
||
add_textbox(s, Inches(0.7), Inches(0.9), Inches(12), Inches(0.7), "출력 형식을 지정하라", size=40, bold=True, color=T.text)
|
||
add_textbox(s, Inches(0.7), Inches(1.55), Inches(12), Inches(0.35), "형식을 안 주면 AI가 알아서 결정 → 원하는 형태가 아닐 수 있음", size=16, bold=True, color=T.muted)
|
||
|
||
add_rect(s, Inches(0.7), Inches(2.05), Inches(5.9), Inches(3.0), fill=_rgb("#FFF1F2"), line=_rgb("#FECACA"), radius=True)
|
||
add_rect(s, Inches(6.75), Inches(2.05), Inches(5.88), Inches(3.0), fill=_rgb("#E9FBF1"), line=_rgb("#BBF7D0"), radius=True)
|
||
add_textbox(s, Inches(0.95), Inches(2.25), Inches(5.4), Inches(0.3), "Before", size=14, bold=True, color=_rgb("#B91C1C"))
|
||
add_textbox(s, Inches(7.0), Inches(2.25), Inches(5.4), Inches(0.3), "After", size=14, bold=True, color=_rgb("#15803D"))
|
||
add_textbox(s, Inches(0.95), Inches(2.65), Inches(5.4), Inches(1.0), "\"이 자료 분석해줘\"", size=22, bold=True, color=_rgb("#7F1D1D"))
|
||
add_textbox(
|
||
s,
|
||
Inches(7.0),
|
||
Inches(2.65),
|
||
Inches(5.4),
|
||
Inches(1.4),
|
||
"\"표로 만들어줘 (열: 항목명, 장점, 단점)\"\n\"3줄 요약으로\"\n\"결론 먼저, 근거는 번호 순으로\"",
|
||
size=16,
|
||
bold=True,
|
||
color=_rgb("#166534"),
|
||
line_spacing=1.2,
|
||
)
|
||
add_rect(s, Inches(0.7), Inches(5.25), Inches(11.93), Inches(1.1), fill=_rgb("#24364D"), line=None, radius=True)
|
||
add_textbox(
|
||
s,
|
||
Inches(1.0),
|
||
Inches(5.4),
|
||
Inches(11.3),
|
||
Inches(0.8),
|
||
"체크포인트\n- 형식(표/글머리/단계)\n- 분량(3줄/1페이지)\n- 순서(결론 먼저)\n- 톤(전문/간결/친절)",
|
||
size=14,
|
||
bold=True,
|
||
color=_rgb("#E5E7EB"),
|
||
line_spacing=1.15,
|
||
)
|
||
add_footer(s, 10, dark=False)
|
||
|
||
|
||
def slide_11_role(prs: Presentation) -> None:
|
||
s = prs.slides.add_slide(prs.slide_layouts[6])
|
||
set_slide_bg(s, T.bg)
|
||
add_textbox(s, Inches(0.7), Inches(0.55), Inches(12), Inches(0.3), "PART 2. 프롬프트 설계 원칙", size=14, bold=True, color=T.muted)
|
||
add_textbox(s, Inches(0.7), Inches(0.9), Inches(12), Inches(0.7), "역할 부여(Role Prompting) 기법", size=36, bold=True, color=T.text)
|
||
add_textbox(s, Inches(0.7), Inches(1.55), Inches(12), Inches(0.35), "\"너는 ○○이야\" 선언의 효과: 관점·깊이·어조를 통제", size=16, bold=True, color=T.muted)
|
||
|
||
add_rect(s, Inches(0.7), Inches(2.05), Inches(11.93), Inches(2.1), fill=T.white, line=T.line, radius=True)
|
||
add_textbox(s, Inches(1.0), Inches(2.25), Inches(11.3), Inches(0.3), "예시", size=14, bold=True, color=T.muted)
|
||
add_rect(s, Inches(1.0), Inches(2.6), Inches(11.3), Inches(1.35), fill=_rgb("#24364D"), line=None, radius=True)
|
||
add_textbox(
|
||
s,
|
||
Inches(1.3),
|
||
Inches(2.75),
|
||
Inches(10.7),
|
||
Inches(1.0),
|
||
"너는 대웅제약 CFO야.\n다음 데이터를 분석해줘. (목표: 비용 절감 관점, 리스크 포함, 1페이지 요약)",
|
||
size=18,
|
||
bold=True,
|
||
color=_rgb("#E5E7EB"),
|
||
line_spacing=1.2,
|
||
)
|
||
|
||
add_rect(s, Inches(0.7), Inches(4.35), Inches(11.93), Inches(2.0), fill=_rgb("#E9FBF1"), line=_rgb("#BBF7D0"), radius=True)
|
||
add_textbox(s, Inches(1.0), Inches(4.55), Inches(11.3), Inches(0.3), "실습", size=14, bold=True, color=_rgb("#15803D"))
|
||
add_bullets(
|
||
s,
|
||
Inches(1.0),
|
||
Inches(4.9),
|
||
Inches(11.3),
|
||
Inches(1.3),
|
||
["동일 데이터를 영업팀장 / 재무팀장 / CEO 역할로 각각 분석", "출력의 관점·강조점·결론이 어떻게 달라지는지 비교"],
|
||
size=16,
|
||
color=_rgb("#166534"),
|
||
)
|
||
add_footer(s, 11, dark=False)
|
||
|
||
|
||
def slide_12_steps(prs: Presentation) -> None:
|
||
s = prs.slides.add_slide(prs.slide_layouts[6])
|
||
set_slide_bg(s, T.bg)
|
||
add_textbox(s, Inches(0.7), Inches(0.55), Inches(12), Inches(0.3), "PART 3. AI를 더 똑똑하게 쓰는 고급 기법", size=14, bold=True, color=T.muted)
|
||
add_textbox(s, Inches(0.7), Inches(0.9), Inches(12), Inches(0.7), "단계적 사고 유도", size=40, bold=True, color=T.text)
|
||
add_textbox(s, Inches(0.7), Inches(1.55), Inches(12), Inches(0.35), "복잡한 문제일수록 절차(단계)를 나눠서 요청하면 결과가 좋아집니다.", size=16, bold=True, color=T.muted)
|
||
|
||
add_rect(s, Inches(0.7), Inches(2.0), Inches(11.93), Inches(1.8), fill=T.white, line=T.line, radius=True)
|
||
add_textbox(s, Inches(1.0), Inches(2.2), Inches(11.3), Inches(0.3), "좋은 요청 방식", size=14, bold=True, color=T.muted)
|
||
add_bullets(
|
||
s,
|
||
Inches(1.0),
|
||
Inches(2.55),
|
||
Inches(11.3),
|
||
Inches(1.1),
|
||
["\"문제를 단계별로 해결 절차로 나눠서 제시해줘\"", "\"각 단계마다 체크리스트를 만들고, 누락된 정보를 질문해줘\"", "\"최종 답변은 마지막에 요약해줘\""],
|
||
size=16,
|
||
color=T.text,
|
||
)
|
||
add_rect(s, Inches(0.7), Inches(4.05), Inches(11.93), Inches(2.3), fill=_rgb("#24364D"), line=None, radius=True)
|
||
add_textbox(s, Inches(1.0), Inches(4.25), Inches(11.3), Inches(0.3), "예시 (AX 과제 선정 기준 적용)", size=14, bold=True, color=T.accent_yellow)
|
||
add_textbox(
|
||
s,
|
||
Inches(1.0),
|
||
Inches(4.55),
|
||
Inches(11.3),
|
||
Inches(1.6),
|
||
"과제 후보 3개를 아래 체크리스트 7개 기준으로 하나씩 평가해줘.\n"
|
||
"1) 목표 명확성 2) 데이터 확보 가능성 3) 기대효과(정량/정성)\n"
|
||
"4) 구현 난이도 5) 리스크(보안/규정) 6) 확장성 7) 일정 적합성\n"
|
||
"출력: 표(열: 기준, 평가, 근거, 리스크) + 결론(우선순위) 먼저",
|
||
size=15,
|
||
bold=True,
|
||
color=_rgb("#E5E7EB"),
|
||
line_spacing=1.2,
|
||
)
|
||
add_footer(s, 12, dark=False)
|
||
|
||
|
||
def slide_13_fewshot(prs: Presentation) -> None:
|
||
s = prs.slides.add_slide(prs.slide_layouts[6])
|
||
set_slide_bg(s, T.bg)
|
||
add_textbox(s, Inches(0.7), Inches(0.55), Inches(12), Inches(0.3), "PART 3. 고급 기법", size=14, bold=True, color=T.muted)
|
||
add_textbox(s, Inches(0.7), Inches(0.9), Inches(12), Inches(0.7), "예시 제공 (Few‑Shot Prompting)", size=34, bold=True, color=T.text)
|
||
add_textbox(s, Inches(0.7), Inches(1.55), Inches(12), Inches(0.35), "\"이런 식으로 해줘\" — 예시 1~3개의 위력", size=16, bold=True, color=T.muted)
|
||
|
||
add_rect(s, Inches(0.7), Inches(2.0), Inches(11.93), Inches(2.25), fill=T.white, line=T.line, radius=True)
|
||
add_textbox(s, Inches(1.0), Inches(2.2), Inches(11.3), Inches(0.3), "효과", size=14, bold=True, color=T.muted)
|
||
add_bullets(s, Inches(1.0), Inches(2.55), Inches(11.3), Inches(1.5), ["출력 형식, 어조, 수준을 예시로 통제", "모호한 요구를 '정답 샘플'로 명확히 전달", "팀 내 산출물 스타일을 표준화"], size=16, color=T.text)
|
||
|
||
add_rect(s, Inches(0.7), Inches(4.45), Inches(11.93), Inches(1.9), fill=_rgb("#E9FBF1"), line=_rgb("#BBF7D0"), radius=True)
|
||
add_textbox(s, Inches(1.0), Inches(4.65), Inches(11.3), Inches(0.3), "[사례 3] 응용", size=14, bold=True, color=_rgb("#15803D"))
|
||
add_textbox(
|
||
s,
|
||
Inches(1.0),
|
||
Inches(4.95),
|
||
Inches(11.3),
|
||
Inches(1.2),
|
||
"`20260223_report_10.doc`를 예시로 제공 → 동일 형식의 보고서를 자동 생성\n"
|
||
"프롬프트에 \"예시 문서의 목차/톤/표현을 유지\" 조건을 포함",
|
||
size=16,
|
||
bold=True,
|
||
color=_rgb("#166534"),
|
||
line_spacing=1.2,
|
||
)
|
||
add_footer(s, 13, dark=False)
|
||
|
||
|
||
def slide_14_context_window(prs: Presentation) -> None:
|
||
s = prs.slides.add_slide(prs.slide_layouts[6])
|
||
set_slide_bg(s, T.bg)
|
||
add_textbox(s, Inches(0.7), Inches(0.55), Inches(12), Inches(0.3), "PART 3. 고급 기법", size=14, bold=True, color=T.muted)
|
||
add_textbox(s, Inches(0.7), Inches(0.9), Inches(12), Inches(0.7), "맥락 누적 활용 (Context Window 관리)", size=30, bold=True, color=T.text)
|
||
add_textbox(s, Inches(0.7), Inches(1.55), Inches(12), Inches(0.35), "대화가 길어질수록 앞 조건을 잊을 수 있으니, 핵심 조건을 관리해야 합니다.", size=16, bold=True, color=T.muted)
|
||
|
||
add_rect(s, Inches(0.7), Inches(2.05), Inches(11.93), Inches(1.8), fill=T.white, line=T.line, radius=True)
|
||
add_textbox(s, Inches(1.0), Inches(2.25), Inches(11.3), Inches(0.3), "실무 습관", size=14, bold=True, color=T.muted)
|
||
add_bullets(
|
||
s,
|
||
Inches(1.0),
|
||
Inches(2.6),
|
||
Inches(11.3),
|
||
Inches(1.2),
|
||
["중요한 조건은 대화 앞부분에 배치", "새 대화 시작 시 \"지금까지 정한 것\" 요약을 먼저 붙여넣기", "긴 문서는 분할(Chunk) + 요약 누적 전략 사용"],
|
||
size=16,
|
||
color=T.text,
|
||
)
|
||
|
||
add_rect(s, Inches(0.7), Inches(4.05), Inches(11.93), Inches(2.3), fill=_rgb("#24364D"), line=None, radius=True)
|
||
add_textbox(s, Inches(1.0), Inches(4.25), Inches(11.3), Inches(0.3), "분할 전략 예시", size=14, bold=True, color=T.accent_yellow)
|
||
add_textbox(
|
||
s,
|
||
Inches(1.0),
|
||
Inches(4.55),
|
||
Inches(11.3),
|
||
Inches(1.6),
|
||
"1) 문서를 3~5페이지 단위로 나눠 요약 요청\n"
|
||
"2) 각 요약을 '핵심 포인트/결정사항/숫자' 위주로 정리\n"
|
||
"3) 마지막에 모든 요약을 합쳐 최종 보고서 작성 요청",
|
||
size=16,
|
||
bold=True,
|
||
color=_rgb("#E5E7EB"),
|
||
line_spacing=1.2,
|
||
)
|
||
add_footer(s, 14, dark=False)
|
||
|
||
|
||
def slide_15_iterative(prs: Presentation) -> None:
|
||
s = prs.slides.add_slide(prs.slide_layouts[6])
|
||
set_slide_bg(s, T.bg)
|
||
add_textbox(s, Inches(0.7), Inches(0.55), Inches(12), Inches(0.3), "PART 3. 고급 기법", size=14, bold=True, color=T.muted)
|
||
add_textbox(s, Inches(0.7), Inches(0.9), Inches(12), Inches(0.7), "반복 정제 (Iterative Refinement)", size=34, bold=True, color=T.text)
|
||
add_textbox(s, Inches(0.7), Inches(1.55), Inches(12), Inches(0.35), "첫 번째 답이 완벽할 필요는 없습니다. 초안 → 피드백 → 확정", size=16, bold=True, color=T.muted)
|
||
|
||
add_rect(s, Inches(0.7), Inches(2.05), Inches(11.93), Inches(2.0), fill=T.white, line=T.line, radius=True)
|
||
add_textbox(s, Inches(1.0), Inches(2.25), Inches(11.3), Inches(0.3), "자주 쓰는 후속 프롬프트", size=14, bold=True, color=T.muted)
|
||
add_bullets(
|
||
s,
|
||
Inches(1.0),
|
||
Inches(2.6),
|
||
Inches(11.3),
|
||
Inches(1.3),
|
||
["\"더 간결하게\"", "\"3번 항목을 더 구체적으로\"", "\"전문적 어조로 바꿔줘\"", "\"표로 재구성해줘\"", "\"리스크/반론도 함께 제시해줘\""],
|
||
size=16,
|
||
color=T.text,
|
||
)
|
||
|
||
add_rect(s, Inches(0.7), Inches(4.25), Inches(11.93), Inches(2.1), fill=_rgb("#E9FBF1"), line=_rgb("#BBF7D0"), radius=True)
|
||
add_textbox(s, Inches(1.0), Inches(4.45), Inches(11.3), Inches(0.3), "실무 비유", size=14, bold=True, color=_rgb("#15803D"))
|
||
add_textbox(
|
||
s,
|
||
Inches(1.0),
|
||
Inches(4.75),
|
||
Inches(11.3),
|
||
Inches(1.4),
|
||
"AI는 탁월한 \"초안 작성자\"입니다.\n"
|
||
"사람은 검토자(Reviewer)로서 방향을 잡고, 근거·수치·규정을 확인해 완성도를 올립니다.",
|
||
size=18,
|
||
bold=True,
|
||
color=_rgb("#166534"),
|
||
line_spacing=1.2,
|
||
)
|
||
add_footer(s, 15, dark=False)
|
||
|
||
|
||
def slide_16_files(prs: Presentation) -> None:
|
||
s = prs.slides.add_slide(prs.slide_layouts[6])
|
||
set_slide_bg(s, T.bg)
|
||
add_textbox(s, Inches(0.7), Inches(0.55), Inches(12), Inches(0.3), "PART 3. 고급 기법", size=14, bold=True, color=T.muted)
|
||
add_textbox(s, Inches(0.7), Inches(0.9), Inches(12), Inches(0.7), "파일·데이터 연동 활용", size=40, bold=True, color=T.text)
|
||
add_textbox(s, Inches(0.7), Inches(1.55), Inches(12), Inches(0.35), "CSV, Excel, Word, PDF 등 정형/반정형 데이터를 먹이면 성능이 크게 개선됩니다.", size=16, bold=True, color=T.muted)
|
||
|
||
add_rect(s, Inches(0.7), Inches(2.05), Inches(11.93), Inches(2.35), fill=T.white, line=T.line, radius=True)
|
||
add_textbox(s, Inches(1.0), Inches(2.25), Inches(11.3), Inches(0.3), "실무 예시", size=14, bold=True, color=T.muted)
|
||
add_bullets(
|
||
s,
|
||
Inches(1.0),
|
||
Inches(2.6),
|
||
Inches(11.3),
|
||
Inches(1.7),
|
||
["채용: 지원서(CSV) + 평가 기준(문서) → 자동 평가 코멘트 생성", "과제 선정: 신청 양식 + 프로세스 문서 → 기준별 점수/근거 표 생성", "성과 평가: KPI 테이블 + 코멘트 → 요약 및 이슈 탐지"],
|
||
size=16,
|
||
color=T.text,
|
||
)
|
||
|
||
add_rect(s, Inches(0.7), Inches(4.6), Inches(11.93), Inches(1.75), fill=_rgb("#24364D"), line=None, radius=True)
|
||
add_textbox(s, Inches(1.0), Inches(4.8), Inches(11.3), Inches(0.3), "포인트: 데이터 구조화", size=14, bold=True, color=T.accent_yellow)
|
||
add_textbox(
|
||
s,
|
||
Inches(1.0),
|
||
Inches(5.1),
|
||
Inches(11.3),
|
||
Inches(1.1),
|
||
"AI는 정형 데이터(표/필드)를 더 잘 처리합니다.\n"
|
||
"입력 데이터에 컬럼명, 단위, 기간, 정의를 명시하면 오류가 크게 줄어듭니다.",
|
||
size=16,
|
||
bold=True,
|
||
color=_rgb("#E5E7EB"),
|
||
line_spacing=1.2,
|
||
)
|
||
add_footer(s, 16, dark=False)
|
||
|
||
|
||
def slide_17_trust(prs: Presentation) -> None:
|
||
s = prs.slides.add_slide(prs.slide_layouts[6])
|
||
set_slide_bg(s, T.bg)
|
||
add_textbox(s, Inches(0.7), Inches(0.55), Inches(12), Inches(0.3), "PART 4. 실수하지 않는 AI 활용법", size=14, bold=True, color=T.muted)
|
||
add_textbox(s, Inches(0.7), Inches(0.9), Inches(12), Inches(0.7), "AI를 믿어야 할 때 vs 검증해야 할 때", size=28, bold=True, color=T.text)
|
||
|
||
add_rect(s, Inches(0.7), Inches(1.9), Inches(5.9), Inches(4.45), fill=_rgb("#E9FBF1"), line=_rgb("#BBF7D0"), radius=True)
|
||
add_rect(s, Inches(6.75), Inches(1.9), Inches(5.88), Inches(4.45), fill=_rgb("#FFF1F2"), line=_rgb("#FECACA"), radius=True)
|
||
add_textbox(s, Inches(0.95), Inches(2.15), Inches(5.4), Inches(0.35), "믿어도 되는 경우", size=18, bold=True, color=_rgb("#15803D"))
|
||
add_textbox(s, Inches(7.0), Inches(2.15), Inches(5.4), Inches(0.35), "반드시 검증", size=18, bold=True, color=_rgb("#B91C1C"))
|
||
add_bullets(s, Inches(0.95), Inches(2.6), Inches(5.4), Inches(3.6), ["형식 작업(문장 다듬기, 문서 구성)", "요약, 번역", "초안 작성(메일/보고서)", "코드 생성(단, 테스트/리뷰 필수)"], size=16, color=_rgb("#166534"))
|
||
add_bullets(s, Inches(7.0), Inches(2.6), Inches(5.4), Inches(3.6), ["수치·통계", "법률·규정", "최신 정보", "사람 이름/조직명", "의사결정에 영향을 주는 사실"], size=16, color=_rgb("#7F1D1D"))
|
||
|
||
add_rect(s, Inches(0.7), Inches(6.55), Inches(11.93), Inches(0.65), fill=_rgb("#24364D"), line=None, radius=True)
|
||
add_textbox(s, Inches(1.0), Inches(6.68), Inches(11.3), Inches(0.4), "\"AI가 틀렸다\"가 아니라 \"내가 확인하지 않았다\"", size=18, bold=True, color=_rgb("#E5E7EB"), align=PP_ALIGN.CENTER)
|
||
add_footer(s, 17, dark=False)
|
||
|
||
|
||
def slide_18_security(prs: Presentation) -> None:
|
||
s = prs.slides.add_slide(prs.slide_layouts[6])
|
||
set_slide_bg(s, T.bg)
|
||
add_textbox(s, Inches(0.7), Inches(0.55), Inches(12), Inches(0.3), "PART 4. 보안과 개인정보", size=14, bold=True, color=T.muted)
|
||
add_textbox(s, Inches(0.7), Inches(0.9), Inches(12), Inches(0.7), "무엇을 넣으면 안 되는가", size=40, bold=True, color=T.text)
|
||
add_rect(s, Inches(0.7), Inches(1.9), Inches(11.93), Inches(2.45), fill=_rgb("#FFF1F2"), line=_rgb("#FECACA"), radius=True)
|
||
add_textbox(s, Inches(1.0), Inches(2.1), Inches(11.3), Inches(0.3), "입력 금지", size=16, bold=True, color=_rgb("#B91C1C"))
|
||
add_bullets(s, Inches(1.0), Inches(2.45), Inches(11.3), Inches(1.8), ["사내 기밀 데이터", "개인식별정보(PII): 이름/주민번호/연락처/계좌/주소 등", "고객·환자·직원 데이터 원문", "계약서/특허 등 민감 문서의 원문"], size=16, color=_rgb("#7F1D1D"))
|
||
|
||
add_rect(s, Inches(0.7), Inches(4.55), Inches(11.93), Inches(1.8), fill=_rgb("#E9FBF1"), line=_rgb("#BBF7D0"), radius=True)
|
||
add_textbox(s, Inches(1.0), Inches(4.75), Inches(11.3), Inches(0.3), "대안", size=16, bold=True, color=_rgb("#15803D"))
|
||
add_bullets(s, Inches(1.0), Inches(5.1), Inches(11.3), Inches(1.1), ["가명화/익명화 후 활용 (ID 치환, 숫자 범위화)", "내부/사내 AI 툴 사용 여부 확인", "필요 최소 정보만 제공 + 출력은 요약 중심"], size=16, color=_rgb("#166534"))
|
||
add_footer(s, 18, dark=False)
|
||
|
||
|
||
def slide_19_copyright(prs: Presentation) -> None:
|
||
s = prs.slides.add_slide(prs.slide_layouts[6])
|
||
set_slide_bg(s, T.bg)
|
||
add_textbox(s, Inches(0.7), Inches(0.55), Inches(12), Inches(0.3), "PART 4. 저작권과 책임", size=14, bold=True, color=T.muted)
|
||
add_textbox(s, Inches(0.7), Inches(0.9), Inches(12), Inches(0.7), "AI 결과물의 저작권과 책임", size=36, bold=True, color=T.text)
|
||
add_rect(s, Inches(0.7), Inches(1.9), Inches(11.93), Inches(4.45), fill=T.white, line=T.line, radius=True)
|
||
add_bullets(
|
||
s,
|
||
Inches(1.0),
|
||
Inches(2.2),
|
||
Inches(11.3),
|
||
Inches(3.8),
|
||
["AI 생성물의 법적 지위는 국가/시점/정책에 따라 달라질 수 있음", "출처 표기와 사실 확인의 의무는 사용자에게 있음", "최종 결과물에 대한 책임은 항상 사람에게", "사내 가이드라인(대웅그룹 AI 활용 가이드라인)과 연계해 준수"],
|
||
size=18,
|
||
color=T.text,
|
||
)
|
||
add_footer(s, 19, dark=False)
|
||
|
||
|
||
def slide_20_skills(prs: Presentation) -> None:
|
||
s = prs.slides.add_slide(prs.slide_layouts[6])
|
||
set_slide_bg(s, T.bg)
|
||
add_textbox(s, Inches(0.7), Inches(0.55), Inches(12), Inches(0.3), "PART 4. 역량 재정의", size=14, bold=True, color=T.muted)
|
||
add_textbox(s, Inches(0.7), Inches(0.9), Inches(12), Inches(0.7), "AI 환경에서의 직무 역량 재정의", size=30, bold=True, color=T.text)
|
||
add_rect(s, Inches(0.7), Inches(1.9), Inches(5.9), Inches(4.45), fill=_rgb("#FFF1F2"), line=_rgb("#FECACA"), radius=True)
|
||
add_rect(s, Inches(6.75), Inches(1.9), Inches(5.88), Inches(4.45), fill=_rgb("#E9FBF1"), line=_rgb("#BBF7D0"), radius=True)
|
||
add_textbox(s, Inches(0.95), Inches(2.15), Inches(5.4), Inches(0.35), "상대적으로 약해지는 역량", size=16, bold=True, color=_rgb("#B91C1C"))
|
||
add_textbox(s, Inches(7.0), Inches(2.15), Inches(5.4), Inches(0.35), "더 중요해지는 역량", size=16, bold=True, color=_rgb("#15803D"))
|
||
add_bullets(s, Inches(0.95), Inches(2.55), Inches(5.4), Inches(3.7), ["단순 요약/정리", "반복 문서 작성", "기본 번역", "정형 보고서 초안"], size=16, color=_rgb("#7F1D1D"))
|
||
add_bullets(s, Inches(7.0), Inches(2.55), Inches(5.4), Inches(3.7), ["문제 정의와 목표 설정", "좋은 질문(프롬프트) 설계", "검증·리스크 관리", "의사결정과 책임", "업무 프로세스 설계(워크플로우)"], size=16, color=_rgb("#166534"))
|
||
add_rect(s, Inches(0.7), Inches(6.55), Inches(11.93), Inches(0.65), fill=_rgb("#24364D"), line=None, radius=True)
|
||
add_textbox(s, Inches(1.0), Inches(6.68), Inches(11.3), Inches(0.4), "\"AI에게 좋은 질문을 하는 능력\" = 새로운 핵심 역량", size=18, bold=True, color=_rgb("#E5E7EB"), align=PP_ALIGN.CENTER)
|
||
add_footer(s, 20, dark=False)
|
||
|
||
|
||
def slide_21_scenarios(prs: Presentation) -> None:
|
||
s = prs.slides.add_slide(prs.slide_layouts[6])
|
||
set_slide_bg(s, T.bg)
|
||
add_textbox(s, Inches(0.7), Inches(0.55), Inches(12), Inches(0.3), "PART 5. 실전 적용 — 대웅 AX 과제와 연결", size=14, bold=True, color=T.muted)
|
||
add_textbox(s, Inches(0.7), Inches(0.9), Inches(12), Inches(0.7), "부서별 AI 활용 시나리오 맵", size=40, bold=True, color=T.text)
|
||
|
||
cards = [
|
||
("영업", ["채권 현황 조회", "인사이트 자동 생성"], T.accent_blue),
|
||
("마케팅", ["대시보드 결산 자동 작성", "기사/콘텐츠 초안 생성"], T.accent_yellow),
|
||
("재무/회계", ["지출 증빙 검토 자동화", "이상 지출 탐지"], T.accent_green),
|
||
("연구개발", ["특허·논문 요약", "보고서 초안"], _rgb("#A855F7")),
|
||
("HR", ["면접 분석", "교육 콘텐츠 생성"], T.accent_red),
|
||
]
|
||
x0 = Inches(0.7)
|
||
y0 = Inches(2.0)
|
||
w = Inches(3.82)
|
||
h = Inches(1.75)
|
||
g = Inches(0.35)
|
||
positions = [
|
||
(x0, y0),
|
||
(x0 + w + g, y0),
|
||
(x0 + (w + g) * 2, y0),
|
||
(x0 + w / 2 + g / 2, y0 + h + g),
|
||
(x0 + (w + g) * 1.5, y0 + h + g),
|
||
]
|
||
for (title, lines, accent), (xx, yy) in zip(cards, positions, strict=True):
|
||
add_rect(s, xx, yy, w, h, fill=T.white, line=T.line, radius=True)
|
||
add_rect(s, xx, yy, w, Inches(0.08), fill=accent, line=None)
|
||
add_textbox(s, xx + Inches(0.25), yy + Inches(0.35), w - Inches(0.5), Inches(0.3), title, size=18, bold=True, color=T.text)
|
||
add_bullets(s, xx + Inches(0.25), yy + Inches(0.75), w - Inches(0.5), Inches(0.9), lines, size=14, color=T.muted)
|
||
add_footer(s, 21, dark=False)
|
||
|
||
|
||
def slide_22_ax_application(prs: Presentation) -> None:
|
||
s = prs.slides.add_slide(prs.slide_layouts[6])
|
||
set_slide_bg(s, T.bg)
|
||
add_textbox(s, Inches(0.7), Inches(0.55), Inches(12), Inches(0.3), "PART 5. 실전 적용", size=14, bold=True, color=T.muted)
|
||
add_textbox(s, Inches(0.7), Inches(0.9), Inches(12), Inches(0.7), "AX 과제 신청 단계에서의 AI 활용", size=32, bold=True, color=T.text)
|
||
add_textbox(s, Inches(0.7), Inches(1.55), Inches(12), Inches(0.35), "신청서 작성 → 자기검토 → 평가 기준 정렬까지 한 번에", size=16, bold=True, color=T.muted)
|
||
|
||
add_rect(s, Inches(0.7), Inches(2.05), Inches(11.93), Inches(2.25), fill=T.white, line=T.line, radius=True)
|
||
add_textbox(s, Inches(1.0), Inches(2.25), Inches(11.3), Inches(0.3), "활용 포인트", size=14, bold=True, color=T.muted)
|
||
add_bullets(
|
||
s,
|
||
Inches(1.0),
|
||
Inches(2.6),
|
||
Inches(11.3),
|
||
Inches(1.6),
|
||
["신청서 작성 시 AI 도움받기: As‑Is → To‑Be 구조화", "과제 평가 기준에 맞는 자기검토(누락 항목 질문하도록)", "정량 효과/리스크(보안·규정)까지 포함해 완성도 향상"],
|
||
size=16,
|
||
color=T.text,
|
||
)
|
||
add_rect(s, Inches(0.7), Inches(4.55), Inches(11.93), Inches(1.8), fill=_rgb("#24364D"), line=None, radius=True)
|
||
add_textbox(s, Inches(1.0), Inches(4.75), Inches(11.3), Inches(0.3), "데모 데이터", size=14, bold=True, color=T.accent_yellow)
|
||
add_textbox(
|
||
s,
|
||
Inches(1.0),
|
||
Inches(5.05),
|
||
Inches(11.3),
|
||
Inches(1.2),
|
||
"`20260223.csv` + `AX추진프로세스.docx` → 자동 평가 보고서 생성 시연",
|
||
size=18,
|
||
bold=True,
|
||
color=_rgb("#E5E7EB"),
|
||
line_spacing=1.2,
|
||
)
|
||
add_footer(s, 22, dark=False)
|
||
|
||
|
||
def slide_23_routine(prs: Presentation) -> None:
|
||
s = prs.slides.add_slide(prs.slide_layouts[6])
|
||
set_slide_bg(s, T.bg)
|
||
add_textbox(s, Inches(0.7), Inches(0.55), Inches(12), Inches(0.3), "PART 5. 실전 적용", size=14, bold=True, color=T.muted)
|
||
add_textbox(s, Inches(0.7), Inches(0.9), Inches(12), Inches(0.7), "나만의 AI 활용 루틴 만들기", size=40, bold=True, color=T.text)
|
||
|
||
cards = [
|
||
("Daily", "AI 초안 작성 → 내가 검토·수정", T.accent_blue),
|
||
("Weekly", "반복 업무 프롬프트 템플릿화", T.accent_green),
|
||
("Monthly", "AI 활용 성과 측정 (시간 절감, 품질)", T.accent_yellow),
|
||
]
|
||
x = Inches(0.7)
|
||
y = Inches(2.05)
|
||
w = Inches(3.82)
|
||
h = Inches(2.0)
|
||
g = Inches(0.35)
|
||
for i, (t, d, a) in enumerate(cards):
|
||
xx = x + (w + g) * i
|
||
add_rect(s, xx, y, w, h, fill=T.white, line=T.line, radius=True)
|
||
add_rect(s, xx, y, w, Inches(0.08), fill=a, line=None)
|
||
add_textbox(s, xx + Inches(0.25), y + Inches(0.45), w - Inches(0.5), Inches(0.3), t, size=18, bold=True, color=T.text)
|
||
add_textbox(s, xx + Inches(0.25), y + Inches(0.85), w - Inches(0.5), Inches(0.9), d, size=16, bold=True, color=T.muted, line_spacing=1.2)
|
||
|
||
add_rect(s, Inches(0.7), Inches(4.35), Inches(11.93), Inches(2.0), fill=_rgb("#E9FBF1"), line=_rgb("#BBF7D0"), radius=True)
|
||
add_textbox(s, Inches(1.0), Inches(4.55), Inches(11.3), Inches(0.3), "권장", size=14, bold=True, color=_rgb("#15803D"))
|
||
add_textbox(s, Inches(1.0), Inches(4.85), Inches(11.3), Inches(1.2), "프롬프트 라이브러리를 구축하세요.\n(업무별 템플릿 + 예시 + 검증 체크리스트)", size=20, bold=True, color=_rgb("#166534"), line_spacing=1.2)
|
||
add_footer(s, 23, dark=False)
|
||
|
||
|
||
def slide_24_closing(prs: Presentation) -> None:
|
||
s = prs.slides.add_slide(prs.slide_layouts[6])
|
||
set_slide_bg(s, T.navy)
|
||
add_textbox(s, Inches(0.7), Inches(0.7), Inches(12), Inches(0.4), "PART 5. 마무리", size=14, bold=True, color=_rgb("#D1D5DB"))
|
||
add_textbox(s, Inches(0.7), Inches(1.1), Inches(12), Inches(0.9), "AI와 함께 일하는 미래", size=46, bold=True, color=T.white)
|
||
add_rect(s, Inches(0.7), Inches(2.15), Inches(11.93), Inches(0.05), fill=T.accent_yellow, line=None)
|
||
add_textbox(s, Inches(0.7), Inches(2.35), Inches(12), Inches(0.6), "AI는 대체자가 아닌 증폭기(Amplifier)", size=28, bold=True, color=T.accent_yellow)
|
||
add_bullets(
|
||
s,
|
||
Inches(0.9),
|
||
Inches(3.2),
|
||
Inches(12),
|
||
Inches(2.0),
|
||
["잘 쓰는 사람과 못 쓰는 사람의 격차는 계속 벌어진다", "지금 시작하는 것이 가장 빠른 것", "핵심은: 목적·맥락·제약·형식 + 검증"],
|
||
size=20,
|
||
color=_rgb("#E5E7EB"),
|
||
)
|
||
add_rect(s, Inches(0.7), Inches(5.7), Inches(11.93), Inches(0.9), fill=_rgb("#24364D"), line=None, radius=True)
|
||
add_textbox(s, Inches(0.7), Inches(5.9), Inches(11.93), Inches(0.5), "Q&A / 다음 학습 자원 안내", size=26, bold=True, color=T.white, align=PP_ALIGN.CENTER)
|
||
add_footer(s, 24, dark=True)
|
||
|
||
|
||
def build_ppt() -> Presentation:
|
||
prs = Presentation()
|
||
prs.slide_width = SLIDE_W
|
||
prs.slide_height = SLIDE_H
|
||
|
||
# Slides 1-5 (re-created as editable)
|
||
slide_01_cover(prs)
|
||
slide_02_core_assumptions(prs)
|
||
slide_03_llm(prs)
|
||
slide_04_good_vs_bad(prs)
|
||
slide_05_hallucination(prs)
|
||
|
||
# Slides 6-24 per outline
|
||
slide_06_prompt_definition(prs)
|
||
slide_07_language(prs)
|
||
slide_08_context(prs)
|
||
slide_09_5w1h(prs)
|
||
slide_10_format(prs)
|
||
slide_11_role(prs)
|
||
slide_12_steps(prs)
|
||
slide_13_fewshot(prs)
|
||
slide_14_context_window(prs)
|
||
slide_15_iterative(prs)
|
||
slide_16_files(prs)
|
||
slide_17_trust(prs)
|
||
slide_18_security(prs)
|
||
slide_19_copyright(prs)
|
||
slide_20_skills(prs)
|
||
slide_21_scenarios(prs)
|
||
slide_22_ax_application(prs)
|
||
slide_23_routine(prs)
|
||
slide_24_closing(prs)
|
||
|
||
return prs
|
||
|
||
|
||
def validate(prs: Presentation) -> None:
|
||
if len(prs.slides) != 24:
|
||
raise ValueError(f"expected 24 slides, got {len(prs.slides)}")
|
||
# Ensure no full-slide raster images are used (editable requirement)
|
||
from pptx.enum.shapes import MSO_SHAPE_TYPE
|
||
|
||
pics = 0
|
||
for slide in prs.slides:
|
||
for sh in slide.shapes:
|
||
if sh.shape_type == MSO_SHAPE_TYPE.PICTURE:
|
||
pics += 1
|
||
if pics != 0:
|
||
raise ValueError(f"expected 0 picture shapes, got {pics}")
|
||
|
||
|
||
def main() -> None:
|
||
base_dir = Path(__file__).resolve().parent
|
||
out = base_dir / "outputs" / "ai_work.pptx"
|
||
out.parent.mkdir(parents=True, exist_ok=True)
|
||
prs = build_ppt()
|
||
validate(prs)
|
||
prs.save(str(out))
|
||
print(f"wrote {out} ({out.stat().st_size:,} bytes)")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|
||
|