概要
毎月、社内の勉強会を開催している。 そこではピザや寿司やお酒などを用意するが、一旦自分が立て替えたあとで経費清算を行なう。 で、この経費清算が非常にめんどうで時間がかかる。 毎回およそ1 時間程度かかる。 毎回同じような作業なのでこの時間が非常に虚無だ。
何に時間がかかるのか
弊社では経費申請を行う際に以下のとおりに申請を行わなければならない。
- 会議に参加したメンバーの一覧の提出
- 同じレシートでも軽減税率と標準税率を別々で申請する
- 適格請求書発行事業者登録番号をレシートごとに入力する
1についてはGASを利用してある程度自動化しているので、そこまで大変ではない。 しかし、2と3についてはレシートから金額やTからはじまる適格請求書発行事業者登録番号を目grepしたうえで、正確に入力しなければならない。 めちゃくちゃストレスフルである。
どう解決するか
LLMのVisionを利用することでレシートの金額や適格請求書発行事業者登録番号を正確に読み込んでくれるのではないかという着想を元にdifyでワークフローを組んでみた。
出来上がり

ワークフロー
ユーザ入力
↓
画像をbase 64エンコード
↓
LLM
↓
パラメータ抽出
↓
google spreadsheetからmoney forwardのsecretを取得
↓
コード実行: spreadsheetの内容からaccess tokenを取り出す
↓
money forwardログインAPIをコール
↓
spreasheetにaccess tokenとrefresh tokenを保存
↓
事業者ID取得APIをコール
↓
human in loopでAIの出力を確認
↓
経費申請APIをコール
各ノードの説明
ユーザ入力
入力フォームにファイルとテキストフィールドを設定する。
テキストフィールドには「田中、佐藤、加藤」の形式で参加メンバーの一覧を入力するが、ここの形式は自由。
画像をbase 64エンコード
ノードの中身のコード。
import httpx
import base64
import json
def main(file_url: str):
url = 'http://api:5001' + file_url
with httpx.Client(timeout=10.0, proxies={}) as client:
response = client.get(url)
data = response.content
encoded = base64.b64encode(data).decode('utf-8')
return {
"result": encoded,
"content_type": response.headers.get("Content-Type")
}
ユーザがアップロードしたファイルは即座にdifyがあるサーバにアップロードされる。 ユーザ入力ノードのfile.urlにはアップロード先のurlの相対パスが格納されている。 ここにアクセスすることによって、ファイルを取得することができる。 money forwardの経費申請では画像を添付する必要があり、apiで申請する場合は画像をbase 64エンコードしてパラメータに指定する必要がある。 このコードでは、ユーザがアップロードしたファイルへのアクセスと画像のbase 64エンコードを行っている。
LLM
このノードでllmを設定している。
プロンプトはめちゃくちゃシンプルで、以下の通り。
ユーザがアップロードしたレシートや領収証を解析して以下の形式でまとめてください。
- 合計金額
- 10 %税対象税込額
- 8 %税対象税込額
- 支払先
- 適格請求書発行事業者登録番号(Tから始まる番号。登録番号などで記されるもの)
また、冒頭の通り「ビジョン」機能をオンにして、ユーザ入力ノードのfileを指定している。
パラメータ抽出
llmの出力からパラメータを抽出している。
パラメータ抽出ノードはllmを利用して、前段のテキストから設定したパラメータの抽出を行う。
パラメータ抽出を正規表現を利用せずにできるのはめちゃくちゃ便利。
SpreadSheet
money forwardのapiをコールするにはaccess tokenとrefresh tokenが必要。
money forwardのOAuthでのapi アクセスしかできなかったので、webでの初回ログイン時に発行されたsecretなどを利用して、一度手動でapi callでaccess tokenとrefresh tokenを取得し、spreadsheetに保存している(本当はよくない)。
HTTP ACCESS
色々端折るが、最後はmoneyforwardの経費申請のapiをコールする。
LLMにレシートから標準税率、軽減税率のそれぞれの金額と適格請求書発行事業者登録番号を取得させて、それをパラメータにつめてmoney forwardのapiを叩いてるだけである。
以下のようにhttp bodyを設定すればapi callができる。

{
"ex_transaction":
{
"remark": "{{#1772424599680.remark#}}",
"recognized_at": "2026-03-02",
"value": {{#1772424599680.amount10#}},
"ex_item_id": "hogehoge",
"dr_excise_id": "hogehoge",
"invoice_registration_number": "{{#1772424599680.invoice_register_number#}}",
"memo": "{{#1772413302807.attendee#}}",
"ex_transaction_attendant_representative_attributes": {
"own_name": "name"
},
"ex_transaction_attendant_count_attributes": {
"own_count": 13
},
"receipt_input": {
"content": "{{#1772425251559.result#}}",
"content_type": "{{#1772425251559.content_type#}}",
"filename": "{{#1772413302807.file.name#}}"
}
}
}
まとめ
要はLLMにレシートから標準税率、軽減税率のそれぞれの金額と適格請求書発行事業者登録番号を取得させて、それをパラメータにつめてmoney forwardのapiを叩いてるだけである。 このような簡単なアプリでもとても経費清算が楽になった。 これまでは1時間程度かかる時間が10分で終わるようになった。 嬉しい。