converter.convert2md のソースコード

"""
概要: ファイルをMarkdown形式に変換するツール。
詳細説明:
    このスクリプトは、さまざまなドキュメントファイル(例: docx, pptx, pdf, jpg)をMarkdown形式に変換します。
    MarkItDownライブラリとオプションでOpenAIのAPIを利用して、ファイルの内容を解析し、テキストコンテンツを抽出します。
    特に画像ファイルに対しては、OpenAIの画像解析機能を使用して説明文を生成することができます。
    環境変数`OPENAI_API_KEY`が設定されている場合、OpenAIサービスが利用されます。
関連リンク:
    :doc:`convert2md_usage`
"""
#https://okumuralab.org/~okumura/python/markitdown.html
#https://self-development.info/markitdown%e5%85%a5%e9%96%80-%e3%82%b7%e3%83%b3%e3%83%97%e3%83%ab%e3%81%a7%e5%8a%b9%e7%8e%87%e7%9a%84%e3%81%aa%e6%96%87%e6%9b%b8%e5%a4%89%e6%8f%9b%e3%83%84%e3%83%bc%e3%83%ab/

#https://blog.beachside.dev/entry/2024/12/17/120000
#画像解析に必要: Azure API
#AOAI_ENDPOINT=xxx
#AOAI_API_KEY =xxxx
#AOAI_API_VERSION=2024-10-21
#AOAI_DEPLOYMENT_CHAT=xxxxx

import os
import sys
from types import SimpleNamespace
try:
    from dotenv import load_dotenv, find_dotenv
except:
    print("\npptx2pdf_recursive.py: Import error: dotenv")
    input("Install: pip install dotenv\n")
try:
    from markitdown import MarkItDown
except:
    print("\npptx2pdf_recursive.2py: Import error: markitdown")
    input("Install: pip inistall markitdown\n")
    input("Install: pip inistall markitdown[docx]\n")
    input("Install: pip inistall markitdown[pptx]\n")
    input("Install: pip inistall markitdown[pdf]\n")
try:
    from openai import OpenAI
except:
    print("\npptx2pdf_recursive.py: Import error: openai")
    input("Install: pip inistall openai\n")


