1. 基本設計
概要
Azure App Serviceを使用して、PDFドキュメントをアップロードし、解析してMarkdown形式に変換するアプリケーションを開発します。PDF内の図は画像として保存し、Markdownには画像のリンクを記載します。保存先はAzure Blob Storageを使用し、Markdownドキュメントはアプリの画面で表示します。
要件
- PDFドキュメントのアップロード機能
- PDFドキュメントの解析とMarkdown形式への変換
- PDF内の図を画像として保存し、Markdownにリンクを記載
- 画像とMarkdownの保存先としてAzure Blob Storageを使用
- Markdownドキュメントの表示機能
- 開発言語はPython
- フレームワークとしてstreamlitを使用
2. システム構成図
3. システムフロー図
4. 必要なパッケージ、ツール
- Streamlit: Webアプリケーションフレームワーク
- azure-storage-blob: Azure Blob Storageとの連携
- PyMuPDF: PDF解析ライブラリ
- Pillow: 画像処理ライブラリ
- markdown2: Markdown変換ライブラリ
5. 詳細設計
PDFアップロード機能
-
エンドポイント:
/upload - メソッド: POST
- 処理内容: PDFファイルを受け取り、Azure Blob Storageに保存
pip install streamlit azure-storage-blob PyMuPDF Pillow markdown2
import streamlit as st
from azure.storage.blob import BlobServiceClient
# Azure Blob Storageの設定
blob_service_client = BlobServiceClient.from_connection_string("your_connection_string")
container_name = "pdf-container"
def upload_pdf(file):
blob_client = blob_service_client.get_blob_client(container=container_name, blob=file.name)
blob_client.upload_blob(file)
st.success("PDF uploaded successfully!")
st.title("PDF Uploader")
uploaded_file = st.file_uploader("Choose a PDF file", type="pdf")
if uploaded_file is not None:
upload_pdf(uploaded_file)
PDF解析とMarkdown変換機能
- エンドポイント: 内部処理
-
処理内容:
- Azure Blob StorageからPDFを取得
- PyMuPDFを使用してPDFを解析
- 画像を抽出し、PillowでJPEG形式に変換
- 画像をAzure Blob Storageに保存
- テキストをMarkdown形式に変換し、画像リンクを挿入
- MarkdownファイルをAzure Blob Storageに保存
import fitz # PyMuPDF
from PIL import Image
import io
def list_blobs(container_name):
container_client = blob_service_client.get_container_client(container_name)
blob_list = container_client.list_blobs()
return [blob.name for blob in blob_list]
def parse_pdf(file_path):
blob_client = blob_service_client.get_blob_client(container=container_name, blob=file_path)
pdf_bytes = blob_client.download_blob().readall()
doc = fitz.open(stream=pdf_bytes, filetype="pdf")
markdown_text = ""
for page_num in range(len(doc)):
page = doc.load_page(page_num)
text = page.get_text("text")
markdown_text += text + "\n\n"
images = page.get_images(full=True)
for img_index, img in enumerate(images):
xref = img[0] # (4, 0, 326, 8, 8, 'DeviceRGB', '', 'Image1', 'DCTDecode', 0)
smask = img[1]
ext_type = img[8] # FlateDecode is png, DCTDecode is jpeg
base_image = doc.extract_image(xref)
image_bytes = base_image["image"]
image = Image.open(io.BytesIO(image_bytes))
image_path = f"image_{page_num}_{img_index}.jpeg"
image.save(image_path)
upload_image_to_blob(image_path)
markdown_text += f"!Image\n\n"
return markdown_text
def upload_image_to_blob(image_path):
blob_client = blob_service_client.get_blob_client(container=container_name, blob=image_path)
with open(image_path, "rb") as data:
blob_client.upload_blob(data)
def convert_to_markdown(file_path):
markdown_text = parse_pdf(file_path)
markdown_file_path = file_path.replace(".pdf", ".md")
with open(markdown_file_path, "w") as md_file:
md_file.write(markdown_text)
upload_markdown_to_blob(markdown_file_path)
def upload_markdown_to_blob(markdown_file_path):
blob_client = blob_service_client.get_blob_client(container=container_name, blob=markdown_file_path)
with open(markdown_file_path, "rb") as data:
blob_client.upload_blob(data)
Markdown表示機能
-
エンドポイント:
/display - メソッド: GET
- 処理内容: Azure Blob StorageからMarkdownファイルを取得し、画面に表示
def display_markdown(file_path):
blob_client = blob_service_client.get_blob_client(container=container_name, blob=file_path)
markdown_content = blob_client.download_blob().readall().decode("utf-8")
st.markdown(markdown_content)
st.title("Markdown Viewer")
markdown_file = st.text_input("Enter the name of the markdown file to display")
if markdown_file:
display_markdown(markdown_file)
Streamlitアプリケーション統合
このコードでは、以下の機能を実装しています:
- PDFファイルのアップロード
- Blob Storageに保存されているPDFファイルのリスト表示と選択
- 選択したPDFファイルのMarkdown形式への変換
- Blob Storageに保存されているMarkdownファイルのリスト表示と選択
- 選択したMarkdownファイルの表示
import streamlit as st
from azure.storage.blob import BlobServiceClient
import fitz # PyMuPDF
from PIL import Image
import io
# Azure Blob Storageの設定
blob_service_client = BlobServiceClient.from_connection_string("your_connection_string")
container_name = "pdf-container"
def list_blobs(container_name):
container_client = blob_service_client.get_container_client(container_name)
blob_list = container_client.list_blobs()
return [blob.name for blob in blob_list]
def upload_pdf(file):
blob_client = blob_service_client.get_blob_client(container=container_name, blob=file.name)
blob_client.upload_blob(file)
st.success("PDF uploaded successfully!")
def parse_pdf(file_path):
blob_client = blob_service_client.get_blob_client(container=container_name, blob=file_path)
pdf_bytes = blob_client.download_blob().readall()
doc = fitz.open(stream=pdf_bytes, filetype="pdf")
markdown_text = ""
for page_num in range(len(doc)):
page = doc.load_page(page_num)
text = page.get_text("text")
markdown_text += text + "\n\n"
images = page.get_images(full=True)
for img_index, img in enumerate(images):
xref = img[0] # (4, 0, 326, 8, 8, 'DeviceRGB', '', 'Image1', 'DCTDecode', 0)
smask = img[1]
ext_type = img[8] # FlateDecode is png, DCTDecode is jpeg
base_image = doc.extract_image(xref)
image_bytes = base_image["image"]
image = Image.open(io.BytesIO(image_bytes))
image_path = f"image_{page_num}_{img_index}.jpeg"
image.save(image_path)
upload_image_to_blob(image_path)
markdown_text += f"!Image\n\n"
return markdown_text
def upload_image_to_blob(image_path):
blob_client = blob_service_client.get_blob_client(container=container_name, blob=image_path)
with open(image_path, "rb") as data:
blob_client.upload_blob(data)
def convert_to_markdown(file_path):
markdown_text = parse_pdf(file_path)
markdown_file_path = file_path.replace(".pdf", ".md")
with open(markdown_file_path, "w") as md_file:
md_file.write(markdown_text)
upload_markdown_to_blob(markdown_file_path)
def upload_markdown_to_blob(markdown_file_path):
blob_client = blob_service_client.get_blob_client(container=container_name, blob=markdown_file_path)
with open(markdown_file_path, "rb") as data:
blob_client.upload_blob(data)
def display_markdown(file_path):
blob_client = blob_service_client.get_blob_client(container=container_name, blob=file_path)
markdown_content = blob_client.download_blob().readall().decode("utf-8")
st.markdown(markdown_content)
# Streamlitアプリケーション
st.title("PDF to Markdown Converter")
# PDFアップロード
st.header("Upload PDF")
uploaded_file = st.file_uploader("Choose a PDF file", type="pdf")
if uploaded_file is not None:
upload_pdf(uploaded_file)
# PDF変換
st.header("Convert PDF to Markdown")
pdf_files = list_blobs(container_name)
selected_pdf = st.selectbox("Select a PDF file to convert", pdf_files)
if st.button("Convert to Markdown"):
convert_to_markdown(selected_pdf)
st.success("PDF converted to Markdown successfully!")
# Markdown表示
st.header("View Markdown Files")
markdown_files = [file for file in list_blobs(container_name) if file.endswith(".md")]
selected_markdown = st.selectbox("Select a Markdown file to view", markdown_files)
if selected_markdown:
display_markdown(selected_markdown)