In the previous chapters, you learned Generative AI fundamentals, OpenAI API fundamentals, prompt engineering, structured prompting, and production-oriented project architecture. Now we put all of that together to build real text-generation applications.
The approach used throughout this series is based on the Responses API, which accepts model input and returns generated output built specifically for application development.
4.1 What Is Text Generation?
Text generation means using an AI model to create new text based on instructions and input.
Input → Instructions → AI Model → Generated Text
Examples:
"Write a product description"
"Summarize this article"
"Translate this text"
"Write a professional email"
4.2 Common Text Generation Use Cases
We’ll focus on six major application types:
1. Content Generation — Topic → AI → Article / Blog / Description
2. Summarization — Long Text → AI → Short Summary
3. Translation — English Text → AI → Hindi / Spanish / Japanese
4. Information Extraction — Unstructured Text → AI → Structured Data
5. Classification — Customer Message → AI → Category
6. Email Generation — Situation → AI → Professional Email
4.3 Industry Project for This Chapter
Rather than building five disconnected scripts, we’ll build one reusable AI Text Processing Service:
┌─────────────────────┐
│ Application Layer │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ Text Service Layer │
└──────────┬──────────┘
│
┌───────┼───────┐
▼ ▼ ▼
Summarizer Translator Generator
│ │ │
└───────┼───────┘
▼
┌─────────────────────┐
│ OpenAI Client │
└─────────────────────┘
Our application will support: summarization, content generation, translation, email generation, and information extraction.
4.4 Project Structure
ai-text-platform/
│
├── src/
│ └── ai_text_platform/
│ │
│ ├── main.py
│ │
│ ├── config/
│ │ ├── __init__.py
│ │ └── settings.py
│ │
│ ├── clients/
│ │ ├── __init__.py
│ │ └── openai_client.py
│ │
│ ├── services/
│ │ ├── __init__.py
│ │ ├── text_generation_service.py
│ │ ├── summarization_service.py
│ │ ├── translation_service.py
│ │ └── email_service.py
│ │
│ ├── prompts/
│ │ ├── __init__.py
│ │ ├── generation_prompts.py
│ │ ├── summarization_prompts.py
│ │ └── translation_prompts.py
│ │
│ ├── models/
│ │ ├── __init__.py
│ │ └── text_models.py
│ │
│ └── utils/
│ ├── __init__.py
│ └── logging_config.py
│
├── tests/
│ ├── test_prompts.py
│ └── test_validation.py
│
├── .env
├── .env.example
├── .gitignore
├── requirements.txt
└── README.md
This is a much more realistic setup than one app.py file trying to hold every feature at once.
4.5 Step 1: Create the Project
mkdir ai-text-platform
cd ai-text-platform
Create a virtual environment:
python -m venv .venv
Windows:
.venv\Scripts\activate
macOS/Linux:
source .venv/bin/activate
Install dependencies:
pip install openai python-dotenv pydantic
requirements.txt:
openai
python-dotenv
pydantic
4.6 Step 2: Configuration
.env:
OPENAI_API_KEY=your_api_key_here
.env.example:
OPENAI_API_KEY=your_api_key_here
.gitignore:
.env
.venv/
__pycache__/
.pytest_cache/
4.7 Step 3: Application Settings
Create src/ai_text_platform/config/settings.py:
import os
from dotenv import load_dotenv
load_dotenv()
class Settings:
def __init__(self) -> None:
self.openai_api_key = os.getenv("OPENAI_API_KEY", "")
self.model_name = os.getenv(
"OPENAI_MODEL",
"YOUR_MODEL_NAME",
)
if not self.openai_api_key:
raise ValueError(
"OPENAI_API_KEY is not configured."
)
settings = Settings()
Why centralize configuration? Instead of scattering model = "..." across File 1, File 2, and File 3, you have one source of truth:
Configuration → All Services
This makes changing a setting a one-line edit instead of a multi-file hunt.
4.8 Step 4: Create the OpenAI Client
Create src/ai_text_platform/clients/openai_client.py:
from openai import OpenAI
from ai_text_platform.config.settings import settings
def create_openai_client() -> OpenAI:
return OpenAI(
api_key=settings.openai_api_key
)
This module has exactly one job: create and configure the OpenAI client.
4.9 Step 5: Create Prompt Templates
Content Generation Prompt — src/ai_text_platform/prompts/generation_prompts.py:
def build_content_generation_prompt(
topic: str,
audience: str,
tone: str,
) -> str:
return f"""
You are a professional content writer.
Task:
Write content about the following topic.
Topic:
{topic}
Target audience:
{audience}
Tone:
{tone}
Requirements:
- Be clear and useful.
- Do not invent unsupported facts.
- Organize the response with headings.
- Avoid unnecessary repetition.
"""
Summarization Prompt — src/ai_text_platform/prompts/summarization_prompts.py:
def build_summary_prompt(
text: str,
max_words: int,
) -> str:
return f"""
You are a professional summarization assistant.
Summarize the text below.
Requirements:
- Preserve the main meaning.
- Remove unnecessary repetition.
- Do not add facts that are not in the source.
- Keep the summary below {max_words} words.
Text:
{text}
"""
Translation Prompt — src/ai_text_platform/prompts/translation_prompts.py:
def build_translation_prompt(
text: str,
target_language: str,
) -> str:
return f"""
Translate the following text into {target_language}.
Rules:
- Preserve the original meaning.
- Do not add explanations.
- Return only the translation.
Text:
{text}
"""
4.10 Step 6: Create a Reusable AI Service
Create src/ai_text_platform/services/text_generation_service.py:
from openai import OpenAI
from ai_text_platform.config.settings import settings
class TextGenerationService:
def __init__(self, client: OpenAI) -> None:
self.client = client
def generate(
self,
prompt: str,
) -> str:
response = self.client.responses.create(
model=settings.model_name,
input=prompt,
)
return response.output_text
This service does one thing:
Prompt → OpenAI API → Generated Text
It doesn’t know or care whether the prompt is for summarization, translation, blog generation, or email generation — and that’s exactly the point of good design: each layer only knows what it needs to.
4.11 Why Use a Service Layer?
Without a service layer:
main.py
├── Build prompt
├── Call API
├── Parse response
├── Handle errors
├── Generate email
├── Summarize
└── Translate
This quickly becomes unmaintainable as features are added.
With a service layer:
main.py → TextGenerationService → OpenAI Client
The application layer stays thin and clean, while each domain-specific service handles its own concerns.
4.12 Application 1: Content Generator
Topic → Prompt Builder → Text Generation Service → OpenAI API → Generated Content
Example input:
Topic: Introduction to Python
Audience: Complete beginners
Tone: Friendly and educational
Generated output might look like:
# Introduction to Python
Python is a popular programming language...
## Why Learn Python?
...
4.13 Application 2: Summarization
Summarization is one of the most common enterprise GenAI use cases — turning long reports, emails, or documents into something a person can actually read in a minute.
Long Text → Validation → Summary Prompt → AI Service → Summary
4.14 Summarization Service
Create src/ai_text_platform/services/summarization_service.py:
from ai_text_platform.prompts.summarization_prompts import (
build_summary_prompt,
)
from ai_text_platform.services.text_generation_service import (
TextGenerationService,
)
class SummarizationService:
def __init__(
self,
text_service: TextGenerationService,
) -> None:
self.text_service = text_service
def summarize(
self,
text: str,
max_words: int = 150,
) -> str:
if not text.strip():
raise ValueError(
"Text cannot be empty."
)
if max_words <= 0:
raise ValueError(
"max_words must be greater than zero."
)
prompt = build_summary_prompt(
text=text,
max_words=max_words,
)
return self.text_service.generate(prompt)
Responsibilities:
SummarizationService → Validate Input → Build Summary Prompt → Call Generic Text Service
This is reusable and easy to test independently.
4.15 Application 3: Translation
Original Text + Target Language → Translation Prompt → AI Service → Translated Text
Create src/ai_text_platform/services/translation_service.py:
from ai_text_platform.prompts.translation_prompts import (
build_translation_prompt,
)
from ai_text_platform.services.text_generation_service import (
TextGenerationService,
)
class TranslationService:
def __init__(
self,
text_service: TextGenerationService,
) -> None:
self.text_service = text_service
def translate(
self,
text: str,
target_language: str,
) -> str:
if not text.strip():
raise ValueError(
"Text cannot be empty."
)
if not target_language.strip():
raise ValueError(
"Target language is required."
)
prompt = build_translation_prompt(
text=text,
target_language=target_language,
)
return self.text_service.generate(prompt)
4.16 Application 4: Email Generation
Imagine a user enters:
Situation: The product delivery is delayed by 5 days.
Recipient: Customer
Tone: Professional and apologetic
The AI generates:
Subject: Update Regarding Your Delivery
Dear Customer,
We sincerely apologize for the delay...
Useful across customer support, sales, HR, internal communication, and marketing.
4.17 Email Prompt
Create src/ai_text_platform/prompts/email_prompts.py:
def build_email_prompt(
situation: str,
recipient: str,
tone: str,
) -> str:
return f"""
You are a professional business communication assistant.
Write an email based on the following information.
Situation:
{situation}
Recipient:
{recipient}
Tone:
{tone}
Requirements:
- Include a clear subject.
- Use professional language.
- Keep the email concise.
- Do not invent details.
"""
4.18 Information Extraction
One of the most valuable AI use cases: converting unstructured text into structured data your systems can actually use.
Input:
John Smith purchased 3 laptops
for $3,000 on March 15, 2026.
Output:
{
"customer_name": "John Smith",
"product": "laptops",
"quantity": 3,
"amount": 3000,
"date": "March 15, 2026"
}
Unstructured Text → Extraction Prompt → AI Model → Structured Output → Application
Widely used for invoice processing, resume parsing, contract analysis, customer data extraction, and email processing.
4.19 Why Structured Output Matters
Suppose the AI returns:
The customer is John Smith and purchased three laptops.
Your application now has to parse this sentence with fragile string logic. Compare that to:
{
"customer_name": "John Smith",
"product": "laptops",
"quantity": 3
}
which can flow directly:
JSON → Python Object → Database
This is a critical, recurring pattern in production AI applications — always prefer structured output when your code needs to act on the result.
4.20 Build a CLI Application
Create src/ai_text_platform/main.py with a simple menu:
AI Text Platform
1. Generate Content
2. Summarize Text
3. Translate Text
4. Generate Email
5. Exit
def main() -> None:
while True:
print("1. Generate Content")
print("2. Summarize Text")
print("3. Translate Text")
print("4. Generate Email")
print("5. Exit")
choice = input("Select an option: ")
if choice == "1":
generate_content()
elif choice == "2":
summarize_text()
elif choice == "3":
translate_text()
elif choice == "4":
generate_email()
elif choice == "5":
break
else:
print("Invalid choice.")
Architectural principle:
CLI → Application Logic → Domain Service → AI Service → OpenAI API
4.21 Input Validation
Never assume user input is valid.
Bad:
max_words = int(
input("Maximum words: ")
)
If the user types abc, this crashes immediately.
Better:
try:
max_words = int(
input("Maximum words: ")
)
except ValueError:
print("Please enter a valid number.")
For production systems, validation should happen before the AI request is even sent — don’t waste an API call on input you already know is invalid.
4.22 Error Handling
try:
result = service.summarize(
text=text,
max_words=150,
)
except ValueError as error:
print(f"Input error: {error}")
except Exception:
print(
"Unable to process your request right now."
)
A real application should also log the underlying technical error internally — while the user-facing message stays simple and doesn’t leak sensitive internal details.
4.23 Logging
Create src/ai_text_platform/utils/logging_config.py:
import logging
def configure_logging() -> None:
logging.basicConfig(
level=logging.INFO,
format=(
"%(asctime)s "
"%(levelname)s "
"%(name)s "
"%(message)s"
),
)
Then:
import logging
logger = logging.getLogger(__name__)
You can log:
logger.info(
"Starting summarization request"
)
and:
logger.exception(
"Summarization request failed"
)
Do not log: API keys, passwords, sensitive customer data, or private documents unnecessarily — logs often have looser access controls than you’d expect.
4.24 Testing Prompt Builders
Prompt builders are pure functions, which makes them easy to test.
Create tests/test_prompts.py:
from ai_text_platform.prompts.summarization_prompts import (
build_summary_prompt,
)
def test_summary_prompt_contains_text() -> None:
prompt = build_summary_prompt(
text="Python is a programming language.",
max_words=100,
)
assert (
"Python is a programming language."
in prompt
)
Another test:
def test_summary_prompt_contains_word_limit() -> None:
prompt = build_summary_prompt(
text="Example text.",
max_words=100,
)
assert "100 words" in prompt
These tests never call the actual API, which makes them fast, cheap, and reliable to run constantly.
4.25 Testing Validation
import pytest
from ai_text_platform.services.summarization_service import (
SummarizationService,
)
def test_empty_text_is_rejected() -> None:
service = SummarizationService(
text_service=None
)
with pytest.raises(ValueError):
service.summarize(
text="",
max_words=100,
)
This verifies application behavior without needing a real API call.
4.26 Mocking AI Calls
In real test suites, you generally don’t want every test hitting the external API — it’s slow, costs money, and makes tests flaky.
Application → Mock AI Service → Fake Response
class FakeTextService:
def generate(
self,
prompt: str,
) -> str:
return "Mock summary"
Then:
service = SummarizationService(
text_service=FakeTextService()
)
This is a genuinely important industry practice — treat it as standard, not optional.
4.27 The Complete Text Generation Flow
┌──────────────────────┐
│ User Input │
└──────────┬───────────┘
│
▼
┌──────────────────────┐
│ Validation │
└──────────┬───────────┘
│
▼
┌──────────────────────┐
│ Domain Service │
└──────────┬───────────┘
│
▼
┌──────────────────────┐
│ Prompt Builder │
└──────────┬───────────┘
│
▼
┌──────────────────────┐
│ AI Text Service │
└──────────┬───────────┘
│
▼
┌──────────────────────┐
│ OpenAI Client │
└──────────┬───────────┘
│
▼
┌──────────────────────┐
│ Generated Text │
└──────────────────────┘
4.28 Practical Exercise 1: Blog Generator
Build a function that accepts Topic, Audience, Tone, Length.
Example:
Topic: Python decorators
Audience: Beginner developers
Tone: Educational
Length: 500 words
Output structure: Title, Introduction, Main Explanation, Example, Conclusion.
4.29 Practical Exercise 2: Meeting Summarizer
Input: a meeting transcript. Output:
{
"summary": "...",
"decisions": [],
"action_items": [],
"risks": []
}
This combines summarization, extraction, and structured output all in one task.
4.30 Practical Exercise 3: Email Assistant
Input:
Situation: Customer's order is delayed.
Tone: Professional and apologetic.
Output:
Subject: Update Regarding Your Order
Dear Customer,
...
4.31 Practical Exercise 4: Multi-Language Translator
Original Text + Target Language → Translated Text
Example:
Input: Good morning, how are you?
Target: Hindi
Output: सुप्रभात, आप कैसे हैं?
4.32 Production Considerations
Input Length — very large inputs may require chunking:
Chunking → Multiple AI Requests → Combined Result
(This becomes central in the RAG chapter.)
Output Validation — never blindly trust generated output:
AI Output → Validation → Application
Sensitive Data — be careful with personal information, financial data, and confidential business documents.
Cost — repeated requests add up; consider caching, smaller inputs, appropriate model selection, and output limits.
Reliability — external API calls can fail; use retry + timeout + logging + graceful failure together.
4.33 Chapter 4 Mini Project
Build an AI Text Processing Platform with a Content Generator, Summarizer, Translator, and Email Generator.
Minimum architecture:
src/
└── ai_text_platform/
├── config/
├── clients/
├── prompts/
├── services/
├── models/
├── utils/
└── main.py
Required development practices:
- Secure API key management
- Reusable OpenAI client
- Separate prompt modules
- Separate service classes
- Input validation
- Error handling
- Logging
- Unit tests
- No hardcoded secrets
- No API calls directly inside every CLI function
Chapter 4 Summary
You learned how to build text-generation applications for content generation, summarization, translation, email generation, and information extraction.
The key architecture:
User Input → Validation → Domain Service → Prompt Template →
AI Service → OpenAI API → Validated Output
The major lesson of this chapter:
A production AI application is not just an API call.
Good Prompt + Good Architecture + Validation + Error Handling + Testing + Security
Next chapter: Chapter 5 — Function Calling & Tools, where we’ll build an AI application that can interact with external functions, APIs, databases, and real-world business systems.
