GEMINI LABJP
NANOLITE — Nano Banana 2 Lite is here: Google's fastest and most cost-efficient Gemini Image model, made for running lightweight image generation cheaplyOMNIFLASH — Gemini Omni Flash is in public preview, a natively multimodal model that lets enterprises and developers build custom, dynamic video workflowsAGENTS — Managed Agents expand with background: true for async server-side runs and polling, remote MCP server integration, and refreshing credentials across interactionsMEMORY — The Memory Bank IngestEvents API is generally available, decoupling event ingestion from memory generation so you can stream content continuouslyTHROUGHPUT — Provisioned Throughput now lets you submit up to seven pending orders for the same model and regionDEPRECATE — Image generation models shut down on August 17, and the Grok 4.1 family on the Gemini Enterprise Agent Platform on August 20NANOLITE — Nano Banana 2 Lite is here: Google's fastest and most cost-efficient Gemini Image model, made for running lightweight image generation cheaplyOMNIFLASH — Gemini Omni Flash is in public preview, a natively multimodal model that lets enterprises and developers build custom, dynamic video workflowsAGENTS — Managed Agents expand with background: true for async server-side runs and polling, remote MCP server integration, and refreshing credentials across interactionsMEMORY — The Memory Bank IngestEvents API is generally available, decoupling event ingestion from memory generation so you can stream content continuouslyTHROUGHPUT — Provisioned Throughput now lets you submit up to seven pending orders for the same model and regionDEPRECATE — Image generation models shut down on August 17, and the Grok 4.1 family on the Gemini Enterprise Agent Platform on August 20
Articles/API / SDK
API / SDK/2026-03-28Intermediate

Build an AI Document Summarizer with Gemini API and Python Flask — Hands-On Tutorial

Learn how to build a web app that automatically summarizes text and PDF documents using the Gemini API and Python Flask. From prompt design to deployment.

gemini-api277python104flasksummarization4web-app2tutorial9

Setup and context — Why Build a Summarizer with Gemini API

In an age of information overload, extracting key insights from lengthy documents is a constant challenge for professionals and developers alike. With Gemini API's powerful natural language understanding, you can build a web application that accurately summarizes long documents and PDF reports in seconds.

In this tutorial, we'll build a fully functional AI document summarizer from scratch using Python Flask and the Gemini API. The app handles both plain text input and PDF file uploads, making it practical for real-world use.

What you'll learn:

  • Setting up and calling the Gemini API with the Google AI Python SDK
  • Building a web application with Python Flask
  • Prompt engineering techniques for high-quality summaries
  • Integrating PDF text extraction into a summarization pipeline

If you're new to the Gemini API, the [Gemini API Quickstart Guide]((/articles/gemini-api/gemini-api-quickstart) is a great place to start before diving in.

Prerequisites and Setup

Requirements

  • Python 3.10 or later
  • A Gemini API key from Google AI Studio (free tier available)
  • pip (Python package manager)

Project Initialization

Create a project directory and install the required packages:

# Run in your terminal
# Create project directory
mkdir gemini-summarizer && cd gemini-summarizer
python -m venv venv
source venv/bin/activate  # Windows: venv\Scripts\activate
 
# Install required packages
pip install flask google-genai pypdf2

The google-genai package is Google's official Python SDK for accessing the Gemini API. pypdf2 handles PDF text extraction.

API Key Configuration

For security, manage your API key as an environment variable:

# Create a .env file (add to .gitignore)
GEMINI_API_KEY=YOUR_API_KEY

Application Architecture

The summarizer application consists of three components:

1. Frontend (HTML templates): Provides a text input form, PDF upload functionality, and displays the summary results.

2. Flask backend: Handles request routing, file processing, and Gemini API orchestration.

3. Gemini API module: The core component responsible for prompt construction and summary generation.

This clean separation keeps the code maintainable and easy to extend.

Building the Gemini API Module

Let's start with the core module that communicates with the Gemini API:

# summarizer.py — Gemini API summarization module
import os
from google import genai
 
# Initialize the client
client = genai.Client(api_key=os.environ.get("GEMINI_API_KEY"))
 
