2
1

レシートを読み込んで家計管理をする記録 ~ChatGPTに情報を抽出してもらおう~

Last updated at Posted at 2024-03-21

OCR部分が固まったが、その結果をどう処理するか。。
まずは以下を抽出してみます。
・店名
・購入日時
・購入商品
・合計額

というわけで、手っ取り早くChatGPT-APIを利用することにしました。
確か無料枠があったはずだから一定量のリクエストは金かからないはず。

と思ったら、無料枠の期限切れてました。。。
「コストは0円で抑えたい(抑えるとは言ってない)」状態になってしまいますが、ChatGPT-APIおよびそれを効率的に利用できるLangChainは利用価値が高いので、必要なコストと割り切っていきましょう。

さて、以下がOCRで読み取ったレシートデータ。

領収証
株式会社 富士薬品
ドラッグセイムス 新河岸店
TEL 049-241-2715
2024年02月23日 (金)20時07分 #3969
内* キリン生茶2L
@149
1
SEIMS
内*
*
149
ワンポットエコティーバッグホウジ茶50袋
@386
1
386
-¥58
104
4909411069100
4901085621929
自動割引(クーポン) 15%
内 薬用ハンドソープ 詰替
@104
1
4513574023000
3点
小計
合計
(含む消費税等
(10%対象
消費税
( 8%対象
消費稅
¥581
¥581
¥44)
#104
¥9)
¥477
¥35)
*は軽減税率8%適用商品
¥581
現金
ブロンズ会員(今月) XXXXXXXXX7390
今回現金ポイント
5P
累計現金ポイント
1,110P
5P
今回ギフトポイント
1,859P
累計ギフトポイント
今月の御買上金額 (税抜) 8,364円
上記正に領収いたしました
店: 009554 レジ : 0002
登録番号
累計現金ポイントが400P貯まる毎に
200円の値引特典がご利用頂けます
ランクアップシステムは24年2月29
日をもちまして終了させていただき
ます。 24年3月から新サービス開始
(24年春頃予定) までの間、 セイム
スポイント2倍キャンペーンを実施
いたします。 ※一部対象外商品もご
ざいます。
001800617
T4030001007483
0900955400022402243969

ここから以下を抽出します。
・店名:ドラッグセイムス 新河岸店
・購入日時:2024年02月23日 (金)20時07分
・購入商品リスト[商品名、個数、定価、割引額、購入額(=定価-割引額)]:以下3つ
 [キリン生茶2L、1、149円、0円、149円]
 [ワンポットエコティーバッグホウジ茶50袋、386円、58円、328円]
 [薬用ハンドソープ 詰替、1、104円、0円、104円]
・合計額:581円

 

フェーズ1:とりあえず目的のデータを抽出

まず、形式にこだわらずにデータを取り出せるか確認します。

# LangChainの必要なクラスをインポート
from langchain import PromptTemplate
from langchain.chat_models import ChatOpenAI
from langchain import LLMChain

# OpenAIのモデルのインスタンスを作成
# model_nameでモデルを指定
# temperatureで応答の自由度を指定 0は正確さと再現性に優れている
chat = ChatOpenAI(model_name="gpt-3.5-turbo", temperature=0)

# プロンプトのテンプレート
# dataにレシートのデータが入る
template = """
この領収証データから、以下を抽出してリストアップしてください。
・店名
・購入日時
・購入商品リスト[商品名、個数、定価、割引額、購入額(=定価-割引額)]
・合計額
{data}
"""
prompt = PromptTemplate(
    input_variables=["data"],
    template=template,
)

# チェーンを作成
chain = LLMChain(llm=chat, prompt=prompt,verbose=True)

# チェーンを実行
res = chain(data)

# 結果を表示
print(res['text'])

実行結果

> Finished chain.
・店名: ドラッグセイムス 新河岸店
・購入日時: 2024年02月23日 (金)20時07分
・購入商品リスト:
  1. 商品名: キリン生茶2L、個数: 1、定価: 149円、割引額: 0円、購入額: 149円
  2. 商品名: ワンポットエコティーバッグホウジ茶50袋、個数: 1、定価: 386円、割引額: 58円、購入額: 328円
  3. 商品名: 薬用ハンドソープ詰替、個数: 1、定価: 104円、割引額: 0円、購入額: 104円
・合計額: 581円

