取り組みの背景 — Gemini APIで文書要約を自動化する意義
日々増え続ける情報の中から、必要なエッセンスを素早く抽出することは、多くのビジネスパーソンやエンジニアにとって切実な課題です。Gemini APIの優れた自然言語理解能力を活用すれば、長い文書やPDFレポートを数秒で的確に要約するWebアプリケーションを構築できます。
ここではPython FlaskフレームワークとGemini APIを組み合わせて、実際に動作するAI文書要約Webアプリをゼロから構築します。テキスト入力だけでなく、PDFファイルのアップロードにも対応した実用的なアプリケーションです。
この記事で学べること:
- Gemini API(Google AI Python SDK)の基本的なセットアップと呼び出し方法
- Python Flaskを使ったWebアプリケーションの構築手順
- 要約品質を高めるプロンプトエンジニアリングのコツ
- PDFファイルからのテキスト抽出と要約の統合パイプライン
Gemini APIの基本操作がはじめての方は、まずGemini API クイックスタートガイドを確認しておくとスムーズです。
前提知識と環境準備
必要な環境
- Python 3.10以上
- Google AI Studio で取得した Gemini API キー(Google AI Studio から無料で発行可能)
- pip(Pythonパッケージマネージャー)
プロジェクトの初期セットアップ
まず、プロジェクトディレクトリを作成し、必要なパッケージをインストールします。
# ターミナルで実行
# プロジェクトディレクトリの作成
mkdir gemini-summarizer && cd gemini-summarizer
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
# 必要パッケージのインストール
pip install flask google-genai pypdf2google-genai は Google の公式 Python SDK で、Gemini API へのアクセスを提供します。pypdf2 は PDF ファイルからテキストを抽出するために使用します。
APIキーの設定
セキュリティのため、APIキーは環境変数として管理します。
# .env ファイルを作成(.gitignore に追加すること)
GEMINI_API_KEY=YOUR_API_KEYアプリケーションの全体設計
要約アプリケーションは、以下の3つのコンポーネントで構成されます。
1. フロントエンド(HTMLテンプレート): テキスト入力フォームとPDFアップロード機能を提供し、要約結果を表示します。
2. Flaskバックエンド: リクエストの受付、ファイル処理、Gemini APIの呼び出しを担当します。
3. Gemini API連携モジュール: プロンプトの構築と要約生成を行う中核部分です。
このシンプルな構成により、コードの保守性を確保しつつ、拡張も容易になります。
Gemini API連携モジュールの実装
まず、Gemini APIを呼び出す中核モジュールを作成します。
# summarizer.py — Gemini API 要約モジュール
import os
from google import genai
# クライアントの初期化
client = genai.Client(api_key=os.environ.get("GEMINI_API_KEY"))
def summarize_text(text: str, style: str = "standard") -> dict:
"""
テキストを Gemini API で要約する
Args:
text: 要約対象のテキスト
style: 要約スタイル("standard", "bullet", "executive")
Returns:
dict: {"summary": str, "word_count": int, "key_points": list}
"""
# スタイル別のプロンプト指示
style_instructions = {
"standard": "簡潔で読みやすい段落形式で要約してください。",
"bullet": "重要なポイントを箇条書きで整理してください。",
"executive": "経営層向けに、結論と推奨アクションを明確にした要約を作成してください。"
}
instruction = style_instructions.get(style, style_instructions["standard"])
prompt = f"""以下のテキストを日本語で要約してください。
【要約のルール】
1. 元のテキストの主要な論点を漏れなく含めること
2. {instruction}
3. 専門用語はそのまま保持し、必要に応じて簡潔な説明を添えること
4. 要約の長さは元のテキストの約20〜30%を目安にすること
5. 最後に「キーポイント」として3〜5個の重要項目をリストアップすること
【対象テキスト】
{text}
【出力形式】
## 要約
(ここに要約文)
## キーポイント
- ポイント1
- ポイント2
- ポイント3
"""
response = client.models.generate_content(
model="gemini-2.5-flash",
contents=prompt
)
# レスポンスの解析
result_text = response.text
# キーポイントの抽出
key_points = []
if "## キーポイント" in result_text:
kp_section = result_text.split("## キーポイント")[1]
key_points = [
line.strip().lstrip("- ").lstrip("・")
for line in kp_section.strip().split("\n")
if line.strip() and line.strip().startswith(("-", "・"))
]
return {
"summary": result_text,
"original_length": len(text),
"key_points": key_points
}
# 期待する出力例:
# {
# "summary": "## 要約\nGemini APIは...\n\n## キーポイント\n- ポイント1\n- ポイント2",
# "original_length": 5000,
# "key_points": ["ポイント1", "ポイント2", "ポイント3"]
# }gemini-2.5-flash モデルを使用している点がポイントです。要約タスクでは応答速度が重要になるため、高速なFlashモデルが適しています。より高精度な要約が必要な場合は gemini-2.5-pro に切り替えることも可能です。
PDF テキスト抽出の実装
PDFファイルからテキストを抽出するヘルパー関数を追加します。
# pdf_extractor.py — PDF テキスト抽出モジュール
from PyPDF2 import PdfReader
import io
def extract_text_from_pdf(file_stream) -> str:
"""
PDFファイルからテキストを抽出する
Args:
file_stream: PDFファイルのバイナリストリーム
Returns:
str: 抽出されたテキスト
"""
reader = PdfReader(io.BytesIO(file_stream))
text_parts = []
for page_num, page in enumerate(reader.pages, 1):
page_text = page.extract_text()
if page_text:
text_parts.append(f"--- ページ {page_num} ---\n{page_text}")
full_text = "\n\n".join(text_parts)
if not full_text.strip():
raise ValueError("PDFからテキストを抽出できませんでした。スキャン画像のPDFの場合はOCR処理が必要です。")
return full_text
# 使用例:
# with open("report.pdf", "rb") as f:
# text = extract_text_from_pdf(f.read())
# print(text[:500]) # 最初の500文字を表示Gemini APIは2026年3月のアップデートでファイルサイズ上限が100MBに拡大されましました。大容量のPDFを直接Gemini APIに送信することも可能ですが、テキスト抽出を事前に行うことでトークン消費を最適化できます。
Flask Webアプリケーションの構築
フロントエンドとバックエンドを統合するFlaskアプリケーションを実装します。
# app.py — Flask メインアプリケーション
import os
from flask import Flask, render_template, request, jsonify
from summarizer import summarize_text
from pdf_extractor import extract_text_from_pdf
app = Flask(__name__)
app.config["MAX_CONTENT_LENGTH"] = 16 * 1024 * 1024 # 16MB上限
@app.route("/")
def index():
"""トップページ表示"""
return render_template("index.html")
@app.route("/summarize", methods=["POST"])
def summarize():
"""要約APIエンドポイント"""
try:
style = request.form.get("style", "standard")
# PDFファイルが送信された場合
if "pdf_file" in request.files:
pdf_file = request.files["pdf_file"]
if pdf_file.filename and pdf_file.filename.endswith(".pdf"):
file_data = pdf_file.read()
text = extract_text_from_pdf(file_data)
else:
return jsonify({"error": "PDFファイルを選択してください"}), 400
else:
# テキスト入力の場合
text = request.form.get("text", "").strip()
if not text:
return jsonify({"error": "要約するテキストを入力してください"}), 400
if len(text) < 100:
return jsonify({"error": "テキストが短すぎます(100文字以上必要)"}), 400
# Gemini API で要約実行
result = summarize_text(text, style=style)
return jsonify({
"success": True,
"summary": result["summary"],
"original_length": result["original_length"],
"key_points": result["key_points"]
})
except ValueError as e:
return jsonify({"error": str(e)}), 400
except Exception as e:
return jsonify({"error": f"要約処理中にエラーが発生しました: {str(e)}"}), 500
if __name__ == "__main__":
app.run(debug=True, port=5000)MAX_CONTENT_LENGTH を 16MB に設定することで、大きなPDFファイルのアップロードにも対応しています。本番環境では、この値やレート制限を適切に調整してください。
要約品質を高めるプロンプトエンジニアリング
Gemini APIで高品質な要約を得るためには、プロンプトの設計が重要です。以下のテクニックを活用すると、要約の精度が大きく向上します。
コンテキストウィンドウの活用
Gemini 2.5 Flashは100万トークンのコンテキストウィンドウを持つため、非常に長い文書でも一度に処理できます。ただし、トークン数が増えるとAPI料金も増加するため、不要な部分(ヘッダー、フッター、目次など)を事前にトリミングすることをおすすめします。
スタイル指定による出力制御
先ほどのコードでは3つの要約スタイルを定義しましたが、用途に応じてさらにカスタマイズできます。
# 要約スタイルの拡張例
CUSTOM_STYLES = {
"technical": (
"技術者向けに、実装の詳細やアーキテクチャの要点を中心に要約してください。"
"コード例やAPI仕様がある場合は特に重点的に扱ってください。"
),
"marketing": (
"マーケティング担当者向けに、市場への影響や競合との比較を中心に要約してください。"
"数値データがある場合は必ず含めてください。"
),
"one_line": (
"1文で最も重要なポイントだけを伝えてください。"
)
}このように要約スタイルをパラメータ化しておくと、同じ文書でも読み手に合わせた最適な要約を生成できます。より高度な出力制御に興味がある方は、Gemini 構造化出力の実践ガイドで詳しく解説しています。
エラーハンドリングとリトライ戦略
本番環境では、APIの一時的な障害やレート制限に対応するリトライ処理が不可欠です。
# retry_handler.py — リトライ付きAPI呼び出し
import time
import logging
logger = logging.getLogger(__name__)
def call_with_retry(func, max_retries=3, base_delay=1.0):
"""
指数バックオフ付きリトライでAPI呼び出しを実行する
Args:
func: 実行する関数
max_retries: 最大リトライ回数
base_delay: 初回リトライの待機秒数
Returns:
関数の戻り値
"""
for attempt in range(max_retries + 1):
try:
return func()
except Exception as e:
error_msg = str(e)
# レート制限(429)の場合は長めに待機
if "429" in error_msg or "RESOURCE_EXHAUSTED" in error_msg:
delay = base_delay * (2 ** attempt) * 2
logger.warning(f"レート制限検出。{delay}秒後にリトライ ({attempt + 1}/{max_retries})")
elif attempt < max_retries:
delay = base_delay * (2 ** attempt)
logger.warning(f"API呼び出し失敗。{delay}秒後にリトライ ({attempt + 1}/{max_retries}): {error_msg}")
else:
logger.error(f"最大リトライ回数に到達: {error_msg}")
raise
time.sleep(delay)
# 使用例:
# result = call_with_retry(lambda: summarize_text(text, style="standard"))エラーハンドリングのベストプラクティスについては、Gemini API エラーハンドリング&リトライパターン実践ガイドも参考になります。
デプロイと運用のヒント
ローカルでの動作確認
# 環境変数を設定して起動
export GEMINI_API_KEY=YOUR_API_KEY
python app.py
# ブラウザで http://localhost:5000 にアクセス
# または curl でテスト:
# curl -X POST http://localhost:5000/summarize \
# -F "text=ここに要約したいテキストを入力..." \
# -F "style=bullet"本番環境への展開
Flaskアプリケーションを本番環境にデプロイする際は、Gunicornなどの WSGIサーバーと組み合わせることを推奨します。
# Gunicorn での起動例
pip install gunicorn
gunicorn app:app --workers 4 --bind 0.0.0.0:8000Google Cloud Runへのデプロイも相性が良く、Gemini APIとの通信レイテンシを最小限に抑えられます。Dockerfileを用意すれば、gcloud run deploy コマンド一つでデプロイが完了します。
まとめ
Gemini APIとPython Flaskを組み合わせることで、テキストやPDFを自動的に要約するWebアプリケーションを効率的に構築できます。今回実装した要約モジュールは、スタイル指定やリトライ処理を含む実践的な設計になっており、そのまま本番プロジェクトに応用可能です。
Gemini APIの100万トークンコンテキストウィンドウは、長大な文書の一括処理を可能にする大きな強みです。まずは今回のコードを動かしてみて、自分のユースケースに合ったプロンプトを試行錯誤してみてください。さらにAPIを活用した自動化パイプラインに興味がある方は、Gemini API × Python 自動化レシピ集もぜひ参考にしてみてください。