def summarize_text(text: str, style: str = "standard") -> dict:
    """
    Summarize text using the Gemini API
 
    Args:
        text: The text to summarize
        style: Summary style ("standard", "bullet", "executive")
 
    Returns:
        dict: {"summary": str, "original_length": int, "key_points": list}
    """
    # Style-specific prompt instructions
    style_instructions = {
        "standard": "Write a concise, readable summary in paragraph form.",
        "bullet": "Organize the key points as a bulleted list.",
        "executive": "Create an executive summary with clear conclusions and recommended actions."
    }
 
    instruction = style_instructions.get(style, style_instructions["standard"])
 
    prompt = f"""Summarize the following text.
 
【Summarization Rules】
1. Include all major arguments from the original text
2. {instruction}
3. Preserve technical terms and add brief explanations where needed
4. Target approximately 20-30% of the original text length
5. End with 3-5 "Key Takeaways" as a bulleted list
 
【Source Text】
{text}
 
【Output Format】
## Summary
(Summary text here)
 
## Key Takeaways
- Takeaway 1
- Takeaway 2
- Takeaway 3
"""
 
    response = client.models.generate_content(
        model="gemini-2.5-flash",
        contents=prompt
    )
 
    # Parse the response
    result_text = response.text
 
    # Extract key takeaways
    key_points = []
    if "## Key Takeaways" in result_text:
        kp_section = result_text.split("## Key Takeaways")[1]
        key_points = [
            line.strip().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
    }
 
# Expected output example:
# {
#     "summary": "## Summary\nThe Gemini API...\n\n## Key Takeaways\n- Point 1\n- Point 2",
#     "original_length": 5000,
#     "key_points": ["Point 1", "Point 2", "Point 3"]
# }

Notice that we're using the gemini-2.5-flash model. For summarization tasks where response speed matters, the Flash model is the ideal choice. If you need higher accuracy for complex documents, you can switch to gemini-2.5-pro.

Implementing PDF Text Extraction

Add a helper function to extract text from uploaded PDF files:

# pdf_extractor.py — PDF text extraction module
from PyPDF2 import PdfReader
import io
 
def extract_text_from_pdf(file_stream) -> str:
    """
    Extract text content from a PDF file
 
    Args:
        file_stream: Binary stream of the PDF file
 
    Returns:
        str: Extracted text content
    """
    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 {page_num} ---\n{page_text}")
 
    full_text = "\n\n".join(text_parts)
 
    if not full_text.strip():
        raise ValueError("Could not extract text from the PDF. Scanned image PDFs require OCR processing.")
 
    return full_text
 
# Usage example:
# with open("report.pdf", "rb") as f:
#     text = extract_text_from_pdf(f.read())
#     print(text[:500])  # Display first 500 characters

As of March 2026, the Gemini API increased its file size limit from 20MB to 100MB. While you can send large PDFs directly to the API, pre-extracting text helps optimize token consumption and reduce costs.

Building the Flask Web Application

Now let's bring everything together in the Flask application:

# app.py — Flask main application
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 limit
 
@app.route("/")
def index():
    """Render the home page"""
    return render_template("index.html")
 
@app.route("/summarize", methods=["POST"])
def summarize():
    """Summarization API endpoint"""
    try:
        style = request.form.get("style", "standard")
 
        # Handle PDF file upload
        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": "Please select a valid PDF file"}), 400
        else:
            # Handle text input
            text = request.form.get("text", "").strip()
 
        if not text:
            return jsonify({"error": "Please enter text to summarize"}), 400
 
        if len(text) < 100:
            return jsonify({"error": "Text is too short (minimum 100 characters)"}), 400
 
        # Run summarization via 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"Summarization failed: {str(e)}"}), 500
 
if __name__ == "__main__":
    app.run(debug=True, port=5000)

The MAX_CONTENT_LENGTH is set to 16MB to accommodate large PDF uploads. In production, adjust this value along with rate limiting based on your requirements.

Prompt Engineering for Better Summaries

The quality of your summaries depends heavily on prompt design. Here are techniques that significantly improve output quality with the Gemini API.

Leveraging the Context Window

Gemini 2.5 Flash supports a 1-million-token context window, allowing you to process extremely long documents in a single request. However, since token usage affects billing, it's worth trimming unnecessary content like headers, footers, and tables of contents before sending them to the API.

Controlling Output with Style Parameters

We defined three summary styles earlier, but you can customize further based on your use case:

# Extended summary style examples
CUSTOM_STYLES = {
    "technical": (
        "Focus on implementation details, architecture decisions, and technical specifics. "
        "Pay special attention to code examples and API specifications."
    ),
    "marketing": (
        "Focus on market impact, competitive analysis, and business implications. "
        "Always include numerical data when available."
    ),
    "one_line": (
        "Convey only the single most important point in one sentence."
    )
}

By parameterizing summary styles, you can generate optimized summaries for different audiences from the same source document. For more advanced output control techniques, check out the [Gemini Structured Output Production Guide]((/articles/gemini-advanced/gemini-structured-output-production-guide).

Error Handling and Retry Strategy

In production environments, implementing retry logic for transient API failures and rate limiting is essential:

# retry_handler.py — API call with retry logic
import time
import logging
 
logger = logging.getLogger(__name__)
 
def call_with_retry(func, max_retries=3, base_delay=1.0):
    """
    Execute an API call with exponential backoff retry
 
    Args:
        func: The function to execute
        max_retries: Maximum number of retry attempts
        base_delay: Initial delay in seconds before first retry
 
    Returns:
        The function's return value
    """
    for attempt in range(max_retries + 1):
        try:
            return func()
        except Exception as e:
            error_msg = str(e)
 
            # Rate limit (429) — wait longer
            if "429" in error_msg or "RESOURCE_EXHAUSTED" in error_msg:
                delay = base_delay * (2 ** attempt) * 2
                logger.warning(f"Rate limit hit. Retrying in {delay}s ({attempt + 1}/{max_retries})")
            elif attempt < max_retries:
                delay = base_delay * (2 ** attempt)
                logger.warning(f"API call failed. Retrying in {delay}s ({attempt + 1}/{max_retries}): {error_msg}")
            else:
                logger.error(f"Max retries reached: {error_msg}")
                raise
 
            time.sleep(delay)
 
# Usage:
# result = call_with_retry(lambda: summarize_text(text, style="standard"))

For a deeper dive into error handling best practices, see the [Gemini API Error Handling and Retry Patterns Guide]((/articles/gemini-api/gemini-api-error-handling-retry-patterns).

Deployment Tips

Local Testing

# Set environment variable and launch
export GEMINI_API_KEY=YOUR_API_KEY
python app.py
 
# Open http://localhost:5000 in your browser
# Or test with curl:
# curl -X POST http://localhost:5000/summarize \
#   -F "text=Enter your text to summarize here..." \
#   -F "style=bullet"

Production Deployment

For production, pair Flask with a WSGI server like Gunicorn:

# Launch with Gunicorn
pip install gunicorn
gunicorn app:app --workers 4 --bind 0.0.0.0:8000

Google Cloud Run is an excellent hosting choice for this type of application, as it minimizes latency when communicating with the Gemini API. With a Dockerfile in place, deployment is a single gcloud run deploy command away.

Summary

By combining the Gemini API with Python Flask, you can efficiently build a web application that automatically summarizes text and PDF documents. The summarization module we built includes style parameterization and retry handling, making it production-ready out of the box.

Gemini API's 1-million-token context window is a major advantage for processing lengthy documents in a single pass. Start by running the code from this tutorial, then experiment with prompts tailored to your specific use case. If you're interested in building more advanced automation pipelines, the [Gemini API Python Automation Recipes]((/articles/gemini-api/gemini-api-python-automation-recipes) guide is an excellent next step.

Share

Thank You for Reading

Gemini Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

API / SDK2026-07-12
When a Whole Chapter Vanished From My Long-PDF Summary — Field Notes on Auditing Coverage
Chapter-wise summarize-then-merge works well on long PDFs, but a lost extraction or a merge step can drop an entire chapter while the pipeline finishes without a single error. This walks through catching those silent drops with one number—coverage—and re-running only the chapters that fell out.
API / SDK2026-05-01
Speaker Diarization with Gemini API: Meetings and Podcasts
Use the Gemini API's multimodal audio understanding to label who said what in meeting recordings and podcasts — with a working Python example and prompt design tips.
API / SDK2026-03-30
How to Build an Audio Transcription and Summarization App with Gemini API and Python
Learn how to build an audio transcription and auto-summarization app using Gemini API's multimodal capabilities and Python, with step-by-step code examples.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →