From Script to Web App
Everything you've built over the last four days runs in a terminal. You type python script.py, you see output, you close the window. That's not a product. That's a proof of concept.
A web application means anyone on the internet can use what you built — without installing Python, without touching a terminal, without knowing that Claude is involved. They just open a browser and ask a question.
Today you build that. A real API backend, a simple HTML frontend, and an understanding of what it takes to make it production-grade. By the end of this lesson you'll have something you could put in front of a colleague or a client and say "try it."
Install FastAPI and uvicorn
Run this before we start: pip install fastapi uvicorn
FastAPI is the most popular Python web framework for building APIs. uvicorn is the server that runs your FastAPI application.
Build the API
Create a new file called app.py. This is the entire backend for your AI document assistant:
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import anthropic
import os
app = FastAPI(title="AI Document Assistant")
client = anthropic.Anthropic()
# ── Data Models ──────────────────────────────────────────
# Pydantic validates and documents your request/response shapes
class Question(BaseModel):
question: str
class Answer(BaseModel):
answer: str
sources: list[str]
# ── Knowledge Base ───────────────────────────────────────
# In production this would be a vector database from Day 4
knowledge = {
"company-policy.txt": (
"Our company offers unlimited PTO, requires 2 weeks notice for "
"time off, and operates remote-first. Core hours are 10am-3pm "
"in your local timezone. Equipment budget is $2,000/year."
),
"product-faq.txt": (
"Our product has 3 tiers: Free (100 requests/day), Pro ($29/mo, "
"10K requests/day), Enterprise (custom pricing, SLA, SSO). "
"All plans include API access and a 14-day free trial."
),
"onboarding.txt": (
"New employees receive a laptop on day 1. Slack and GitHub access "
"within 24 hours. Compliance training completed by end of week 1. "
"30/60/90 day check-ins with manager. Buddy program available."
),
}
# ── Routes ───────────────────────────────────────────────
@app.post("/ask", response_model=Answer)
async def ask_question(q: Question):
"""Ask a question about company documents"""
if not q.question.strip():
raise HTTPException(status_code=400, detail="Question cannot be empty")
# Simple keyword retrieval (replace with Day 4 RAG for production)
relevant = []
for name, content in knowledge.items():
if any(word in content.lower() for word in q.question.lower().split()):
relevant.append((name, content))
# Fallback: return first two docs if nothing matches
if not relevant:
relevant = list(knowledge.items())[:2]
context = "\n\n".join([f"[{n}]: {c}" for n, c in relevant])
message = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=512,
system="Answer based only on the provided documents. Cite sources by filename.",
messages=[{
"role": "user",
"content": f"Documents:\n{context}\n\nQuestion: {q.question}"
}]
)
return Answer(
answer=message.content[0].text,
sources=[n for n, _ in relevant]
)
@app.get("/health")
async def health():
"""Simple health check endpoint"""
return {"status": "ok"}
Start the server: uvicorn app:app --reload
The --reload flag restarts the server automatically when you save changes. You'll see output like Uvicorn running on http://127.0.0.1:8000. Your API is live.
Test it from a second terminal window:
curl -X POST http://localhost:8000/ask \
-H "Content-Type: application/json" \
-d '{"question": "What is the PTO policy?"}'
You should get back a JSON response with an answer and a sources list. That's a working AI API.
What each piece does
FastAPI is the framework that handles HTTP requests and routes them to your Python functions. The @app.post("/ask") decorator tells FastAPI: "when someone sends a POST request to /ask, run this function."
Pydantic (the BaseModel classes) validates that incoming requests have the right shape. If someone sends a request without a question field, FastAPI returns a 422 error automatically — you never write validation code manually.
async def makes your functions asynchronous. When your function is waiting for Claude to respond, FastAPI can handle other requests in the meantime. This is how a single process handles thousands of concurrent users.
Visit http://localhost:8000/docs in your browser. FastAPI generates interactive documentation automatically from your code. You can test your API directly from the browser without writing any curl commands.
Add a Simple Frontend
Add this route to your app.py — it serves an HTML page from inside Python:
# Add to your imports at the top:
from fastapi.responses import HTMLResponse
# Add this route alongside your existing routes:
@app.get("/", response_class=HTMLResponse)
async def home():
"""Serve the frontend UI"""
return """
<html>
<head>
<title>AI Document Assistant</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, sans-serif;
max-width: 640px;
margin: 60px auto;
padding: 0 20px;
background: #fafaf9;
}
h1 { font-size: 24px; color: #1a1a1a; margin-bottom: 6px; }
.sub { font-size: 14px; color: #888; margin-bottom: 28px; }
input {
width: 100%;
padding: 13px 16px;
font-size: 15px;
border: 2px solid #e2e8f0;
border-radius: 8px;
background: white;
outline: none;
transition: border-color .2s;
}
input:focus { border-color: #c4873e; }
button {
margin-top: 8px;
padding: 12px 28px;
background: #1e3a5f;
color: white;
border: none;
border-radius: 8px;
font-size: 15px;
font-weight: 600;
cursor: pointer;
transition: background .2s;
}
button:hover { background: #2a4f7f; }
button:disabled { opacity: .5; cursor: not-allowed; }
#answer {
margin-top: 24px;
padding: 20px;
background: white;
border: 1px solid #e8e4de;
border-radius: 8px;
display: none;
line-height: 1.7;
}
#answer .label { font-size: 11px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: #999; margin-bottom: 8px; }
#answer .text { font-size: 15px; color: #3d3d3d; margin-bottom: 14px; }
#answer .sources { font-size: 12px; color: #999; font-style: italic; }
.spinner { display: inline-block; width: 14px; height: 14px; border: 2px solid rgba(255,255,255,.3); border-top-color: white; border-radius: 50%; animation: spin .7s linear infinite; margin-left: 6px; vertical-align: middle; }
@keyframes spin { to { transform: rotate(360deg); } }
</style>
</head>
<body>
<h1>AI Document Assistant</h1>
<p class="sub">Ask any question about our company documents.</p>
<input
id="q"
placeholder="e.g. What is the PTO policy?"
onkeypress="if(event.key==='Enter') ask()"
autocomplete="off"
>
<br>
<button id="btn" onclick="ask()">Ask</button>
<div id="answer"></div>
<script>
async function ask() {
const q = document.getElementById('q').value.trim();
if (!q) return;
const btn = document.getElementById('btn');
const div = document.getElementById('answer');
btn.disabled = true;
btn.innerHTML = 'Thinking<span class="spinner"></span>';
div.style.display = 'block';
div.innerHTML = '<div class="label">Answer</div><div class="text">Working on it...</div>';
try {
const res = await fetch('/ask', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ question: q })
});
if (!res.ok) throw new Error('Request failed');
const data = await res.json();
div.innerHTML =
'<div class="label">Answer</div>' +
'<div class="text">' + data.answer.replace(/\\n/g, '<br>') + '</div>' +
'<div class="sources">Sources: ' + data.sources.join(', ') + '</div>';
} catch (e) {
div.innerHTML = '<div class="text" style="color:#dc2626">Something went wrong. Please try again.</div>';
}
btn.disabled = false;
btn.textContent = 'Ask';
}
</script>
</body>
</html>"""
Save the file — uvicorn reloads automatically. Open http://localhost:8000 in your browser.
You now have a working AI web application with a backend API and a frontend interface. Type a question and hit Ask. You'll see the loading spinner, then the AI's answer with source citations. This is the pattern behind every AI product you've ever used.
What you just built
A complete full-stack AI application: Python backend with a REST API, HTML/CSS/JS frontend, Claude integration, and source-cited responses — all in one file under 100 lines of Python.
What the frontend is doing
When you click Ask, the JavaScript fetch() call sends a POST request to your FastAPI backend — the same request you tested with curl earlier. The backend calls Claude, gets an answer, and returns JSON. The frontend displays it. The browser never "knows" Claude is involved; it just gets JSON back from your API.
This separation — frontend talks to your API, your API talks to Claude — is intentional. Your API key lives server-side, never in the browser. Users can't see it. This is the architecture you'd use in production.
Production Considerations
What you've built is a working application. What makes it production-ready is a set of additional concerns you don't need on day one — but you need before you show it to real users.
Environment variables
Never hardcode your API key. Use os.environ.get("ANTHROPIC_API_KEY") and store it in a .env file that's in your .gitignore. One accidental commit exposes it to the world.
Rate limiting
One user making 1,000 requests/minute can burn your API budget in minutes. Use slowapi or a reverse proxy like nginx to cap requests per IP. Most APIs need this before going public.
Error handling
What happens when Claude is down? When the user sends a 50,000-word document that exceeds token limits? Wrap your API calls in try/except and return useful errors — don't let your app crash silently.
Authentication
Who can access your app? Add API key auth for services, or OAuth for user-facing apps. FastAPI has built-in support for both. Without auth, anyone who finds your URL can use your Claude budget.
Logging
Log every question asked (not the answers, for privacy). You need to know what people actually use your app for, what's failing, and what's costing money. Use Python's logging module or a service like Datadog.
Cost monitoring
Set budget alerts in the Anthropic dashboard. Know your cost per request. At scale, 1 cent/request is $100/day at 10K requests. Monitor before you market.
Deployment options
- Railway: Easiest. Connect your GitHub repo, it deploys automatically. $5/mo to start.
- Render: Similar to Railway. Free tier available. Good for small apps.
- AWS (App Runner or ECS): More control, more cost. Right choice when you need VPC, compliance, or enterprise integrations. We cover this on Day 3 of the bootcamp.
- Cloudflare Workers: Edge deployment, global latency, free tier. Best for lightweight APIs without heavy Python dependencies.
These aren't things you need to implement today. They're the things you'll add one by one as your application grows. The order matters: environment variables first (security), error handling second (reliability), rate limiting third (cost), then auth and logging.
What You Built This Week
Five days ago you didn't know how to call an AI API. Look at what you built:
Connected to the Claude API and built a writing tool
API keys, the Anthropic client, system prompts, and streaming. You sent your first message to an LLM programmatically.
Built a document processor that extracts structured data
Pydantic models, structured JSON output, batch processing. You turned unstructured documents into structured data automatically.
Built an AI agent that uses tools and makes decisions
Tool use, the agent loop, multi-step reasoning. You built a system that decides what actions to take to complete a goal.
Built a RAG system that answers questions from your data
Keyword and semantic retrieval, embeddings, cosine similarity. You made Claude smart about data it was never trained on.
Deployed it all as a web application
FastAPI, Pydantic, async, HTML frontend, production architecture. You turned Python scripts into a real product accessible from any browser.
You went from zero to a deployed AI application in five days. You understand APIs, prompt engineering, agents, RAG, and deployment. You know how to structure AI calls, handle errors, and think about production. You're ahead of 95% of professionals who use AI tools daily but have never looked under the hood.
Course Complete
You've completed the
5-Day AI Foundations Course
You built five real AI applications from scratch. That's not a tutorial you followed — that's code you understand, can modify, and can ship.
Ready to Go Deeper?
You built 5 AI projects in 5 days by yourself. Now imagine doing it in a room with Bo Peng and 39 other professionals for 3 full days.
The free course gave you the foundations. The bootcamp goes into production depth — the things you'd need to actually ship AI products at work, charge a client, or build a business on top of AI.
No commitment yet — just save your spot.
Full refund up to 30 days before the event.
What you built in 5 days
- Day 1: Claude API connection, writing tool, streaming responses
- Day 2: Document processor, structured JSON extraction, batch processing
- Day 3: AI agent with tool use, multi-step reasoning, the agent loop
- Day 4: RAG system with keyword and semantic search, embeddings, cosine similarity
- Day 5: FastAPI backend, HTML frontend, production architecture