🤖

GCPを使用してPDFファイルをアップロード、分析、保存するアプリケーションの構築

2024/03/27に公開

こんにちは、ikechan こといけがわです。

最近社内で「Document AI」や「BigQuery」に関して話を聞く機会がありました。個人的にGCPのコンソールを使用しサービスを活用したことがほとんどなかったことや、アプリケーション上どのようにして実装するのか気になったので、メモがてら簡単に実装内容を記事に残そうかと思います。

前提条件

GCPのプロジェクトが作成済みであること
必要なGCPサービス(Cloud Storage、Document AI、BigQuery)のAPIが有効化されていること
開発環境にNode.jsとnpmがインストールされていること
Honoフレームワークの基本的な使用方法を理解していること

使用するGCPサービス

Cloud Storage

Cloud StorageはGCPが提供するオブジェクトストレージサービスです。本アプリケーションでは、アップロードされたPDFファイルを一時的に保存するために使用します。

Document AI

Document AIは、ドキュメントの分析と処理を自動化するためのサービスです。本アプリケーションでは、アップロードされたPDFファイルからテキストデータを抽出するために使用します。

BigQuery

BigQueryは、フルマネージドのデータウェアハウスサービスです。本アプリケーションでは、分析結果をテーブルに保存し、保存されたデータを照会するために使用します。

使用するPDF

アプリケーションの構築

Honoで新しいプロジェクト作成

npm create hono@latest my-app

必要なパッケージをインストール
[Cloud Storage]

npm install @google-cloud/storage

[Document AI]

npm install @google-cloud/storage

[BigQuery]

npm install @google-cloud/storage

実際のソースコード

import { Hono } from "hono";
import { serve } from "@hono/node-server";
import { Storage } from "@google-cloud/storage";
import { DocumentProcessorServiceClient } from "@google-cloud/documentai";
import { BigQuery } from "@google-cloud/bigquery";
import fs from "fs";

const app = new Hono();

// 環境変数から設定を取得
const projectId = process.env.PROJECT_ID;
const processorId = process.env.DOCUMENT_AI_PROCESSOR_ID;
const datasetId = process.env.BIGQUERY_DATASET_ID;
const tableId = process.env.BIGQUERY_TABLE_ID;
const bucketName = process.env.STORAGE_BUCKET_NAME;
const port = process.env.PORT || 8080;

// Google Cloud Storage用の設定
const storage = new Storage({ projectId });

// Document AI用の設定
const documentAI = new DocumentProcessorServiceClient();

// BigQuery用の設定
const bigQuery = new BigQuery({ projectId });

// BigQueryのテーブルを作成する関数
async function createTableIfNotExists() {
  const dataset = bigQuery.dataset(datasetId);
  const [tableExists] = await dataset.table(tableId).exists();

  if (!tableExists) {
    await dataset.createTable(tableId, {
      schema: {
        fields: [
          { name: "document_id", type: "STRING" },
          { name: "text", type: "STRING" },
        ],
      },
    });
    console.log(`Table ${tableId} created with schema.`);
  }
}

// ファイルアップロード用のエンドポイント
app.post("/upload", async (c) => {
  const localFilePath = "履歴書.pdf";

  // ローカルのPDFファイルを読み込む
  const fileContent = await fs.promises.readFile(localFilePath);

  // Cloud Storageにファイルをアップロード
  const bucketFile = storage.bucket(bucketName).file("zenn_sample.pdf");
  await bucketFile.save(fileContent);

  // Cloud StorageからファイルをダウンロードしてDocument AIで分析
  const [downloadedFile] = await bucketFile.download();
  const request = {
    name: processorId,
    rawDocument: {
      content: Buffer.from(downloadedFile).toString("base64"),
      mimeType: "application/pdf",
    },
  };
  const [result] = await documentAI.processDocument(request);
  const { document } = result;

  // BigQueryのテーブルを作成(もしまだ存在しない場合)
  await createTableIfNotExists();

  // textをBigQueryに保存
  console.log("document", document);
  if (document) {
    const row = {
      document_id: "document_1",
      text: document.text,
    };

    try {
      await bigQuery.dataset(datasetId).table(tableId).insert([row]);
      console.log("Text data inserted into BigQuery.");
    } catch (error) {
      console.error("Error inserting data into BigQuery:", error);
      // エラーメッセージを返すか、適切なエラーハンドリングを行う
    }

    return c.json({ message: "File uploaded and processed successfully" });
  }
});

// BigQueryからデータを取得するエンドポイント
app.get("/data", async (c) => {
  const query = `SELECT * FROM \`${datasetId}.${tableId}\``;
  const [rows] = await bigQuery.query(query);

  return c.json(rows);
});

serve({
  fetch: app.fetch,
  port: port,
});

upload実行の結果

// http://localhost:8080/upload
{
"message": "File uploaded and processed successfully."
}

data取得結果

[
 {
 "document_id": "document_1",
 "text": "履歴書\n自分の名前\n郵便番号\n都道府県 市区町村 番地\n(+81) 000-0000\nNO_REPLY@EXAMPLE.COM\nスキル\n●\nここにテキストを挿入。\n職歴\n20XX年XX月~現在\n会社名(場所) - 役職\n•\nここにテキストを挿入。\n20XX年XX月~20XX年XX月\n会社名(場所) - 役職\n•\nここにテキストを挿入。\n20XX年XX月~20XX年XX月\n会社名(場所) - 役職\n•\nここにテキストを挿入。\n学歴\n20XX年XX月~20XX年XX月\n学校名(場所) - 学位\n•\nここにテキストを挿入。\n受賞歴\n•\nここにテキストを挿入。\n"
 }
]

まとめ

本記事では、Google Cloud Platform(GCP)のサービスであるCloud Storage、Document AI、BigQueryを使用して、PDFファイルをアップロード、分析、保存するアプリケーションの簡単な実装方法について紹介しました。Honoフレームワークを使用することで、シンプルかつ効率的なAPIの実装が可能です。

最後に、toraco株式会社ではエンジニアを積極採用中です。
フロントエンドエンジニア、バックエンドエンジニア、クラウドインフラエンジニアなど職種問わず、様々な技術領域にチャレンジできます。また、PM(プロジェクトマネージャー) や EM(エンジニアリングマネージャー)のキャリアパスも用意しています。
興味のある方は Wantedly,typeの募集をぜひ読んでください!

お知らせ

最後に、toraco株式会社では2024年11月1日にエンジニア向けのコミュニティを立ち上げました。
Discord のサーバーで運営しており、以下のリンクから無料で参加できます。コミュニティ内では以下のような投稿・活動がされます!

https://discord.gg/pxfMjDfsge

  • もくもく会・作業ラジオ・雑談部屋などオンライン上での交流
  • オフラインイベントの案内
  • 代表の稲垣(トラハック)が公開するコンテンツの説明・質問回答
  • toraco株式会社からの副業や案件の紹介
  • フロントエンド関連技術の情報共有および議論
  • 生成AI関連技術のキャッチアップ
  • その他、技術領域にこだわらない情報共有および議論
toraco株式会社のテックブログ

Discussion