マイクロソフトから様々な形式のドキュメントをMarkdownファイルに変換できるOSSが登場しました。ニュースサイトやXを見て気になり、実際に試してみました。古い情報をRAG向けに整理するのに役立つかもしれません。
以下の記事でも紹介されています:マイクロソフトのMarkdownライブラリhttps://forest.watch.impress.co.jp/docs/serial/yajiuma/1647731.html
内製されている要素があまりないので、Microsoft公式のツールと呼ぶにはちょっと……という感じですが、それでも便利なのは確か。
不安になるコメントです。。
検証結果から
結論から言うと、どのフォーマットからの変換も満足いく結果は得られませんでした。比較的良い結果が得られるPPTでも追加修正が必要でした。ライブラリはまだバージョンがv0.0.1a3なので、これからの改善に期待しています。しかし、SNSでは何人かが「すごい」と発信しているため、ちょっと期待をしてしまいましたが、実際は触っていなかったみたいですね。👻
検証プログラム
README.mdにはBatch Processing Multiple Filesのサンプルコードが提供されており、それを少し改良してTkinterでフォルダを開けるようにしました。
事前準備
パッケージのインストール
pip install markitdown openai
LLMを使用する場合には環境変数OPENAI_API_KEYへAPIキーを格納し、llm_clientの方を有効にします。
どちらかを有効にする
md = MarkItDown(llm_client=client, llm_model="gpt-4o")
md = MarkItDown()
コード全体
# https://github.com/microsoft/markitdown
import os
from tkinter import Tk, filedialog
from markitdown import MarkItDown
from openai import OpenAI
# Tkinterの初期化
root = Tk()
root.withdraw() # メインウィンドウを表示しない
# フォルダ選択ダイアログを表示
folder_path = filedialog.askdirectory(title='フォルダ選択')
if folder_path:
my_api_key = os.getenv("OPENAI_API_KEY")
client = OpenAI(api_key=my_api_key)
md = MarkItDown(llm_client=client, llm_model="gpt-4o")
#md = MarkItDown()
supported_extensions = ('.pptx', '.docx', '.pdf', '.jpg', '.jpeg', '.png')
files_to_convert = [f for f in os.listdir(folder_path) if f.lower().endswith(supported_extensions)]
for file in files_to_convert:
print(f"\nConverting {file}...")
try:
md_file = os.path.splitext(file)[0] + '.md'
result = md.convert(os.path.join(folder_path, file))
with open(os.path.join(folder_path, md_file), 'w', encoding="utf-8") as f:
f.write(result.text_content)
print(f"Successfully converted {file} to {md_file}")
except Exception as e:
print(f"Error converting {file}: {str(e)}")
print("\nAll conversions completed!")
else:
print("フォルダが選択されませんでした。")
実行結果
フォルダを指定して一気に処理することができますので、色々なファイルを試しましたが、今回は下記のファイルを紹介します。
.pptx: マイナンバーの研修資料
.pdf: NVIDIAのセミナー記事 (コピー禁止)
.pdf: マイクロソフトサーフェイスのマニュアル(英語版) (目次あり)
.png: いらすとやの画像
PPTX -> .MD
おおむね出力され、NOTES欄も一覧で確認できましたが、、、よく見ると改行がPPTXの見たままの改行が入っています。😂
「マ
イナンバー法」や~

PPTをよく確認するとテキストボックスがブロックごとに配置されているのではなく、でかい一つのテキストボックスの中で文字を改行や全角スペースでレイアウトを整えている書き方をしている書面でした。。・・・日本のお役所書面対応実装が必要そうです😑

.PDF(コピー禁止・目次なし) → .MD
よくある文字列のコピペを禁止したPDFです。

こちらもテキストの出力は可能でしたが、見出しや段落が取得できず、視覚的な改行が優先されて非常に見辛い状態になりました。目次も判定できないのは残念ですね。

.PDF(英語・目次あり)→.MD
一番成功しそうでしたが、これも失敗。テキストのみの出力結果で、見出し構造が反映されていません。「Markdownとは何ですか?」と聞き返したくなる程残念な結果。
元のPDFはマイクロソフトのSurfaceのユーザーマニュアル英語版です。


.PNG -> .MD
EXIFファイルの解析が行われると想像していたところ、実際には絵の説明が出力されました。内部のプロンプトには独創的な指示が与えられているようで、非常に興味深いです。
また、他の絵でも想像力を働かせ、表現豊かなコメントを見ることができます。
(日本語の説明はmarkitdownの出力ではなく、後から和訳追加しました)
キャラクターの表情は興奮と好奇心を伝え、レンズを通して世界を探索し、記録する情熱的な写真家の本質を捉えています。

