【Power Apps】Power AppsからMarkItDown使ってみた【半分AWSじゃん】

:::note info
本記事はPower Apps Advent Calendar 2024 シリーズ2の17日目担当記事になります。
後日会社HP上の技術ブログでもアップさせていただく予定ですので、その際は記事内にリンクを追記させていただきます。
:::

# はじめに

こんにちは、reireです。

みなさん、**MarkItDown**はご存じでしょうか？
https://github.com/microsoft/markitdown
<img src="https://artisan.jp.net/wp-content/uploads/2024/12/MID_18.png" alt="github" style="zoom:50%;" />

**MarkItDown**はつい最近Microsoftより公開された**Pythonライブラリ**で、以下のような様々なファイルを**Markdownテキストに変換**してくれるとのことです。

- PDF (.pdf)
- PowerPoint (.pptx)
- Word (.docx)
- Excel (.xlsx)
- 画像（EXIFメタデータおよびOCR）
- 音声（EXIFメタデータおよび音声の文字起こし）
- HTML（Wikipediaなどの特別な処理を含む）
- その他のさまざまなテキスト形式（csv、json、xmlなど）

OCR処理や音声ファイルの文字起こしまでしてくれる、というのはかなり気になりますね。

そこでさっそく試してみようと思ったのですが、ただ試しても面白みがないかな～と思い。
せっかくMicrosoftから提供されているのであれば、**Power Apps**や**Power Automate**と絡められれば面白いのでは？ということでチャレンジしてみました。

ということで今回はPower AppsからMarkItDownを使う方法について解説していきたいと思います。



# 動作イメージ

