"""
概要: ファイルを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()