[ドキュメント] def initialize(): """ 概要: 設定を初期化し、環境変数を読み込む。 詳細説明: `SimpleNamespace`オブジェクトを作成し、`.env`ファイルから環境変数をロードします。 特に`OPENAI_API_KEY`を読み込み、設定されていない場合は警告を表示します。 Returns: SimpleNamespace: 初期化された設定オブジェクト。`OPENAI_API_KEY`などの変数が含まれます。 """ cfg = SimpleNamespace() # 環境変数の読み込み # if not find_dotenv(): # terminate("Error: .envファイルが見つかりません。") load_dotenv() cfg.OPENAI_API_KEY = os.getenv("OPENAI_API_KEY") if not cfg.OPENAI_API_KEY: print("\nWarning: OPENAI_API_KEYが設定されていません\n") # terminate("Error: OPENAI_API_KEYが設定されていません。") return cfg
[ドキュメント] def replace_path(path, ext): """ 概要: 指定されたファイルパスの拡張子を新しいものに置換する。 詳細説明: 入力パスのファイル名から拡張子を除去し、新しい拡張子を付加したパスを生成します。 入力パスが空の場合、エラーとして終了します。 Parameters: :param path: str: 元のファイルパス。 :param ext: str: 新しい拡張子(例: ".md")。 Returns: str: 新しい拡張子を持つファイルパス。 """ if not path: terminate("Error: 入力パスが空です。") return os.path.splitext(path)[0] + ext
[ドキュメント] def save(path, text): """ 概要: 指定されたパスにテキストコンテンツを保存する。 詳細説明: UTF-8エンコーディングでファイルを書き込みモードで開きます。 保存するテキストが空の場合や、ファイルI/Oエラーが発生した場合はスクリプトを終了します。 Parameters: :param path: str: テキストを保存するファイルパス。 :param text: str: 保存するテキストコンテンツ。 """ if not text: terminate("Error: 保存するテキストが空です。") try: with open(path, "w", encoding="utf-8") as file: file.write(text) except IOError: terminate(f"Error: ファイル {path} の保存に失敗しました。")
[ドキュメント] def update_vars(cfg, args): """ 概要: コマンドライン引数に基づいて設定変数を更新する。 詳細説明: スクリプトの第1引数(インデックス1)を入力ファイルパスとして`cfg.infile`に設定します。 入力ファイルが存在しない場合や、引数が不足している場合はエラーとして終了します。 Parameters: :param cfg: SimpleNamespace: 現在の設定オブジェクト。 :param args: list[str]: コマンドライン引数のリスト (sys.argv)。 Returns: SimpleNamespace: 更新された設定オブジェクト。入力ファイルパスが含まれます。 """ if len(args) > 1: cfg.infile = args[1] if not os.path.exists(cfg.infile): terminate(f"Error: ファイル {cfg.infile} が存在しません。") else: terminate("Error: 入力ファイルが指定されていません。") return cfg
[ドキュメント] def convert_to_md(infile, cfg): """ 概要: 指定された入力ファイルをMarkdown形式のテキストに変換する。 詳細説明: `MarkItDown`ライブラリを使用してファイルを変換します。 `cfg.OPENAI_API_KEY`が設定されている場合、OpenAIクライアントを初期化し、 特に画像ファイル(.jpg)の場合はOpenAIの画像解析機能(`gpt-4o-mini`モデル)を利用して 画像の説明文をMarkdownに含めます。 変換結果が空の場合、エラーとして終了します。 Parameters: :param infile: str: 変換する入力ファイルのパス。 :param cfg: SimpleNamespace: 設定オブジェクト。`OPENAI_API_KEY`を含む可能性があります。 Returns: str: 変換されたMarkdown形式のテキストコンテンツ。 """ # OpenAIクライアントの初期化 if cfg.OPENAI_API_KEY: client = OpenAI() else: client = None if not infile: terminate("Error: 入力ファイルが無効です。") # MarkItDownの設定 if ".jpg" in infile.lower(): print(f"Analyze image file {infile}") md = MarkItDown(mlm_client=client, mlm_model="gpt-4o-mini") result = md.convert(infile, mlm_prompt="画像について説明してください。") else: print(f"Analyze {infile}") md = MarkItDown() result = md.convert(infile) if not result.text_content: terminate("Error: 変換結果が空です。") return result.text_content
[ドキュメント] def convert(infile, outfile): """ 概要: 指定されたファイルをMarkdownに変換し、結果をファイルに保存する。 詳細説明: `initialize`関数で設定をロードし、`convert_to_md`でファイルコンテンツをMarkdownに変換します。 `outfile`が指定されていない場合、入力ファイルと同じディレクトリに`.md`拡張子でファイルを作成します。 変換されたMarkdownテキストは`save`関数によって出力ファイルに書き込まれます。 Parameters: :param infile: str: 変換する入力ファイルのパス。 :param outfile: Union[str, None]: 出力ファイルのパス。Noneの場合、入力ファイル名から自動生成されます。 """ cfg = initialize() filename_without_ext = os.path.splitext(os.path.basename(infile))[0] if outfile is None: outfile = os.path.join(os.path.dirname(infile), f"{filename_without_ext}.md") text = convert_to_md(infile, cfg) print(f"Save to {outfile}") save(outfile, text)
[ドキュメント] def usage(): """ 概要: スクリプトの正しい使用方法を標準出力に表示する。 """ print("\nUSAGE:") print(" python script.py <input_file>") print(" <input_file>: The path to the input file to be converted to markdown.\n")
[ドキュメント] def terminate(message): """ 概要: エラーメッセージを表示し、スクリプトの使用方法を出力して終了する。 Parameters: :param message: str: 終了時に表示するエラーメッセージ。 """ print(message) usage() sys.exit(1)
[ドキュメント] def main(): """ 概要: スクリプトのメイン実行関数。 詳細説明: 設定の初期化、コマンドライン引数からの入力ファイルパスの取得、 Markdownへの変換、そして結果のファイル保存を行います。 最後に使用方法を表示します。 """ cfg = initialize() cfg = update_vars(cfg, sys.argv) outfile = replace_path(cfg.infile, '.md') print("\nConvert document file to markdown file") print(f"infile: {cfg.infile}") print(f"outfile: {outfile}") text = convert_to_md(cfg.infile, cfg) print(text) print(f"Save to {outfile}") save(outfile, text) usage()
if __name__ == "__main__": main()