Firebase FunctionsでPDF解析機能を実装した実装記録

Tags
Next.js
Published
February 13, 2025
Author

はじめに

文書添削AIツールを開発する中で、PDFファイルのアップロードと解析機能を実装することになりました。この記事では、特にFirebase Functions側の実装に焦点を当てて、開発過程を共有します。

システム構成

  • フロントエンド: Next.js (App Router)
  • バックエンド: Firebase Functions
  • PDF処理: pdf.js
  • CORS対応: cors middleware

Firebase Functions の実装

1. プロジェクトの初期設定

まず、Firebase Functionsのプロジェクト構成を設定します。
{ "name": "functions", "description": "Cloud Functions for Firebase", "type": "module", "scripts": { "serve": "firebase emulators:start --only functions", "deploy": "firebase deploy --only functions" }, "engines": { "node": "16" }, "dependencies": { "firebase-admin": "^9.8.0", "firebase-functions": "^3.14.1", "pdfjs-dist": "^3.11.174", "cors": "^2.8.5" } }

2. PDF処理関数の実装

Firebase Functionsでのメイン処理を実装します。
import { https } from "firebase-functions"; import * as pdfjsLib from "pdfjs-dist"; import cors from "cors"; import admin from "firebase-admin"; admin.initializeApp(); const corsHandler = cors({ origin: "*", methods: ["POST", "OPTIONS"], }); export const extractpdftext = https.onRequest((request, response) => { return corsHandler(request, response, async () => { try { if (request.method !== "POST") { response.status(405).send("Method Not Allowed"); return; } const pdfBuffer = request.body.pdfBuffer; if (!pdfBuffer) { response.status(400).send("PDF data is required"); return; } // PDFからテキストを抽出 const pdf = await pdfjsLib.getDocument(pdfBuffer).promise; let fullText = ""; for (let i = 1; i <= pdf.numPages; i++) { const page = await pdf.getPage(i); const textContent = await page.getTextContent(); const pageText = textContent.items.map((item) => item.str).join(" "); fullText += pageText + "\n"; } response.json({ text: fullText }); } catch (error) { console.error("PDF処理エラー:", error); response.status(500).send("PDF処理に失敗しました"); } }); });

実装のポイント

1. CORSの設定

クロスオリジンリクエストを適切に処理するため、corsミドルウェアを使用しています:
const corsHandler = cors({ origin: "*", methods: ["POST", "OPTIONS"], });
 

2. エラーハンドリング

様々なエラーケースに対応するため、適切なエラーハンドリングを実装:
  • メソッドチェック
  • 必要なデータの存在確認
  • PDF処理時のエラーキャッチ

3. PDFテキスト抽出

pdf.jsライブラリを使用して、PDFからテキストを抽出。
const pdf = await pdfjsLib.getDocument(pdfBuffer).promise; let fullText = ""; for (let i = 1; i <= pdf.numPages; i++) { const page = await pdf.getPage(i); const textContent = await page.getTextContent(); const pageText = textContent.items.map((item) => item.str).join(" "); fullText += pageText + "\n"; }

実装で苦労した点

pdf.jsの設定
  • Node.js環境でのpdf.jsの設定が特殊
  • ブラウザ環境とは異なる使用方法への対応
 
CORSの適切な設定
  • 開発環境と本番環境での動作の違い
  • OPTIONSリクエストへの対応
 
エラーハンドリング
  • 様々なエラーケースへの対応
  • クライアントへの適切なエラーメッセージの返却

セキュリティ考慮事項

  • ファイルサイズ制限
  • 大きすぎるPDFファイルによるメモリ消費の防止
  • アップロード制限の設定
  • CORS設定
  • 本番環境では適切なオリジン制限が必要
  • origin: "*" は開発用
  • エラー情報の制限
  • 詳細なエラー情報は内部でログ
  • クライアントには必要最小限の情報のみ返却

デプロイと運用

  • デプロイ手順
    • cd functions
      npm install
      firebase deploy --only functions
  • 環境変数の管理
  • Firebase Console での環境変数設定
  • 開発環境と本番環境の分離

今後の改善点

  1. パフォーマンス最適化
  • PDFテキスト抽出処理の効率化
  • メモリ使用量の最適化
2.機能拡張
  • OCR機能の追加
  • 画像付きPDFへの対応
  • テキストフォーマットの改善
  • エラーハンドリングの強化
  • より詳細なエラーメッセージ
  • リトライメカニズムの実装

まとめ

Firebase Functionsを使用したPDF解析機能の実装は、いくつかの技術的課題がありましたが、最終的に安定した機能を提供することができました。特にCORSの設定やPDFファイルの処理については、サーバーレス環境での実装における重要な学びとなりました。この実装を通じて、Firebase Functionsでのファイル処理パターンやエラーハンドリングの基本的な方法を理解することができ、今後の同様の実装に活かせる貴重な経験となりました。