awesometaro

moneyforwardでの経費申請がダルいのでdifyで半自動化する

概要

毎月、社内の勉強会を開催している。 そこではピザや寿司やお酒などを用意するが、一旦自分が立て替えたあとで経費清算を行なう。 で、この経費清算が非常にめんどうで時間がかかる。 毎回およそ1 時間程度かかる。 毎回同じような作業なのでこの時間が非常に虚無だ。

何に時間がかかるのか

弊社では経費申請を行う際に以下のとおりに申請を行わなければならない。

  1. 会議に参加したメンバーの一覧の提出
  2. 同じレシートでも軽減税率と標準税率を別々で申請する
  3. 適格請求書発行事業者登録番号をレシートごとに入力する

1についてはGASを利用してある程度自動化しているので、そこまで大変ではない。 しかし、2と3についてはレシートから金額やTからはじまる適格請求書発行事業者登録番号を目grepしたうえで、正確に入力しなければならない。 めちゃくちゃストレスフルである。

どう解決するか

LLMのVisionを利用することでレシートの金額や適格請求書発行事業者登録番号を正確に読み込んでくれるのではないかという着想を元にdifyでワークフローを組んでみた。

出来上がり

workflow1 workflow1

ワークフロー

ユーザ入力

画像を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をコール

各ノードの説明

ユーザ入力

userinput 入力フォームにファイルとテキストフィールドを設定する。 テキストフィールドには「田中、佐藤、加藤」の形式で参加メンバーの一覧を入力するが、ここの形式は自由。

画像をbase 64エンコード

base64encode ノードの中身のコード。

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-node このノードでllmを設定している。 プロンプトはめちゃくちゃシンプルで、以下の通り。

ユーザがアップロードしたレシートや領収証を解析して以下の形式でまとめてください。
- 合計金額
- 10 %税対象税込額
- 8 %税対象税込額
- 支払先
- 適格請求書発行事業者登録番号(Tから始まる番号。登録番号などで記されるもの)

また、冒頭の通り「ビジョン」機能をオンにして、ユーザ入力ノードのfileを指定している。

パラメータ抽出

parameter-extractor llmの出力からパラメータを抽出している。 パラメータ抽出ノードはllmを利用して、前段のテキストから設定したパラメータの抽出を行う。 パラメータ抽出を正規表現を利用せずにできるのはめちゃくちゃ便利。

SpreadSheet

read_from_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ができる。 http1 http2

{
"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分で終わるようになった。 嬉しい。