メインコンテンツへスキップ
開発者ガイド

TesseractをAPIとして実行
またはセルフホストサービスとして。

TesseractをHTTPサービスに確実に包みます:本番向けFastAPIエンドポイント、プロセスプールによる並行処理、言語パックとヘルスチェックを備えたDockerイメージ、スケーリングとバックプレッシャー、サーバーレス展開 — マネージドOCR APIとのプライバシーとコストのトレードオフも解説。

TL;DR — 最小構成のサービス

CLIまたはpytesseractバインディングをHTTPの背後に包みます。画像がインフラの外に出ることはありません。

bash
pip install fastapi uvicorn python-multipart pytesseract pillow
# 先にエンジン + 言語パックをインストール(インストールガイド参照)
uvicorn app:app --host 0.0.0.0 --port 8000

呼び出し: curl -F "file=@invoice.png" "http://localhost:8000/ocr?lang=jpn"。Tesseract本体はインストールガイドに従って導入します。

まず設計上の判断

3つの選択がサービス全体を決めます。

判断選択肢指針
同期 vs 非同期ブロッキングリクエスト vs ジョブキュー数秒以内の単一画像は同期。大きな文書やバッチは非同期ジョブID。
入力multipartアップロード vs base64 JSONバイナリ画像はmultipartを推奨。クライアントがファイルを送れない場合のみbase64(サイズが約33%増)。
出力プレーンテキスト、JSON、hOCR/ALTO、検索可能PDF既定はJSON。レイアウト用にhOCR、アーカイブ用にPDFダウンロードURLを提供。

1エンドポイントにつき主要な意図は1つ。/ocr はテキストを返すままにし、PDFとレイアウトデータは別エンドポイントに分けます。

本番向けPythonサービス(FastAPI)

検証、サイズ制限、タイムアウト、イベントループ外でのOCR。

app.py
import asyncio, io
from concurrent.futures import ProcessPoolExecutor
from fastapi import FastAPI, File, UploadFile, HTTPException, Query
from PIL import Image
import pytesseract

app = FastAPI(title="Tesseract OCR API")
pool = ProcessPoolExecutor(max_workers=4)
MAX_BYTES = 10 * 1024 * 1024  # 10 MB
LANGS = {"eng", "jpn"}

def _ocr(data: bytes, lang: str) -> str:
    image = Image.open(io.BytesIO(data))
    return pytesseract.image_to_string(image, lang=lang)

@app.get("/health")
def health():
    return {"status": "ok"}

@app.post("/ocr")
async def ocr(file: UploadFile = File(...), lang: str = Query("jpn")):
    if lang not in LANGS:
        raise HTTPException(400, "未対応の言語")
    data = await file.read()
    if len(data) > MAX_BYTES:
        raise HTTPException(413, "ファイルが大きすぎます")
    loop = asyncio.get_running_loop()
    try:
        text = await asyncio.wait_for(loop.run_in_executor(pool, _ocr, data, lang), timeout=30)
    except asyncio.TimeoutError:
        raise HTTPException(504, "OCRタイムアウト")
    return {"text": text, "lang": lang}

要点:言語を許可リスト化、デコード前にバイト上限を適用、OCRはプロセスプールで実行、実時間を制限。Pythonガイドでpytesseractの全APIを参照してください。

コンテナ化する

Tesseractと言語パックをイメージに焼き込み、レプリカを同一にします。

Dockerfile
FROM python:3.12-slim
RUN apt-get update && apt-get install -y --no-install-recommends \
      tesseract-ocr tesseract-ocr-eng tesseract-ocr-jpn \
      libgl1 libglib2.0-0 && rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app.py .
EXPOSE 8000
HEALTHCHECK CMD python -c "import urllib.request;urllib.request.urlopen('http://localhost:8000/health')"
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "2"]

必要な言語パックだけを追加してイメージを小さく保ちます。インストールガイドでDockerとtessdataの配置を詳しく扱っています。

並行処理とスケーリング

OCRはCPUバウンド — スレッドではなくプロセスで並列化します。

セキュリティとプライバシー

セルフホストはチームがTesseractを選ぶ主な理由です。

サーバーレスとコンテナプラットフォーム

セルフホストTesseract vs マネージドOCR API

観点セルフホストTesseractマネージドOCR API
コスト固定インフラ。ページ課金なしリクエスト/ページ課金。量に比例
プライバシー文書がネットワーク外に出ない文書が第三者に送信される
精度きれいな印刷に強い。ドメインごとに調整可能難しいスキャンや手書きにしばしば強い
制御完全:バージョン、言語、カスタムモデルベンダーのロードマップとクォータ
運用自社で運用:スケーリング、更新、監視完全マネージド

多くのチームは大量・プライバシー重視の処理にTesseractをセルフホストし、難しい少数の文書のみマネージドAPIに頼ります。

API FAQ

Tesseract OCRをAPIとして実行するには?

CLIまたはpytesseractをFastAPI/Flaskで包み、POST /ocrを公開してコンテナ化します。画像はインフラ内に留まります。

スレッドかプロセスか?

プロセスです。OCRはCPUバウンドでGILがスレッド並列を妨げるため、ProcessPoolExecutorかCLIサブプロセスを使います。

セルフホストAPIはプライベートですか?

はい。アップロード画像はローカルで処理され、第三者に送信されません。マネージドOCR APIとは異なります。

サーバーレスで実行できますか?

はい。Cloud Run、Lambdaコンテナイメージ、Fly.ioなどで可能です。コールドスタートと言語パックによるイメージサイズに注意してください。

どの出力形式を返せますか?

プレーンテキスト、信頼度付きJSON、hOCR/ALTO、ダウンロードURL経由の検索可能PDF。