無事に目的のデータを抽出できた!

フェーズ2:JSON形式で抽出

お次はプロンプトを変更して、JSON形式で抽出してもらいます。
変更といっても、フェーズ1で「この領収証データから、以下を抽出してリストアップしてください。」と書いてたプロンプトを「この領収証データから、以下を抽出してJsonで構造化してください。」と書き換えるだけです。

# LangChainの必要なクラスをインポート
from langchain import PromptTemplate
from langchain.chat_models import ChatOpenAI
from langchain import LLMChain

# OpenAIのモデルのインスタンスを作成
# model_nameでモデルを指定
# temperatureで応答の自由度を指定 0は正確さと再現性に優れている
chat = ChatOpenAI(model_name="gpt-3.5-turbo", temperature=0)

# プロンプトのテンプレート
# dataにレシートのデータが入る
template = """
この領収証データから、以下を抽出してJsonで構造化してください。
・店名
・購入日時
・購入商品リスト[商品名、個数、定価、割引額、購入額(=定価-割引額)]
・合計額
{data}
"""
prompt = PromptTemplate(
    input_variables=["data"],
    template=template,
)

# チェーンを作成
chain = LLMChain(llm=chat, prompt=prompt,verbose=True)

# チェーンを実行
res = chain(data)

# 結果を表示
print(res['text'])

実行結果

> Finished chain.
{
  "店名": "ドラッグセイムス 新河岸店",
  "購入日時": "2024年02月23日 (金)20時07分",
  "購入商品リスト": [
    {
      "商品名": "キリン生茶2L",
      "個数": 1,
      "定価": 149,
      "割引額": 0,
      "購入額": 149
    },
    {
      "商品名": "ワンポットエコティーバッグホウジ茶50袋",
      "個数": 1,
      "定価": 386,
      "割引額": 58,
      "購入額": 328
    },
    {
      "商品名": "薬用ハンドソープ 詰替",
      "個数": 1,
      "定価": 104,
      "割引額": 0,
      "購入額": 104
    }
  ],
  "合計額": 581
}

問題なくJson形式で出せた!
出力値はあくまで「JSONの形した文字列」なのでJSON形式にパースすることも忘れずに。

# LangChainの必要なクラスをインポート
from langchain import PromptTemplate
from langchain.chat_models import ChatOpenAI
from langchain import LLMChain

# OpenAIのモデルのインスタンスを作成
# model_nameでモデルを指定
# temperatureで応答の自由度を指定 0は正確さと再現性に優れている
chat = ChatOpenAI(model_name="gpt-3.5-turbo", temperature=0)

# プロンプトのテンプレート
# dataにレシートのデータが入る
template = """
この領収証データから、以下を抽出してJsonで構造化してください。
・店名
・購入日時
・購入商品リスト[商品名、個数、定価、割引額、購入額(=定価-割引額)]
・合計額
{data}
"""
prompt = PromptTemplate(
    input_variables=["data"],
    template=template,
)

# チェーンを作成
chain = LLMChain(llm=chat, prompt=prompt,verbose=True)

# チェーンを実行
res = chain(data)
print(type(res['text']))

# GPTから受け取った回答をJson形式にパース
structured_response = json.loads(res['text'])

print(type(structured_response))
print(structured_response)

実行結果

<class 'str'> ←Jsonパース前のresponse
<class 'dict'> ←Jsonパース後のresponse
{'店名': 'ドラッグセイムス 新河岸店', '購入日時': '2024年02月23日 (金)20時07分', '購入商品リスト': [{'商品名': 'キリン生茶2L', '個数': 1, '定価': 149, '割引額': 0, '購入額': 149}, {'商品名': 'ワンポットエコティーバッグホウジ茶50袋', '個数': 1, '定価': 386, '割引額': 58, '購入額': 328}, {'商品名': '薬用ハンドソープ 詰替', '個数': 1, '定価': 104, '割引額': 0, '購入額': 104}], '合計額': 581}

これで良し!
(改行とインデントなくなって読みづらくなったけど、まあいいでしょう。)
これでOCRで読み取ったデータの抽出処理の目途が立ったので、あとはGoogle Vision APIによるOCR処理とがっちゃんこすればメインの処理はいったん完成です。

そろそろ(というか次回投稿で)、全体的なアーキテクチャについても書いていきます。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1