ChatGPTにPythonスクリプトを書いてもらう(実践1:pptxスライドをpng形式で一括出力)

実践系の記事では、自分の環境が整っている前提でPythonとChatGPTを使ったスクリプト作成について紹介していこうと思います。今回は、途中で発生したトラブルやその対応も交えながら「PowerPointスライドをPNG形式で出力するスクリプト」を作る過程を書いていきます。

背景と目的

GPT-4oでは画像の文字を読み取ることができるため、Powerpointのスライドを画像出力し、ChatGPTにスライドの翻訳と説明文を作ってもらおうと考えました。

しかし、対象のスライド数が40枚以上あり、一回一回画像形式で保存するのは手間だったので、その前段階としてChatGPTにスクリプトも作ってもらうことにしました。

使用ツールなど

今回の作業で使用したものは以下になります。

  • ChatGPT o3-mini-high
  • Visual Studio Code
  • Microsoft PowerPoint

プロンプトの入力

最初のプロンプトは以下のように書きました。やりたいことと要件を適当に書いています。一発で完璧なスクリプトを出してもらうのは難しいので、まずは作ってもらおうと手短に指示しています。

今回は「指定したpptx形式のファイルを開き、スライドを一枚ずつpng形式で出力する」ことが目的になります。それ以外の要件は自分がやりたいように調整していくと良いです。

このプロンプトを入力すると、ChatGPTがコードを書いてくれました。しかし、最初のプロンプトを入力したあとに以下の要件を付け加えています。(ここに逐一出力コードを書いていくと長くなるので割愛します)

  • INPUTに一つのpptxファイルを指定すること(ファイルパスの直接指定)
  • 出力ファイル名はスライド番号+スライドタイトルにすること

色々指示していくと、以下のようなコードになりました。

import os
import re
import win32com.client

def sanitize_filename(filename):
    # Windowsで使用できない文字(\ / * ? : " < > |)を除去する
    return re.sub(r'[\\/*?:"<>|]', "", filename)

# INPUT: pptxファイルのパスを直接指定
input_file = r"C:\Input\プレゼンテーションファイル.pptx"

# OUTPUT: 画像を出力するフォルダを指定
output_folder = r"C:\Output"

# PowerPointを起動(バックグラウンドで実行)
powerpoint = win32com.client.Dispatch("PowerPoint.Application")
powerpoint.Visible = 1  # PowerPointを表示する場合は1、非表示なら0

# pptxファイルを開く
presentation = powerpoint.Presentations.Open(input_file, WithWindow=False)

# 各スライドをPNG画像としてエクスポート
for slide in presentation.Slides:
    slide_title = ""
    # スライド内の図形からタイトルプレースホルダを検索
    for shape in slide.Shapes:
        if shape.HasTextFrame and shape.TextFrame.HasText:
            try:
                # PlaceholderFormat.Typeが1ならタイトルとみなす(ppPlaceholderTitle = 1)
                if shape.PlaceholderFormat.Type == 1:
                    slide_title = shape.TextFrame.TextRange.Text.strip()
                    break
            except Exception:
                continue
    # タイトルが取得できなかった場合はスライド番号をファイル名にする
    if not slide_title:
        slide_title = f"Slide{slide.SlideIndex}"
    
    # ファイル名に使えない文字を除去
    slide_title = sanitize_filename(slide_title)
    # ページ番号を先頭に追加してファイル名を生成(例: "3-スライドタイトル.png")
    file_name = f"{slide.SlideIndex}-{slide_title}.png"
    output_path = os.path.join(output_folder, file_name)
    
    # スライドをPNG形式でエクスポート(エラー発生時はメッセージを表示して続行)
    try:
        slide.Export(output_path, "PNG")
        print(f"Exported: {output_path}")

# プレゼンテーションとPowerPointを閉じる
presentation.Close()
powerpoint.Quit()

ところどころ、どのような処理をしているのか日本語でコメントを入れてくれていてわかりやすいです。
コードを見ると、いくつかのモジュールを使うことになっています。もし自分の環境にインストールされていない場合は動かす前にモジュールのインストールをしておきます。

今回はVisual Studio Codeを開き、このコードを.pyで保存しました。コードは入出力フォルダと対象のファイル指定の箇所だけを手直しします。
なお手っ取り早くテキストエディタで作ってしまっても問題ないです。

エラーの発生と原因分析

実際に実行してみると、途中で以下のエラーが発生し処理が止まってしまいました。

Error exporting slide 23: (-2147352567, '例外が発生しました。', ...)

