プログラミング初心者が1日でマスター！ChatGPTとGoogle Apps Scriptで驚きの自作OCRを実現！！

こんにちは！こんばんは！
地方のスーパーでテナントさんの誘致や管理をしているおみえです。

当社では約1500件のテナント契約があり、業種は飲食、サービス、ATMなど多岐にわたります。すべてのテナントに共通して毎月賃料をお支払いいただいており、その請求書発行を私が担当しています。既存のテナントには社内システムを通じて自動で請求書を発行していますが、新しく入店するテナントには社内システム稼働までの間は個別に請求書を発行します。
![18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3754093/47dbda16-9807-cf31-1cd0-27c35aa10b92.png)

# 請求管理の課題と解決策
請求書を発行した後、内容を財務経理部に報告するためPDFをメールで送信し、同時に金額や支払い期限などの詳細をExcelで管理簿に記録しています。~~しかし、忙しい時はこの記録作業を忘れがちです。~~
PDF化・メール・転記と複数の作業をやるとなるとそこそこ時間がかかるので、Excel入力を楽にしたいと思い、請求書の内容を自動で読み取り記録する方法がないか、ChatGPTに相談してみることにしました。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3754093/c2fe8a8c-9313-e7fd-76ef-af67a63fdcd4.png)


OCRを考慮していたところ、Googleドキュメントと書いてあります！Googleを使えば、GoogleドライブにあるPDFをスプレッドシートに転記できるかもしれないと思い、その方法について再度ChatGPTに相談しました。

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3754093/a3131c78-e0fb-8764-9027-f45bd26167de.png)

<strong>解決の糸口が見え、新たな希望が明るく輝き始めました！</strong>

## やりたいこと
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3754093/65beb656-0788-520d-99e4-8bcd2d5c1689.png)

# 完成品

https://x.com/hoshiee38/status/1787132400012763407

+ 動画は一部カット編集しています。
+ 5つのPDFファイルの転記に約1分30秒かかっています。
+ 個人情報保護のため、動画の一部にぼかし処理を施しています。

# 作成方法

