インボイス制度スタートを機にfreee会計のほとんどの支出取引に証憑を添付しようとしています。その際にもとのレシート類のファイル名をファイルボックスのメモに転載するようにしているので、もとの証憑のファイル名が重要です。
が、これはもちろん手動でポチポチやる必要があるので、ここを(半分)自動化すべく「連載:Googleドライブに保存したレシートを自動リネームする」に挑戦中です。
前回は、「ドライブに保存したPDFからOCRでテキスト取得」を紹介しました。
「ドライブに保存したPDFからOCRでテキスト取得」を関数化する
今回の開発方針のおさらいです。
- Drive APIのOCR機能でレシート内のテキストを抽出
- 抽出したテキストから必要な情報をGPT APIで抽出
- ↑で取得した情報をもとにPDFファイルをリネーム
前回は、ドライブに保存したPDFからOCRでテキスト取得が成功しました。前回のスクリプトは単純にログ出力するだけだったので、まずこのスクリプトを汎用的に使えるように関数化しておきます。
/**
* 画像ファイルをテキストに変換する関数
*
* @param {string} idImg - 変換する画像ファイルのID
* @param {string} language - OCRの言語設定
* @return {string} 変換されたテキスト
*/
function img2Text_(idImg, language = 'ja') {
// 指定されたIDの画像ファイルを取得
const fileImg = DriveApp.getFileById(idImg);
// 変換後のファイル名とMIMEタイプの設定
const meta = {
name: fileImg.getName().replace(/\..+$/, ''), // 元のファイル名から拡張子を除去
mimeType: MimeType.GOOGLE_DOCS, // Googleドキュメント形式に変換
};
// OCRの設定
const params = {
ocrLanguage: language // OCRに使用する言語を指定
};
// 画像ファイルをGoogleドキュメントに変換
const docTemp = Drive.Files.create(meta, fileImg.getBlob(), params);
// 変換されたドキュメントからテキストを取得
const text = DocumentApp.openById(docTemp.id).getBody().getText();
// 一時的に作成されたドキュメントを削除
DriveApp.getFileById(docTemp.id).setTrashed(true);
return text;
}
ついでに少し変更を加えているのが、元のファイルをPDFに限定しないようにしました。もちろん画像ファイル以外だとエラーになると思うので、ひとまずは運用でカバー。
OpenAI APIを使って質問に答えてもらう
OCRされたテキストは、様々な情報がごちゃごちゃになっています。ここからいい塩梅で「支払日・支払金額・支払先」を抽出するために、Chat GPTでおなじみのOpenAIの技術をお借りします。
OpenAI APIのChatエンドポイント(いわゆるChatGPTに相当)にリクエストを送って、よしなに処理してもらう算段です。
APIキーを取得する
Google Apps Script(以下 GAS)でOpenAI APIを利用するには、APIキーが必要です。ひとまず「OpenAI APIキー取得方法」でググってみてください。
注意点は、多少の無料枠がありますが、基本的に有料となるという点です。
Chatエンドポイントにシンプルな質問をするスクリプト
つづいて、ChatGPTに相当するChatエンドポイントにシンプルな質問をするスクリプトを作成します。
/**
* ChatGPT APIに質問する関数
*
* @param {string} systemRole - システムの役割を指定するメッセージ
* @param {string} prompt - ユーザーからのプロンプト(質問)
* @param {string} [model='gpt-3.5-turbo'] - 使用するモデル(デフォルトは 'gpt-3.5-turbo')
* @return {Object} ChatGPTからの応答を含むオブジェクト
*/
function askChatGPT_(systemRole, prompt, model = 'gpt-3.5-turbo') {
// ChatGPT APIのURL
const urlChatGPT = 'https://api.openai.com/v1/chat/completions';
// APIキーの取得
const apiKey = '取得したAPIキー';
// メッセージの配列を作成
const aryMessage = [
{ role: 'system', content: systemRole },
{ role: 'user', content: prompt }
];
// APIリクエストのペイロードを作成
const payload = {
model: model,
messages: aryMessage
};
// APIリクエストのパラメータを設定
const params = {
contentType: 'application/json',
headers: { Authorization: `Bearer ${apiKey}` },
payload: JSON.stringify(payload),
muteHttpExceptions: false // HTTP例外を無視しない
};
// APIリクエストを送信し、応答を取得
const response = UrlFetchApp.fetch(urlChatGPT, params).getContentText();
const objChat = JSON.parse(response);
return objChat;
}
ということで、ChatGPT APIに質問するaskChatGPT_()関数を作成しました。
この関数は、システムの役割、ユーザーのプロンプト、使用するモデルを引数として受け取り、Chat APIを使用して応答を取得します。
// APIキーの取得
const apiKey = '取得したAPIキー';
はベタ打ちになっていますが、APIキーは、各自プロパティストアなどに格納してください。
使用例はこちら
function demoAskChatGPT() {
// システムの役割を指定するメッセージ
const systemRole = 'あなたは、こんまり流片づけコンサルタントです。';
// ユーザーからのプロンプト(質問)
const prompt = 'デスクの周りを掃除したいです。何からはじめたらよいでしょうか?';
// ChatGPT APIに質問し、応答を取得
const objChat = askChatGPT_(systemRole, prompt);
// 応答をログに出力
const answer = objChat.choices[0].message.content;
console.log('ChatGPTの応答:', answer);
}
ChatGPTの応答: デスクの周りを掃除する際には、以下の手順を参考にすると良いでしょう。
1. 全てを取り除く: デスク上のすべてのアイテムを取り除きます。ペンやメモ帳、書類などを別の場所に移しましょう。
2. 手入れをする: デスクやデスク上の椅子など、表面の汚れを拭き取ります。ディスプレイやキーボードなどのPC周辺機器も、専用のクリーニング剤やクロスできれいにします。
3. 整理する: 取り除いたアイテムをカテゴリごとに分けます。例えば、ペンはペン立てに、文具類は引き出しに、書類は整理ファイルに入れるなど、使いやすい収納方法を考えましょう。
4. 不要なものを処分する: 不要な書類や使わなくなった文房具など、廃棄するか寄付するかを判断します。片づける際には、必要なものだけを残し、整理がしやすいように意識しましょう。
5. 片づけをする: アイテムを整理し、必要な場所に戻します。頻繁に使うものは手の届く場所に置き、あまり使わないものは目立たない場所に収納すると良いでしょう。
6. デスク上の仕上げ: デスク上に必要なアイテムだけを置き、スッキリとした配置にします。余分なものはなるべく取り除き、デスク上を広々と使えるように心がけましょう。以上の手順に従って、デスクの周りを整理していきましょう。片づけは一度やっただけではすぐに乱れてしまうこともありますので、定期的に整理・整頓を行っていくことをおすすめします。
OpenAI APIの回答
どのあたりが「こんまり風」かは不明ですが、ちゃんと答えてくれました。
メッセージ配列の作成
const aryMessage = [
{ role: 'system', content: systemRole },
{ role: 'user', content: prompt }
];
スクリプトのこの部分で、APIに送信するメッセージの配列を作成しています。ここに「システムの役割」と「ユーザーからのプロンプト」を含めます。
APIリクエストのペイロード作成
const payload = {
model: model,
messages: aryMessage
};
APIリクエストのペイロード(payload)とは、クライアント(ユーザー)がサーバーに送信するデータのことを指します。具体的には、APIにリクエストを送る際に、サーバー側に伝える必要がある情報や命令を含むデータの部分です。
ここで使用するモデルを指定します。今回の関数では、デフォルトで”gpt-3.5-turbo”を指定していますが、異なるモデルを指定することも可能です。
戻り値は chat completion object
この関数の戻り値は、chat completion object と呼ばれるオブジェクトです。
このオブジェクトには、メッセージのテキストを示すコンテンツを持つ配列や、使用されたモデルやID、消費したトークンなど、APIの応答に関する詳細が含まれています。
const answer = objChat.choices[0].message.content;
一番知りたい応答メッセージを取得するには、↑のようにオブジェクトの階層を掘っていきます。
履歴を反映した会話のやり取りを行いたい場合
今回の関数では、ChatGPTのような会話の履歴を保持して応答するような機能は実装していません。一方通行な質問と応答を得る関数になっています。
履歴を反映した会話のやり取りを行いたい場合は、私の師匠であるもりさんのブログをご参照ください。
おわりに
無事にGASでOpenAIのAPIにリクエストを送信することができました。ChatGPTの機能をGASで使えるのは色々可能性がありますね。
はじめて、リクエストを送って応答が返ってきた時は、ちょっぴり感動しました。
シリーズ目次
- Googleドライブに保存したレシートを自動リネームする その1 – ドライブに保存したPDFからOCRでテキスト取得
- Googleドライブに保存したレシートを自動リネームする その2 – GASとOpenAI APIを使って質問に答えてもらう
- Googleドライブに保存したレシートを自動リネームする その3 – プロンプトとモデルを調整してJSON形式で応答結果を得る
- Googleドライブに保存したレシートを自動リネームする その4 – フォルダ内のすべてのPDF・画像ファイルをリネームする
Google Apps Scriptを勉強したい方へ
この記事を見て、GASを勉強したいなと思われた方はぜひノンプログラマーのためのスキルアップ研究会(通称 ノンプロ研)にご参加ください。私も未経験からこの学習コミュニティに参加し、講座を受講したことでGASが書けるようになりました。
学習コミュニティ「ノンプログラマーのためのスキルアップ研究会」
挫折しがちなプログラミングの学習も、コミュニティの力で継続できます。ノンプロ研でお待ちしております!
※入会時にfreeelover.comを見て入りました!と言うと、私がちょっぴりお小遣い的なのがもらえるので、私が喜びます。
Amazon欲しい物リスト公開しています。
ブログのモチベーションアップのためにAmazon欲しい物リストを公開しております。役に立ったよ!という方で、感謝の気持ちを示したい方は、何かいただけると嬉しいです笑