こんな感じの動作になりました！
![App_Excel](https://artisan.jp.net/wp-content/uploads/2024/12/MID_15.gif)

# アーキテクチャ

今回は以下のようなアーキテクチャで構築していきました。
<img src="https://artisan.jp.net/wp-content/uploads/2024/12/MID_1.png" alt="アーキテクチャ" style="zoom:50%;" />

つまるところ、AWS上のLambdaにMarkItDownの処理を実装、それをAPI GatewayでREST API化し、Power Automateを介してPower Appsから叩けるようにした感じです。

また、Power AppsではMarkdownテキストを直接描画できないので、Lambda側でMarkdownテキストをさらにHTMLテキストにしています。

今回はあくまでも個人でのテスト用ということで、**各所かなり適当**ですがお許しください！！！

# 構築

構築を始めていきます。

## 1.  Lambda

### 1.1 Lambda関数の作成

まずはLambda関数を作成します。
<img src="https://artisan.jp.net/wp-content/uploads/2024/12/MID_2.png" alt="Lambda関数" style="zoom:50%;" />

中身はこんな感じ。
エラー処理なんてそんなお利口さんなことはしません。

```python
# 必要なモジュールをインポート
import json
import base64
import markdown
from markitdown import MarkItDown

def lambda_handler(event, context):

    md = markdown.Markdown(extensions=['tables'])
    markitdown = MarkItDown()

    # リクエストボディからJSONデータを解析
    body = json.loads(event['body'])

    # リクエストボディからファイルデータとファイル名を取得
    base64_data = body.get('file')
    file_name = body.get('filename')

    # Base64デコードしてバイナリデータを取得
    binary_data = base64.b64decode(base64_data)

    # 一時ファイルパスを生成
    file_path = f"/tmp/{file_name}"

    # デコードしたバイナリデータを一時ファイルに保存
    with open(file_path, "wb") as file:
        file.write(binary_data)

    # MarkItDownを使ってMarkdownに変換
    Markdown_text = markitdown.convert(file_path)

    # 変換結果のMarkdownをHTMLに変換
    HTML_text = md.convert(Markdown_text.text_content)

    # APIレスポンスでMarkdownテキストとHTMLテキストを返す
    return {
        'statusCode': 200,
        'body': json.dumps({
            'Markdown_Text': Markdown_text.text_content,
            'HTML_Text': HTML_text
        })
    }
```



### 1.2 Layerの作成、追加

次に、Lambda関数に対してLayerを追加します。

というのも、デフォルトのLambda環境ではMarkItDownなどのサードパーティー製ライブラリはインストールされていません。
そのため、自身で使用したいライブラリやモジュールをまとめて一度zip形式にし、Layerとして作成してあげる必要があります。

今回は本命であるMarkdown変換を行う**MarkItDown**ライブラリと、変換したMarkdownテキストをさらにHTMLテキストに変換する**Markdown**ライブラリをLayerとして追加しました。
<img src="https://artisan.jp.net/wp-content/uploads/2024/12/MID_3.png" alt="Lambda_Layer" style="zoom:50%;" />

MarkItDown結構ファイルサイズ大きかったのでS3にアップロードしています。
<img src="https://artisan.jp.net/wp-content/uploads/2024/12/MID_4.png" alt="Lambda_Layer_S3" style="zoom:50%;" />



## 2. API Gateway

続いてAPI Gatewayです。

### 2.1 REST APIの作成

まずはREST APIを作成し、POSTメソッドを追加します。
<img src="https://artisan.jp.net/wp-content/uploads/2024/12/MID_5.png" alt="API" style="zoom:50%;" />

**Lambdaプロキシ統合**は有効にしましょう。
<img src="https://artisan.jp.net/wp-content/uploads/2024/12/MID_6.png" alt="API_Lambda" style="zoom:50%;" />

### 2.2 APIキーや使用量プラン

作成したAPIに対し、APIキーの作成と使用量プランの関連付けを行います。
<img src="https://artisan.jp.net/wp-content/uploads/2024/12/MID_7.png" alt="API_plan" style="zoom:50%;" /><img src="https://artisan.jp.net/wp-content/uploads/2024/12/MID_8.png" alt="API_key" style="zoom:50%;" />



これで先ほど作成したLambda関数がAPIとして叩けるようになります。



## 3. Power Automate

ここまでくれば後はいつも通りPower Platformでの作業です。

### 3.1 フローのトリガー

トリガーはもちろんPower Appsのフロー呼び出しトリガー。
ファイル名、ファイルコンテンツを受け取ります。
<img src="https://artisan.jp.net/wp-content/uploads/2024/12/MID_9.png" alt="Flow_trigger" style="zoom:50%;" />

### 3.2 API呼び出しとレスポンスの解析

続いてHTTPアクションを配置し、先ほどAPI Gatewayで作成したAPIのパラメーターを入力していきます。
<img src="https://artisan.jp.net/wp-content/uploads/2024/12/MID_10.png" alt="Flow_HTTP" style="zoom:50%;" />

:::note warn
本来Power Automate上でAPIキーなどの機密性の高い値を扱う場合は、
ソリューション化して環境変数として設定してあげるようにしましょう。
:::

その後はJsonの解析アクションでAPIからのレスポンスのJsonテキストを解析します。
<img src="https://artisan.jp.net/wp-content/uploads/2024/12/MID_11-1.png" alt="Flow_Json" style="zoom:50%;" />

### 3.3 SharePoint上にファイル作成

APIから受け取ったMarkdownテキストをコンテンツにして任意のSharePointライブラリ上にファイルを作成し、リンクを取得するためにプロパティ取得のアクションを実行します。
<img src="https://artisan.jp.net/wp-content/uploads/2024/12/MID_19.png" alt="Flow_Json" style="zoom:50%;" />
<img src="https://artisan.jp.net/wp-content/uploads/2024/12/MID_20.png" alt="Flow_Json" style="zoom:50%;" />

### 3.4 Power Appsへの応答

最後にPower Apps応答アクションでHTMLテキストとファイルリンクを返して完成
<img src="https://artisan.jp.net/wp-content/uploads/2024/12/MID_12-1.png" alt="Flow_App" style="zoom:50%;" />



## 4. Power Apps

これでMarkItDownを実行する準備は整いました。
最後にPower Appsを作成していきましょう。

### 4.1 Power Automateフローの追加

先ほど作成したPower AutomateフローをPower Appに追加します。
<img src="https://artisan.jp.net/wp-content/uploads/2024/12/MID_13.png" alt="Apps_Flow_Add" style="zoom: 67%;" />



### 4.2 コントロールの配置

以下のようにコントロールを配置します。
<img src="https://artisan.jp.net/wp-content/uploads/2024/12/MID_14.png" alt="App_Control" style="zoom:50%;" />



### 4.3 各コントロールのプロパティ設定

以下のように、各コントロールのプロパティを設定していきます。

- FileUploader

  ```FileUploader.MaxAttachments
  //今回は複数ファイルを一発で変換できるように構築していないため、とりあえず1ファイルに制限しておく
  1
  ```
  
  ```FileUploader.MaxSize
  //任意のサイズ
  30
  ```

- FileContents
  ```FileContents.Image
  //FileUploaderにアップしたファイルのコンテンツを設定
  First(FileUploader.Attachments).Value
  ```

- Button
  ```Button.OnSelect
  //Json関数でFileUploaderにアップしたファイルをBase64に変換し、不要な文字列を削除
  Set(
      FileJson,
      Substitute(Match(JSON(FileContents.Image,JSONFormat.IncludeBinaryData),"(?<=base64,).*").FullMatch,"""","")
  );
  
  //Power Automateフローを実行し、レスポンスを受け取る
  Set(
      res,
      Markitdown.Run(FileJson,First(FileUploader.Attachments).Name)
  );
  
  //FileUploaderをリセット
  Reset(FileUploader);
  
  //Markdownファイルのダウンロード
  Download(res.path);
  ```

- HtmlViewer

  ```HtmlViewer.HtmlText
  res.htmltext
  ```

おつかれさまです、これでPower Apps側も完成です！

# 動作確認

動作を試してみましょう。

まずはExeclファイル
![App_Excel](https://artisan.jp.net/wp-content/uploads/2024/12/MID_15.gif)
HTMLテキストを通してMarkdown表形式で表示され…
![App_Excel](https://artisan.jp.net/wp-content/uploads/2024/12/MID_21.png)
更にMarkdownファイルもダウンロードすることができました！

続いてドキュメントファイルを試してみましょう。
まずはWordから
![App_Excel](https://artisan.jp.net/wp-content/uploads/2024/12/MID_16.gif)
![App_Excel](https://artisan.jp.net/wp-content/uploads/2024/12/MID_22.png)

そしてPowerPoint
![App_Excel](https://artisan.jp.net/wp-content/uploads/2024/12/MID_17.gif)
![App_Excel](https://artisan.jp.net/wp-content/uploads/2024/12/MID_23.png)

こちらも単にテキストだけでなく、見出しやリストが反映されているようです！

このようにMarkItDownを使うことで、社内に散在する様々な文書のMarkdown化を効率よく進めることができそうですね！



# おわり

かなり長くなってしまいましたが、Power AppsからMarkItDownを実行する手順の解説でした。
併せて、AWS上に自作のAPIを作成し、Power AutomateからHTTPアクションでリクエストする手順の解説にもなりましたね。

**MarkItDown**は最近公開されたライブラリですが、ざっくりExcelやWord、PowerPoint、PDFあたりはそこそこの感じでMarkdown化してくれる様子でした。

ただし、画像ファイルと音声ファイルについてはどうにも実行できず。
軽く調べてみた感じ、これらのMarkdown化を行うにはOpenAIなどのLLMとの連携が必要なように思われます。

:::note warn
GPT-4oを使ってみようと思ったのですが、OpenAIのライブラリまで追加しようとするとLambda Layerの容量制限に引っかかり、少なくとも今回の構成では実行できそうにありませんでした；；
:::
また、MarkItDown自体の中身を見てみたところ既存ライブラリをまとめて使いやすいインターフェースにしたという側面が強いように見えますし、まだ発展途上という感じなんですかね、しばらく様子見つつ試してみます。

以上、MarkItDownを触ってみた所感でした。

実は本記事のネタを思いついたのがAdvent Calendar投稿日前日でして、そこから気合で構築、検証してなんとかAdvent Calendar当日の午前3時に書き上げるというかなりの雑構築＆雑解説となってしまいました。
Advent Calendarに投稿するのにクオリティこんなんで大丈夫なのかと大変恐縮なのですが、テーマ自体はそこそこ面白いものを書けたのかな、と思います。
みなさんもぜひMarkItDownを試してみてはいかがでしょうか。

それでは今回はここまで。
引き続き、Power Platformを楽しんでいきましょう！

それでは