The Capstone: A Real AI Toolkit for Bright Leaf Coffee and GreenDesk
Twenty-one parts have built ten real, distinct AI-powered applications. This capstone brings them together — not as separate scripts, but as one real, coherent toolkit, showing how everything this series built actually coexists in a single, shared codebase.
The real, complete toolkit structure
ai-projects/
├── shared/
│ ├── ai_client.py → part 1: shared client, base ask()
│ └── style_guide.py → part 15: BRAND style guides
├── support/ → parts 2, 3, 4, 5: chatbot (Python,
│ Flask, Django)
├── greendesk_api/ → parts 6, 7: FastAPI lead qualification
├── summarizer.py → parts 8, 9: summarization + chunking
├── translator.py → parts 10, 11: translation + tone
├── qa_app.py → parts 12, 13: Q&A + citations
├── content_generator.py → parts 14, 15: blog drafts, on-brand
├── email_generator.py → part 16: follow-up emails
├── code_explainer.py → part 17: code explanation CLI
├── cache.py → part 18: Redis caching layer
└── tests/ → part 19: mocked test suiteEvery real file here maps directly to a specific part of this series — nothing new is introduced in this capstone; it's a real, deliberate assembly of what already exists into a genuinely coherent toolkit.
A real, shared module every tool actually uses
# shared/ai_client.py — the real, single source every tool imports from
from anthropic import Anthropic, APIStatusError, APIConnectionError
import os
from dotenv import load_dotenv
load_dotenv()
def get_client() -> Anthropic:
api_key = os.environ.get("ANTHROPIC_API_KEY")
if not api_key:
raise RuntimeError("ANTHROPIC_API_KEY is not set")
return Anthropic(api_key=api_key)
def safe_ask(system: str, user_message: str, max_tokens: int = 1024) -> str:
"""The real, shared request pattern every tool in this toolkit
ultimately calls — grounding, error handling, and a consistent
model choice, in exactly one place."""
try:
client = get_client()
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=max_tokens,
system=system,
messages=[{"role": "user", "content": user_message}],
)
return response.content[0].text
except (APIStatusError, APIConnectionError):
return "We're having trouble processing this right now — please try again shortly."This is the real, single, shared foundation every one of this series' ten tools ultimately builds on — part 7's error handling, written once here, rather than duplicated across the summarizer, translator, and every other real project.
This is genuinely why part 1 started with a shared client module — building ten separate, real AI features without one is exactly how a codebase ends up with ten slightly different, inconsistent versions of the same error-handling and request logic. Consolidating it here, in the capstone, is the real, concrete payoff of that early architectural decision.
A real, final pre-launch checklist for this toolkit
[ ] Every tool imports get_client()/safe_ask() from shared/, not its
own separate client setup (part 1)
[ ] Every user-facing tool (chatbot, Q&A app) is grounded in real,
provided data, not relying on the model's own training knowledge
(parts 2, 12, 13)
[ ] Every externally-sent output (emails, part 16) has a real, human
review step before sending
[ ] Real rate limiting and authentication on every API endpoint
(part 7)
[ ] Real caching applied only where inputs genuinely recur (part 18)
[ ] A real, mocked test suite covering the deterministic logic in
every tool (part 19)
[ ] Real secrets managed via the deployment platform, not a shipped
.env file (part 20)This is directly part 21's mistakes roundup, restated as a real, actionable checklist — the same pattern every capstone across this site's tutorial series has used to close out a real, complete project.
Quick links, by use case
- Setup and shared foundation: Setting up a real Python AI project
- Chatbots: Build an AI chatbot with Python · Adding a web UI · Build an AI chatbot with Django
- APIs: Build an AI REST API with FastAPI · Authentication and rate limiting
- Summarization and translation: Build an AI text summarizer · Handling documents that exceed the context window · Build an AI text translator · Preserving tone and formatting
- Question-answering: Build an AI question-answering app · Adding source citations
- Content generation: Build an AI content generator · Keeping AI-generated content on-brand · Build an AI email generator · Build an AI code explainer
- Production concerns: Caching AI responses · Testing AI features without burning credits · Deploying a real Python AI application · Common mistakes
What connects this series to the rest of this site
This toolkit's real chatbot connects directly to the AI Fundamentals
series' own project
Its content generator connects directly to the Content Marketing
series' funnel-stage framework
Its email generator connects directly to the same GreenDesk sales
context referenced throughout the Google Ads and Meta Ads seriesEvery real tool built across this series exists because a genuine, specific need for it was already established somewhere else on this site — this wasn't ten disconnected coding exercises, but ten real, practical answers to needs Bright Leaf Coffee and GreenDesk already had.
That's the complete AI Projects with Python series — from a shared setup through to ten real, working AI-powered applications, unified into one coherent toolkit. Combined with the AI Fundamentals series' own conceptual foundation and the Django and Content Marketing series this project draws on throughout, this series closes the loop from understanding how AI works to actually shipping it in real, production Python code.