ChatGPTに聞いてみます。(この時点では日本語が悪さしているのかなと思ってそういう聞き方をしています。)

考えられる原因

ChatGPTが分析した原因はまとめると以下のとおりです。

  • スライドに特殊なオブジェクト(動画や埋め込みファイルなど)が含まれている
  • ファイル名が長すぎるまたは特殊文字が含まれている
  • PowerPointかpywin32ライブラリのバージョンまたは互換性の問題

解決案

ここまでで考えられる対応策は以下の3点です。

  1. 出力ファイル名の長さを制限する(15文字以内)
  2. 特殊文字を除去する
  3. エラーが発生しても次のスライドに進むようにする

コードの修正

今回は応急処置として出力ファイル名に文字数制限を設けてみました。また、エラーで出力されないスライドは一旦無視して次スライドの処理に移ってもらうようにします。

エラー報告をした時点で、ChatGPTがtry-exceptでエラーをキャッチし、そのスライドのみスキップするようにコードを書き換えてくれていました。
追加のプロンプトでは出力ファイル名に文字数制限を設けて、特殊文字は無視するよう指示します。

スクリプトの完成

何度か改良を繰り返し、最終的には以下のようなスクリプトになりました。

import os
import re
import win32com.client

def sanitize_filename(filename):
    # Windowsで使用できない文字(\ / * ? : " < > |)を除去する
    return re.sub(r'[\\/*?:"<>|]', "", filename)

# INPUT: pptxファイルのパスを直接指定(日本語が含まれても基本は問題ありません)
input_file = r"C:\Input\プレゼンテーションファイル.pptx"

# OUTPUT: 画像を出力するフォルダを指定
output_folder = r"C:\Output"

# PowerPointを起動(バックグラウンドで実行)
powerpoint = win32com.client.Dispatch("PowerPoint.Application")
powerpoint.Visible = 1  # PowerPointを表示する場合は1、非表示なら0

# pptxファイルを開く
presentation = powerpoint.Presentations.Open(input_file, WithWindow=False)

# 各スライドをPNG画像としてエクスポート
for slide in presentation.Slides:
    slide_title = ""
    # スライド内の図形からタイトルプレースホルダを検索
    for shape in slide.Shapes:
        if shape.HasTextFrame and shape.TextFrame.HasText:
            try:
                # PlaceholderFormat.Typeが1ならタイトルとみなす(ppPlaceholderTitle = 1)
                if shape.PlaceholderFormat.Type == 1:
                    slide_title = shape.TextFrame.TextRange.Text.strip()
                    break
            except Exception:
                continue

    # タイトルが取得できなかった場合はスライド番号をファイル名にする
    if not slide_title:
        slide_title = f"Slide{slide.SlideIndex}"
    
    # 改行文字を削除
    slide_title = slide_title.replace("\r", "").replace("\n", "")
    # 不要な特殊文字を除去
    slide_title = sanitize_filename(slide_title)
    # 文字数を15文字以内に制限
    slide_title = slide_title[:15]
    
    # ページ番号を先頭に追加してファイル名を生成(例: "3-スライドタイトル.png")
    file_name = f"{slide.SlideIndex}-{slide_title}.png"
    output_path = os.path.join(output_folder, file_name)
    
    # スライドをPNG形式でエクスポート(エラー発生時はメッセージを表示して続行)
    try:
        slide.Export(output_path, "PNG")
        print(f"Exported: {output_path}")
    except Exception as e:
        print(f"Error exporting slide {slide.SlideIndex}: {e}")

# プレゼンテーションとPowerPointを閉じる
presentation.Close()
powerpoint.Quit()

このスクリプトでほぼエラーなく保存ができるようになりましたが、タイトルやセクション見出しスライドだけうまくいかない場合がありました。PlaceholderFormat.Typeを調整すればうまくいくかも?

まとめ

本記事では、PowerPointスライドをPNG形式でエクスポートする自動化スクリプトを作成しました。
作成する中で発生していたエラーの対応としては、応急処置ですが出力ファイル名の文字数を制限し、エラーが発生したスライドをスキップする処理を入れました。これにより、エラーを完全になくすことはできませんでしたが、手作業よりは遥かに早く出力できるようになりました。

業務上、スライドを翻訳したり説明用のスクリプトを作る必要があるため今回のスクリプトを作るに至りました。画像の情報を読み込めるタイプの生成AIであれば、毎回スライドの文字をコピーペーストして指示するよりは格段に楽になります。

タイトルとURLをコピーしました