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-30Beginner

Text Classification and Sentiment Analysis with Gemini API and Python — A

Learn how to build text classification and sentiment analysis pipelines using the Gemini API and Python. Leverage Structured Output for reliable labeling of customer reviews, support tickets, and social media posts.

gemini-api277python104text-classificationsentiment-analysis2structured-output22nlp

When You Need Text Classification and Sentiment Analysis

E-commerce reviews, brand mentions on social media, incoming support emails — the need to automatically categorize text and gauge sentiment keeps growing. Traditionally, you'd need to train a dedicated NLP model with hundreds of labeled examples. With the Gemini API's Structured Output, you can build a high-accuracy text classification and sentiment analysis pipeline in Python without any training data.

Setting Up Your Environment

Getting Your API Key

  1. Visit Google AI Studio
  2. Click "Get API key" in the left menu
  3. Create a new project or select an existing one to generate your key

Installing the SDK

pip install google-genai

Testing the Connection

from google import genai
 
client = genai.Client(api_key="YOUR_GEMINI_API_KEY")
 
response = client.models.generate_content(
    model="gemini-2.5-flash",
    contents="Hello, Gemini! Please send a test response."
)
print(response.text)
# Expected output: Hello! Here's your test response. How can I help you today?

If your API key is configured correctly, you'll see a response from Gemini.

Building a Text Classifier with Structured Output

Gemini API's Structured Output lets you receive classification labels in a strict JSON format. Instead of parsing free text, you get structured data that flows directly into your downstream processing.

Defining the Classification Schema

from google import genai
from pydantic import BaseModel, Field
from enum import Enum
from typing import Optional
 
class Category(str, Enum):
    PRODUCT_QUALITY = "product_quality"
    SHIPPING = "shipping"
    CUSTOMER_SERVICE = "customer_service"
    PRICING = "pricing"
    OTHER = "other"
 
class Sentiment(str, Enum):
    POSITIVE = "positive"
    NEUTRAL = "neutral"
    NEGATIVE = "negative"
 
class TextClassification(BaseModel):
    category: Category = Field(description="The primary category of the text")
    sentiment: Sentiment = Field(description="The sentiment polarity of the text")
    confidence: float = Field(description="Classification confidence score (0.0–1.0)", ge=0.0, le=1.0)
    keywords: list[str] = Field(description="Key terms extracted from the text (up to 5)")
    summary: str = Field(description="One-line summary of the text")

By defining Category and Sentiment as Enums, you ensure that the returned labels never contain unexpected values. Pydantic handles validation automatically.

Classifying a Single Text

client = genai.Client(api_key="YOUR_GEMINI_API_KEY")
 
review = "Arrived in just two days. The packaging was excellent and the product quality met my expectations. The only downside is the manual was only available in Japanese."
 
response = client.models.generate_content(
    model="gemini-2.5-flash",
    contents=f"""Analyze the following customer review.
 
Review: {review}
 
Return the category, sentiment, confidence, keywords, and summary.""",
    config={
        "response_mime_type": "application/json",
        "response_schema": TextClassification,
    }
)
 
result = TextClassification.model_validate_json(response.text)
print(f"Category: {result.category.value}")
print(f"Sentiment: {result.sentiment.value}")
print(f"Confidence: {result.confidence}")
print(f"Keywords: {result.keywords}")
print(f"Summary: {result.summary}")
 
# Expected output:
# Category: product_quality
# Sentiment: positive
# Confidence: 0.82
# Keywords: ['packaging', 'quality', 'delivery', 'manual', 'Japanese']
# Summary: Good product quality and fast delivery, but manual lacks English translation

Just pass the Pydantic model to response_schema, and Gemini returns a response matching your exact JSON structure. No parsing headaches.

Batch Processing for Large Datasets

In production, you'll often need to process hundreds or thousands of reviews at once. Here's a batch implementation with retry logic.

import time
from google import genai
from google.genai.errors import ClientError
 
client = genai.Client(api_key="YOUR_GEMINI_API_KEY")
 
reviews = [
    "The product itself is great, but shipping took over a week.",
    "Customer support was incredibly helpful and responsive.",
    "At this price point, the quality is genuinely surprising. Best value I've found.",
    "The item looks nothing like the photos. The return process is frustrating too.",
    "It works fine. Nothing special to report.",
]
 
def classify_review(review_text: str, max_retries: int = 3) -> Optional[TextClassification]:
    """Classify a review with retry logic."""
    for attempt in range(max_retries):
        try:
            response = client.models.generate_content(
                model="gemini-2.5-flash",
                contents=f"Analyze the following customer review.\n\nReview: {review_text}",
                config={
                    "response_mime_type": "application/json",
                    "response_schema": TextClassification,
                }
            )
            return TextClassification.model_validate_json(response.text)
        except ClientError as e:
            if "429" in str(e):
                wait = 2 ** attempt
                print(f"Rate limited. Retrying in {wait} seconds...")
                time.sleep(wait)
            else:
                print(f"Error: {e}")
                return None
    return None
 
# Run batch classification
results = []
for i, review in enumerate(reviews):
    print(f"Processing: {i + 1}/{len(reviews)}")
    result = classify_review(review)
    if result:
        results.append({"review": review, "classification": result})
    time.sleep(0.5)  # Respect rate limits
 
# Aggregate results
from collections import Counter
 
sentiment_counts = Counter(r["classification"].sentiment.value for r in results)
category_counts = Counter(r["classification"].category.value for r in results)
 
print(f"\n--- Sentiment Distribution ---")
for sentiment, count in sentiment_counts.most_common():
    print(f"  {sentiment}: {count}")
 
print(f"\n--- Category Distribution ---")
for category, count in category_counts.most_common():
    print(f"  {category}: {count}")
 
# Expected output:
# --- Sentiment Distribution ---
#   positive: 2
#   negative: 2
#   neutral: 1
# --- Category Distribution ---
#   shipping: 1
#   customer_service: 1
#   pricing: 1
#   product_quality: 2

The key points are adding time.sleep(0.5) between requests and using exponential backoff for 429 errors. For large-scale processing, consider using the Batch API approach covered in Gemini API Production Pipeline Architecture.

Multilingual Sentiment Analysis

Gemini handles multiple languages natively, so you can process Japanese, English, Chinese, and other texts through the same pipeline.

class MultilingualAnalysis(BaseModel):
    detected_language: str = Field(description="Detected language code (ja, en, zh, etc.)")
    sentiment: Sentiment
    confidence: float = Field(ge=0.0, le=1.0)
    translated_summary: str = Field(description="One-line summary in English")
 
multilingual_texts = [
    "This product exceeded my expectations! Highly recommended.",
    "配送が遅すぎます。二度と利用しません。",
    "产品质量一般,但价格很合理。",
]
 
for text in multilingual_texts:
    response = client.models.generate_content(
        model="gemini-2.5-flash",
        contents=f"Analyze the following text. Detect the language and determine the sentiment.\n\nText: {text}",
        config={
            "response_mime_type": "application/json",
            "response_schema": MultilingualAnalysis,
        }
    )
    result = MultilingualAnalysis.model_validate_json(response.text)
    print(f"Language: {result.detected_language} | Sentiment: {result.sentiment.value} | Summary: {result.translated_summary}")
 
# Expected output:
# Language: en | Sentiment: positive | Summary: Product exceeded expectations, strongly recommended
# Language: ja | Sentiment: negative | Summary: Severe dissatisfaction with slow delivery
# Language: zh | Sentiment: neutral | Summary: Average quality but reasonable pricing

No need to switch models for different languages — one prompt handles everything.

Custom Categories for Your Business

You can customize the classification categories to match your specific business needs. Here's an example for automatic support ticket routing.

class TicketPriority(str, Enum):
    URGENT = "urgent"
    HIGH = "high"
    MEDIUM = "medium"
    LOW = "low"
 
class TicketCategory(str, Enum):
    BUG_REPORT = "bug_report"
    FEATURE_REQUEST = "feature_request"
    BILLING = "billing"
    ACCOUNT = "account"
    GENERAL = "general"
 
class SupportTicket(BaseModel):
    category: TicketCategory
    priority: TicketPriority
    sentiment: Sentiment
    requires_human: bool = Field(description="Whether the ticket needs human escalation")
    suggested_response: str = Field(description="Suggested first response (under 50 words)")
 
ticket_text = "I can't log in to my account. The password reset email isn't arriving either. I need this resolved urgently."
 
response = client.models.generate_content(
    model="gemini-2.5-flash",
    contents=f"""Analyze the following support ticket and determine the category, priority, sentiment, escalation need, and suggested response.
 
Ticket: {ticket_text}""",
    config={
        "response_mime_type": "application/json",
        "response_schema": SupportTicket,
    }
)
 
ticket = SupportTicket.model_validate_json(response.text)
print(f"Category: {ticket.category.value}")
print(f"Priority: {ticket.priority.value}")
print(f"Sentiment: {ticket.sentiment.value}")
print(f"Escalation: {'Required' if ticket.requires_human else 'Not needed'}")
print(f"Suggested Response: {ticket.suggested_response}")
 
# Expected output:
# Category: account
# Priority: urgent
# Sentiment: negative
# Escalation: Required
# Suggested Response: We're looking into your login issue right away. A team member will follow up shortly.

Adding a requires_human field lets you automatically separate tickets that can be handled by bots from those that need human attention.

Prompt Design Tips for Better Accuracy

Classification accuracy depends heavily on how you write your prompts. Here are techniques that make a real difference.

Using System Instructions

response = client.models.generate_content(
    model="gemini-2.5-flash",
    contents=review_text,
    config={
        "system_instruction": """You are a text classification expert.
Follow these rules:
- When text fits multiple categories, choose the single most prominent one
- Set confidence conservatively (only use 0.9+ for clear-cut cases)
- Watch for sarcasm and irony (e.g., "Oh great, another delay" is negative)
- Consider emojis and emoticons as sentiment signals""",
        "response_mime_type": "application/json",
        "response_schema": TextClassification,
    }
)

Adding Few-Shot Examples

few_shot_prompt = """Classify the following review.
 
## Classification examples
Review: "Best product ever!" → category: product_quality, sentiment: positive, confidence: 0.95
Review: "It's okay I guess" → category: product_quality, sentiment: neutral, confidence: 0.70
Review: "I want a refund" → category: billing, sentiment: negative, confidence: 0.90
 
## Text to classify
Review: {review_text}"""

Adding just 2–3 few-shot examples significantly improves accuracy on borderline cases like mildly positive-neutral texts. For more details on configuring Structured Output, check out the Gemini API JSON Mode and Structured Output Guide.

Looking back

By combining the Gemini API's Structured Output with Pydantic models, you can build a text classification and sentiment analysis pipeline quickly — no training data required. Defining categories and sentiment labels as Enums ensures consistent, reliable results that plug directly into your data workflows.

The patterns shown here apply well beyond customer reviews: support ticket routing, social media monitoring, survey analysis, and more. Start with the Gemini API Quickstart Guide to get your API key, and try classifying a small dataset first.

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-13
When responseSchema Can't Do $ref: Handling Recursive Schemas in Production with responseJsonSchema
Gemini's responseSchema is an OpenAPI subset with no $ref or $defs, so it can't express shared definitions or recursion. Here's how I moved to responseJsonSchema to reuse localized fields and handle a recursive category tree in production.
API / SDK2026-05-16
Automating Firebase Crashlytics Analysis with Gemini API — A Real-World Implementation from an Indie App
A real-world implementation record of automating Firebase Crashlytics log analysis with Gemini API, validated during development of an indie wallpaper app (v2.1.0). Includes Before/After code for a RecyclerView crash fix and a production cost breakdown.
API / SDK2026-05-03
Automate Contact Form Handling with Gemini API — Classification, Priority Scoring & Slack Alerts
Build a Python system that automatically classifies incoming contact form submissions using Gemini API, scores their priority, and sends structured Slack notifications — ready to deploy today.
📚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 →