Pythonでメモからパワポを作成する

## 背景
日頃、発表内容を箇条書きのメモで整理しています。そのメモからパワポのスライドを作成するのですが、メモをパワポにコピペする作業が予想以上に時間を取ります。
そこで、箇条書きのメモから自動でパワーポイントを作成するPythonプログラムを作成しました。

## 動作例
入力例
```txt:input.txt
- 卒業研究進捗報告
    - 今週の成果
        - 文献調査完了
        - 実験計画立案
    - 来週の予定
        - 実験機材準備
        - 予備実験開始
- 就活準備
    - エントリーシート対策
        - 自己PR作成
        - 志望動機整理
    - 面接準備
```
出力例
![スライド2.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3813135/66b193d4-e27f-080c-b0a4-ad3c59fc8bdf.jpeg)
![スライド3.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3813135/1d3614bc-0795-6e50-b056-f76a7ddac71e.jpeg)



## ライブラリのインストール
Pythonでパワーポイントを作成するのにpython-pptxを使用します。
```
pip install python-pptx
```

## コード
このプログラムを使用するには、以下の2つのファイルを準備する必要があります。
- input.txt : プレゼンテーションの内容となる箇条書きのメモをこれに書く
- template.pptx : パワーポイントのひな型となるテンプレートファイルです。生成されるプレゼンテーションのベースになります

```python:main.py
from pptx import Presentation
from pptx.enum.lang import MSO_LANGUAGE_ID


def parse_hierarchical_text(text):
    """
    インデントされたテキストを階層構造に解析する
    :param text: 入力テキスト
    :return: 階層構造を表すリスト
    """
    lines = text.strip().split('\n')
    result = []
    stack = [(-1, result)]

    for line in lines:
        indent = len(line) - len(line.lstrip())
        content = line.strip('- ').strip()

        # 現在の行のインデントレベルに基づいてスタックを調整
        while stack and indent <= stack[-1][0]:
            stack.pop()

        if not stack:
            stack = [(-1, result)]

        parent = stack[-1][1]
        current = []
        parent.append((content, current))
        stack.append((indent, current))

    return result


def add_body(text_frame, items, level=0):
    """
    テキストフレームに階層構造のテキストを追加する
    :param text_frame: PowerPointのテキストフレーム
    :param items: 階層構造のアイテムリスト
    :param level: 現在のインデントレベル
    """
    for item, sub_items in items:
        # 既存のパラグラフを使用するか、新しいパラグラフを追加
        p = text_frame.add_paragraph() if text_frame.text else text_frame.paragraphs[0]
        p.text = item
        p.level = level
        # サブアイテムを再帰的に処理
        add_body(text_frame, sub_items, level + 1)


def set_japanese_language(shape):
    """
    シェイプ内のすべてのテキストの言語を日本語に設定する
    言語を適切に設定しないと、不必要な校正の赤線が引かれる
    :param shape: PowerPointのシェイプオブジェクト
    """
    for paragraph in shape.text_frame.paragraphs:
        for run in paragraph.runs:
            run.font.language_id = MSO_LANGUAGE_ID.JAPANESE


def create_presentation(hierarchy, template_path, output_path):
    """
    階層構造のデータからPowerPointプレゼンテーションを作成する
    :param hierarchy: 階層構造のデータ
    :param template_path: テンプレートファイルのパス
    :param output_path: 出力ファイルのパス
    """
    prs = Presentation(template_path)

    for item, sub_items in hierarchy:
        # prs.slide_layouts[2]: タイトルと本文
        # テンプレートによってレイアウトの種類や順序が異なる場合がある
        slide = prs.slides.add_slide(prs.slide_layouts[2])
        slide.shapes.title.text = item

        # 本文を追加
        body_shape = slide.shapes.placeholders[1]
        add_body(body_shape.text_frame, sub_items)
        set_japanese_language(body_shape)

    prs.save(output_path)
    print(f"{output_path}を作成")


def main():
    input_file = "input.txt"
    template_file = "template.pptx"
    output_file = "example.pptx"

    # 入力ファイルを読み込む
    with open(input_file, encoding="utf-8") as f:
        text = f.read()

    # テキストを解析し、階層構造を作成
    hierarchy = parse_hierarchical_text(text)

    # プレゼンテーションを作成
    create_presentation(hierarchy, template_file, output_file)


if __name__ == "__main__":
    main()
```

## まとめ
箇条書きのメモから自動的にパワーポイントのプレゼンテーションを作成するPythonプログラムを作成しました。メモからスライドへの手動でのコピペ作業が不要になり、プレゼンテーション準備の時間が減らせます。
改善案として、画像の挿入機能や、複雑なレイアウトへの対応などを考えています。