iT邦幫忙

2025 iThome 鐵人賽

DAY 20
0

昨天我們讓 AI 產生簡報大綱。今天直接把大綱做成 PPT 檔

功能說明

  • 讀取 content.txt(放任何素材:段落、FAQ、圖片說明…)
  • 用 OpenAI 產出 JSON 大綱
  • python-pptx 生成 slides.pptx
  • 自訂中文字型

今天程式碼比較冗長

# make_ppt.py — Day 20:AI 產生 PPT(從大綱到投影片)
import os
import json
from pathlib import Path

from dotenv import load_dotenv
from openai import OpenAI
from pptx import Presentation
from pptx.util import Pt
from pptx.enum.text import PP_ALIGN

# ---------------------------
# 基本設定
# ---------------------------
load_dotenv()
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

INPUT_TXT = Path("content.txt")
OUTPUT_PPTX = Path("slides.pptx")

# 優先挑常見中文字型(視系統可能改名)
FALLBACK_FONT = "Microsoft JhengHei"  # Windows
MAC_FONT = "PingFang TC"              # macOS
FONT_CANDIDATES = [MAC_FONT, FALLBACK_FONT, "Arial"]

def pick_font():
    # 簡單回傳優先順序的第一個(python-pptx不提供列舉系統字型 API)
    return FONT_CANDIDATES[0]

FONT_NAME = pick_font()

# ---------------------------
# 讓 GPT 產生 JSON 大綱
# ---------------------------
def make_outline_json(raw_content: str) -> dict:
    prompt = f"""
你是一位簡報顧問。請將下列資料整理為結構化 JSON 的簡報大綱。
需求:
- 使用繁體中文
- 欄位格式如下(務必回傳合法 JSON,勿加註解):
{{
  "title": "簡報主題",
  "slides": [
    {{"title": "投影片標題", "bullets": ["要點1","要點2","要點3"]}}
  ]
}}
- 5~8 張投影片,每張 2~4 個要點,語句精簡

資料如下:
\"\"\" 
{raw_content}
\"\"\"
"""

    resp = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[
            {"role": "system", "content": "你是嚴謹的結構化輸出專家,只回傳 JSON。"},
            {"role": "user", "content": prompt}
        ],
        temperature=0.5,
        max_tokens=800,
    )

    text = resp.choices[0].message.content.strip()
    # 嘗試解析 JSON;若失敗再做一次修正要求
    try:
        return json.loads(text)
    except Exception:
        fix = client.chat.completions.create(
            model="gpt-4o-mini",
            messages=[
                {"role": "system", "content": "請將下列內容修正為合法 JSON,只輸出 JSON 本體。"},
                {"role": "user", "content": text}
            ],
            temperature=0.0,
            max_tokens=800,
        )
        return json.loads(fix.choices[0].message.content.strip())

# ---------------------------
# 產生 PPT
# ---------------------------
def add_title_slide(prs: Presentation, title_text: str, subtitle_text: str = ""):
    slide_layout = prs.slide_layouts[0]  # Title slide
    slide = prs.slides.add_slide(slide_layout)
    slide.shapes.title.text = title_text

    if subtitle_text:
        subtitle = slide.placeholders[1]
        run = subtitle.text_frame.paragraphs[0].add_run()
        run.text = subtitle_text
        run.font.size = Pt(18)
        run.font.name = FONT_NAME

    # 設定主標題字型
    title = slide.shapes.title
    p = title.text_frame.paragraphs[0]
    for run in p.runs:
        run.font.size = Pt(44)
        run.font.name = FONT_NAME
    p.alignment = PP_ALIGN.CENTER

def add_bullet_slide(prs: Presentation, title_text: str, bullets: list[str]):
    slide_layout = prs.slide_layouts[1]  # Title and Content
    slide = prs.slides.add_slide(slide_layout)

    # 標題
    title_shape = slide.shapes.title
    title_shape.text = title_text
    tp = title_shape.text_frame.paragraphs[0]
    for run in tp.runs:
        run.font.name = FONT_NAME
        run.font.size = Pt(32)

    # 內容(子彈點)
    body = slide.placeholders[1].text_frame
    body.clear()

    for i, text in enumerate(bullets):
        para = body.add_paragraph() if i > 0 else body.paragraphs[0]
        para.text = text
        para.level = 0
        for run in para.runs:
            run.font.name = FONT_NAME
            run.font.size = Pt(20)

def build_ppt(outline: dict, output_path: Path):
    prs = Presentation()
    main_title = outline.get("title", "AI 自動產生簡報")
    add_title_slide(prs, main_title, "由 OpenAI + python-pptx 自動生成")

    for slide in outline.get("slides", []):
        title = slide.get("title", "未命名")
        bullets = slide.get("bullets", [])
        bullets = [b.strip() for b in bullets if b and isinstance(b, str)]
        add_bullet_slide(prs, title, bullets)

    prs.save(str(output_path))

# ---------------------------
# 主流程
# ---------------------------
def main():
    if not INPUT_TXT.exists():
        INPUT_TXT.write_text("請把你的素材貼在這裡:像是文章摘要、FAQ、圖片說明等。", encoding="utf-8")
        print(f"已建立 {INPUT_TXT},先把素材寫進去再執行喔!")
        return

    raw = INPUT_TXT.read_text(encoding="utf-8")
    outline = make_outline_json(raw)
    build_ppt(outline, OUTPUT_PPTX)
    print(f"完成!已輸出:{OUTPUT_PPTX.absolute()}")

if __name__ == "__main__":
    main()
    

來看一下成果:
https://ithelp.ithome.com.tw/upload/images/20251004/20169376u7zU6egsYd.pnghttps://ithelp.ithome.com.tw/upload/images/20251004/20169376OSLImYnUez.png

我們也可以控制風格,把系統訊息調整成「商務簡報/教學簡報/產品發表」等方式
或著是字數控制 圖片插入(可另外寫 add_picture()(python-pptx 支援))
避免亂跑版:子彈點建議 2–4 個,句子短一點

今天我們把 AI 產生的大綱自動做成 PPT:
明天把我們做到這裡的功能包成 FastAPI 服務,變成一支你團隊都能呼叫的小 API!


上一篇
Day 19:報告有了!AI 自動生成簡報大綱
系列文
AI 三十天,哎呀每天都很難:OpenAI API 生存指南20
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言