## 使用ツール
・[ChatGPT (GPT-3.5)](https://chatgpt.com)
・[Googleドライブ](https://www.google.com/intl/ja_jp/drive/)
・[Googleスプレッドシート](https://www.google.com/intl/ja_jp/sheets/about/)
・[Google Apps Script](https://workspace.google.com/intl/ja/products/apps-script/)

## 事前準備
1. Googleドライブ内にフォルダを作成し、そこにPDFをアップロードします。
今回は以下のような請求書サンプルPDFを５つ作成してドライブの中に保存しました。
2. データ転記用のスプレッドシートも作成します。
![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3754093/7e71e913-a584-c08f-2a4a-38b2d3005f77.png)


## ChatGPTにスクリプトを依頼

![19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3754093/0b2cadff-2614-e369-6a9d-7dbd3cccd908.png)

Google Apps Scriptの詳細な使用方法はこちらを参考にしてください。

https://qiita.com/k_nam/items/9e54ec22b929d4a08e51

さっそくChatGPTに依頼します。
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3754093/3ebb7e12-dc56-34a6-0936-64c622fe7f79.png)

<details><summary><b>最初に生成されたコードはこちら</b></summary>


```javascript:スクリプト
function extractTextFromPDF() {
  // PDFファイルが保存されているGoogleドライブのフォルダIDを入力してください
  var folderId = "Your_Folder_ID_Here";
  
  // Googleドライブの指定されたフォルダからPDFファイルを取得します
  var folder = DriveApp.getFolderById(folderId);
  var files = folder.getFilesByType(MimeType.PDF);
  
  // スプレッドシートに新しいシートを作成します
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = spreadsheet.insertSheet();
  
  // PDFからテキストを抽出してスプレッドシートに転記します
  while (files.hasNext()) {
    var file = files.next();
    var pdf = PdfApp.open(file.getBlob());
    var numPages = pdf.getNumPages();
    
    for (var i = 0; i < numPages; i++) {
      var page = pdf.getPageNum(i);
      var text = page.getText();
      sheet.appendRow([text]);
    }
  }
}

```
:::note warn
<b>参考：GoogleドライブのフォルダIDとは</b>
該当のフォルダを開きブラウザのアドレスバーに表示される`/folders/`の後の部分がフォルダIDとなります。/drive.google.com/drive/u/1/folders/<b>`Your_Folder_ID_Here`</b>
:::
</details>

生成されたコードを見てみると
```javascript
// PDFファイルが保存されているGoogleドライブのフォルダIDを入力してください
// Googleドライブの指定されたフォルダからPDFファイルを取得します
// スプレッドシートに新しいシートを作成します
// PDFからテキストを抽出してスプレッドシートに転記します
```
~~指定されたフォルダからPDFファイルを取得、PDFからテキストを抽出してスプレッドシートに転記します。私がやりたいことの流れですが、~~
新しいシートは作成しなくていいので修正していきます。

![8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3754093/eac5b202-d400-9ccc-212f-0536bf9bb385.png)
このように自分がこうしてほしいという要望をChatGPTに依頼して修正していきます。

:::note
何度も同じエラーに直面し、その原因を調査した結果、Drive APIを有効にする必要があることがわかりました。解決策は下記の記事に記載されています。
※これについてはChatGPTに聞いても解決策がよくわかりませんでした。
:::

https://qiita.com/21HideK/items/4005559995ac2f270528

## 初回成功の結果
エラーが発生しては、その都度ChatGPTに修正を依頼して、初めて成功したのがこちらです。
<img width="250" src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3754093/9cf82a07-6aca-8e57-c54b-2a58ae0ec337.png>

<strong>PDFファイルからテキストを読み取り、スプレッドシートに転記することができました！</Strong>
ただA列に全てが転記されていて、これではデータとして使用しにくいのでスプレッドシートへの転記方法を変更します。

## ChatGPTのプロンプト
<details><summary>プロンプトの一部はこちら</summary>

![10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3754093/66f65b0c-eac7-b1de-1c7b-a52eeb69bdd3.png)
![11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3754093/89f52b53-c90b-457d-9f31-d9a4f9335247.png)
![13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3754093/ea98c6f1-f713-d483-5bc4-44aca0198f7c.png)
![14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3754093/3eec1e45-a3cf-6e71-88e5-56e185a0c1f5.png)
![20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3754093/d179a1ab-184d-9a35-844d-37239ef97b0b.png)
![12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3754093/24fd839a-22e5-a162-003b-2e53a0ccd4ef.png)

</details>
だんだんChatGPTが愛おしくなってきました:relaxed:
※注意：ChatGPTはあくまで人工知能です

## 最終完成スクリプト
<!-- open属性あり -->
<details open><summary><b>最終的に完成したスクリプトはこちら</b></summary>

```javascript:スクリプト
function extractTextFromPDF() {
  // PDFファイルが保存されているGoogleドライブのフォルダIDを入力してください
  var folderId = "Your_Folder_ID_Here";
  
  // Googleドライブの指定されたフォルダからPDFファイルを取得します
  var folder = DriveApp.getFolderById(folderId);
  var files = folder.getFilesByType(MimeType.PDF);
  
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet(); // アクティブなシートを取得
  
  // PDFファイルからテキストを抽出してスプレッドシートに転記します
  while (files.hasNext()) {
    var file = files.next();
    
    // PDFファイルのURLを取得してスプレッドシートに挿入します
    var pdfUrl = file.getUrl();
    
    // PDFからテキストを抽出してスプレッドシートに転記します
    var pdfText = extractTextFromPDFFile(file);
    
    // PDFのURLをA列に挿入します
    sheet.appendRow([pdfUrl]);
    
    // PDFから抽出したテキストをB列から挿入します
    for (var i = 0; i < pdfText.length; i++) {
      sheet.getRange(sheet.getLastRow(), 2 + i).setValue(pdfText[i]);
    }
  }
}

// PDFファイルからテキストを抽出する関数
function extractTextFromPDFFile(file) {
  var pdfBlob = file.getBlob();
  var tempFolder = DriveApp.getRootFolder().createFolder('temp'); // 一時フォルダを作成
  
  var tempFile = tempFolder.createFile(pdfBlob);
  
  // Googleドキュメントを作成します
  var resource = {
    title: file.getName(),
    mimeType: MimeType.GOOGLE_DOCS
  };
  var docFile = Drive.Files.insert(resource, tempFile.getBlob(), {
    convert: true
  });
  
  // ドキュメントを開いてテキストを取得します
  var doc = DocumentApp.openById(docFile.id);
  var text = doc.getBody().getText();
  
  // 一時フォルダとファイルを削除します
  tempFolder.setTrashed(true);
  Drive.Files.remove(docFile.id);
  
  return text.split("\n"); // 改行でテキストを分割して配列に変換
}
```
</details>

実際のプロセスでは、GoogleドライブのフォルダからPDFを取得し、そのテキストを抽出してGoogleドキュメントに転記します。その後、OCR技術を用いてこのテキストを読み取り、Googleスプレッドシートに転記しています。この一連の作業をGoogle Apps Script（GAS）を活用して自動化しています。

![22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3754093/d1acf048-f698-40ab-9389-0b0db0c7e631.png)

## 転記されたスプレッドシート
![15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3754093/c2aebf91-0d7c-80df-32f0-fc2d7dd5de6a.png)

:::note
<strong>工夫した点</strong>
テキストを転記するだけでなく、PDFのファイルURLも読み取ってスプレッドシートのA列に記録しました。このリンクはクリック可能で、直接該当のPDFファイルを開いて確認できます。
:::
<img width="300" src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3754093/a58c7202-c897-f839-5c78-f89530f118ad.png>




# まとめ
## PDFデータ転記の課題
+ 今回の方法では、PDFからすべてのテキストを抽出しているため、不要なテキストも含まれてしまいます。スクリプト内で不要な文言を削除する設定も可能ですが、今回は必要のない列を非表示にすることで対応しました。
+ 今回使用したのはサンプルデータで、全て同じ形式のため列がきれいに揃っていますが、PDFデータの質によっては転記する列がずれることもあります。また、手書きのテキストは読み込むことができませんでした。

ChatGPTに確認したところ、手書きを読み込むためにはGoogle Cloud Vision APIが必要だということでした。Google Cloud Vision APIは認証情報や設定が複雑で、試みたもののうまく機能しませんでした。今後、再度挑戦します！

## ChatGPT使用時の注意点
:::note alert
エラー箇所の修正の場合、修正箇所のみを表示したり、時には元のスクリプトに戻ることもあります。したがって、修正されている箇所の変更や、どこを修正しないといけないか、自分で見極めることも重要です。このプロセスは自身の学びにもつながります！
:::

:::note alert
当初のプロトタイプでは、フォルダIDではなくPDFのファイルIDを使って作成していました。プロンプトの書き方によって生成されるスクリプトが変わるため、~~完成したスクリプトをChatGPTでチェックすると、エラーが指摘されることもあります。~~
作成中にズレが起きないように、明確で具体的なプロンプトを作成することが非常に重要です。
:::

:::note alert
ChatGPTの学習モデルはGPT-3.5の場合、2021年9月までのデータが反映されています（※GPT-4は2023年4月まで）。Googleのアップデートなどにより、設定方法が変わっている場合があるので注意が必要です。
:::
:::note alert
ChatGPTに依頼するスクリプトの中に個人のAPIキー等を含めるべきではありません。一度私が誤ってAPIキーを入力したところ、ChatGPTから「入力すべきでない」と怒られました。
:::

## 多様な活用方法
今回作成したプロトタイプは、スプレッドシートにデータを1行ずつ転記する仕様で、これによりデータ活用の可能性が広がります。AppSheet[^1]でアプリ化したり、Excel形式でダウンロードしてオフライン保存やメール送信など、多様な活用方法を探求しています。
さらに、有料サービスでしか不可能と思っていたOCR技術を用いて、長年の夢であったPDFからの自動転記（OCR）を自分の技術力で実現していきたいと思います！


## ChatGPTとGASで変わる学習効率と新たな自動化への挑戦
Google Apps Script（GAS）を１から学ぼうとすれば1ヶ月以上かかるかもしれませんが、ChatGPTを利用することで、プログラミング経験がない私でもわずか1日で自動化を実現しました。このプロセスを通じてGASの操作を迅速に学ぶことができ、学習時間が大幅に削減されました。
様々なサービスを組み合わせて効果的なツールを開発できるのではと、新しいアイデアを考えることにもっと時間を使うことができるようになり、モチベーションが高まっています。既にGASを使用した自動化を３つ作りましたのでまたご紹介したいと思います！


[^1]: [AppSheet](https://cloud.google.com/appsheet?hl=ja)とは、Google Cloudの一部であるノーコードプラットフォームです。このプラットフォームを使用すると、データベースやスプレッドシートから直接、カスタムモバイルアプリやウェブアプリを簡単に作成できます。プログラミングスキルは不要で、ビジュアルデザイナーとフォームベースのインターフェイスを通じてアプリを構築することが可能です。