コンバートプログラムのアップデート
LLMによる解析を行うオプションをUIに実装しました。マークダウンへの変換がうまく行った場合は、もう少しUIを丁寧に作成したかったところですが、今回の結果が思わしくなかったため、非同期処理やエラー処理を含めずここまでにしておきます。

"""
https://github.com/microsoft/markitdown
このスクリプトは、MarkItDownライブラリを使用してさまざまなファイル形式をMarkdownに変換するためのグラフィカルユーザーインターフェース(GUI)を提供します。
ユーザーが変換するファイルを含むフォルダを選択し、オプションで言語モデル(LLM)を使用して処理を行うことができます。
関数:
- select_folder: ユーザーがフォルダを選択するためのダイアログを開き、パスを保存します。
- start_conversion: フォルダが選択されているか確認し、環境変数からOpenAI APIキーを取得し、LLMの有無に応じてMarkItDownインスタンスを初期化し、選択されたフォルダ内の対応するファイルをリストアップし、各ファイルをMarkdownに変換して結果を保存します。
UI要素:
- 選択されたフォルダパスを表示するラベル。
- フォルダを選択するためのボタンと変換プロセスを開始するためのボタン。
- 処理にLLMを使用するかどうかを切り替えるためのチェックボタン。
依存関係:
- os: オペレーティングシステムとの対話のため。
- tkinter: GUIの作成のため。
- markitdown: ファイルをMarkdownに変換するため。
- openai: OpenAIの言語モデルを使用するため(有効にした場合)。
使用方法:
1. スクリプトを実行します。
2. 変換するファイルを含むフォルダを選択します。
3. オプションでLLM処理を有効にします。
4. "処理開始"ボタンをクリックして変換プロセスを開始します。
"""
import os
from tkinter import Tk, filedialog, Label, Button, Checkbutton, BooleanVar, StringVar
from markitdown import MarkItDown
from openai import OpenAI
def select_folder():
# フォルダを選択し、そのパスを保存
folder_path.set(filedialog.askdirectory(title='フォルダ選択'))
def start_conversion():
# フォルダが選択されているか確認
if folder_path.get():
# 環境変数からAPIキーを取得
my_api_key = os.getenv("OPENAI_API_KEY")
client = OpenAI(api_key=my_api_key)
# LLMの使用有無に応じてMarkItDownのインスタンスを作成
if use_llm.get():
md = MarkItDown(llm_client=client, llm_model="gpt-4o")
else:
md = MarkItDown()
# 対応するファイル拡張子を定義
supported_extensions = ('.pptx', '.docx', '.pdf', '.jpg', '.jpeg', '.png')
# 指定されたフォルダ内の対応するファイルをリストアップ
files_to_convert = [f for f in os.listdir(folder_path.get()) if f.lower().endswith(supported_extensions)]
# 各ファイルをマークダウン形式に変換
for file in files_to_convert:
print(f"\nConverting {file}...")
try:
# ファイル名の拡張子を.mdに変更
md_file = os.path.splitext(file)[0] + '.md'
# ファイルを変換
result = md.convert(os.path.join(folder_path.get(), file))
# 変換結果をファイルに書き込む
with open(os.path.join(folder_path.get(), md_file), 'w', encoding="utf-8") as f:
f.write(result.text_content)
print(f"Successfully converted {file} to {md_file}")
except Exception as e:
print(f"Error converting {file}: {str(e)}")
print("\nAll conversions completed!")
else:
print("フォルダが選択されませんでした。")
# Tkinterの初期化
root = Tk()
root.title("MarkItDown Converter")
# UI用の変数を定義
folder_path = StringVar()
use_llm = BooleanVar()
# UIの作成
Label(root, text="選択されたフォルダ:").grid(row=0, column=0, padx=10, pady=10)
Label(root, textvariable=folder_path).grid(row=0, column=1, padx=10, pady=10)
Button(root, text="フォルダを選択", command=select_folder).grid(row=1, column=0, columnspan=2, padx=10, pady=10)
Checkbutton(root, text="LLMによる処理を行う", variable=use_llm).grid(row=2, column=0, columnspan=2, padx=10, pady=10)
Button(root, text="処理開始", command=start_conversion).grid(row=3, column=0, columnspan=2, padx=10, pady=10)
# メインループ開始
root.mainloop()
まとめ
Markitdownをそのまま使うより、自分で作った方がよさそうな印象です。特に日本のお役所データにも対応できる用にしたり、神エクセルにも対応できるようにちょっと仕様を考えてみたいと思います。(できればAIに丸投げしたいですね)
検証資料ダウンロード元
https://www.ppc.go.jp/files/etc/mynumber_kensyuu_.pptx
https://www.innervision.co.jp/ressources/pdf/innervision2019/iv201907_079.pdf
https://download.microsoft.com/download/B/D/4/BD44C612-D08E-4586-9345-ACA8AB978BC8/eng_Surface_Pro_User_Guide.pdf
コメント