Loading
Loading
We'll build a FastAPI app with Claude API and deploy it with Docker Compose.
ai-docker-project/
âââ app/
â âââ main.py â FastAPI Application
â âââ __init__.py
âââ requirements.txt
âââ Dockerfile
âââ docker-compose.yml
âââ .env â API Keys (never commit to Git)
âââ .dockerignore
from fastapi import FastAPI
from pydantic import BaseModel
import anthropic, os
app = FastAPI(title="AI Assistant API")
client = anthropic.Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
class ChatRequest(BaseModel):
message: str
max_tokens: int = 500
@app.get("/health")
def health():
return {"status": "ok"}
@app.post("/chat")
def chat(req: ChatRequest):
msg = client.messages.create(
model="claude-haiku-4-5-20251001",
max_tokens=req.max_tokens,
messages=[{"role": "user", "content": req.message}],
)
return {"reply": msg.content[0].text}
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
version: "3.9"
services:
api:
build: .
ports:
- "8080:8000"
env_file:
- .env
volumes:
- .:/app
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 10s
retries: 3
# Start the entire project
docker compose up -d
# View logs
docker compose logs -f api
# Rebuild after code changes
docker compose up -d --build
# Stop everything
docker compose down
# Test the API
curl http://localhost:8080/health
curl -X POST http://localhost:8080/chat \
-H "Content-Type: application/json" \
-d '{"message": "Hello!"}'
#!/usr/bin/env python3
"""
Ų
ØīØąŲØđ: ŲØīØą FastAPI ŲŲ Docker
Project: FastAPI + Claude + Docker Complete Project Generator
"""
from pathlib import Path
import os
PROJECT_NAME = "ai-docker-project"
# âââ Ų
ØØŠŲŲ Ø§ŲŲ
ŲŲØ§ØŠ âââââââââââââââââââââââââââââââââââââââââ
FILES = {
"app/__init__.py": "",
"app/main.py": '''from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
import anthropic
import os
import logging
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
logger = logging.getLogger(__name__)
app = FastAPI(title="AI Assistant API", version="1.0.0")
app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"])
client = anthropic.Anthropic(api_key=os.environ.get("ANTHROPIC_API_KEY", ""))
class ChatRequest(BaseModel):
message: str
max_tokens: int = 500
class ChatResponse(BaseModel):
reply: str
tokens_used: int
@app.get("/")
def root():
return {"service": "AI Assistant API", "status": "ok"}
@app.get("/health")
def health():
return {"healthy": True}
@app.post("/chat", response_model=ChatResponse)
def chat(req: ChatRequest):
try:
msg = client.messages.create(
model="claude-haiku-4-5-20251001",
max_tokens=req.max_tokens,
messages=[{"role": "user", "content": req.message}],
)
tokens = msg.usage.input_tokens + msg.usage.output_tokens
logger.info(f"Chat request processed: {tokens} tokens")
return ChatResponse(reply=msg.content[0].text, tokens_used=tokens)
except Exception as e:
logger.error(f"Error: {e}")
raise HTTPException(status_code=500, detail=str(e))
''',
"requirements.txt": """fastapi==0.115.0
uvicorn[standard]==0.31.0
anthropic==0.34.0
pydantic==2.9.0
python-dotenv==1.0.1""",
"Dockerfile": """FROM python:3.11-slim
# ØŠØŦØĻŲØŠ curl ŲŲŲ health check
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
WORKDIR /app
# ŲØģØŪ اŲŲ
ØŠØ·ŲØĻØ§ØŠ ØĢŲŲØ§Ų (cache optimization)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# ŲØģØŪ اŲŲŲØŊ
COPY . .
ENV PYTHONUNBUFFERED=1
EXPOSE 8000
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]""",
"docker-compose.yml": """version: "3.9"
services:
api:
build: .
container_name: ai-assistant-api
ports:
- "8080:8000"
env_file:
- .env
volumes:
- .:/app
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 10s""",
".env.example": """# Ø§ŲØģØŪ ŲØ°Ø§ اŲŲ
ŲŲ ØĨŲŲ .env ŲØĢØķŲ Ų
ŲØŠØ§ØŲ
ANTHROPIC_API_KEY=sk-ant-your-key-here
LOG_LEVEL=info""",
".dockerignore": """__pycache__/
*.pyc
*.pyo
.env
.env.*
.git/
.github/
tests/
*.log
*.md
venv/
.venv/
.pytest_cache/""",
".gitignore": """.env
__pycache__/
*.pyc
.venv/
venv/
*.log
.pytest_cache/""",
}
# âââ ØŠŲŲŲØŊ اŲŲ
ØīØąŲØđ âââââââââââââââââââââââââââââââââââââââââ
def generate_project(base_dir: str = "/tmp"):
project = Path(base_dir) / PROJECT_NAME
created = []
print(f"\nðģ ØŠŲŲŲØŊ Ų
ØīØąŲØđ: {PROJECT_NAME}")
print("="*55)
for rel_path, content in FILES.items():
file_path = project / rel_path
file_path.parent.mkdir(parents=True, exist_ok=True)
file_path.write_text(content)
size = len(content.encode())
print(f" â
{rel_path:<35} ({size:>5} bytes)")
created.append(file_path)
return project, created
project_path, files = generate_project()
# âââ ØđØąØķ ŲŲŲŲ Ø§ŲŲ
ØīØąŲØđ âââââââââââââââââââââââââââââââââââââ
print(f"\nð ŲŲŲŲ Ø§ŲŲ
ØīØąŲØđ:")
print(f" {PROJECT_NAME}/")
structure_display = [
("app/", "ØØēŲ
ØĐ Ø§ŲØŠØ·ØĻŲŲ"),
(" __init__.py", ""),
(" main.py", "â FastAPI + Claude API"),
("requirements.txt", "â Python dependencies"),
("Dockerfile", "â Docker build instructions"),
("docker-compose.yml","â Multi-service orchestration"),
(".env.example", "â Template (Ø§ŲØģØŪ ØĨŲŲ .env)"),
(".dockerignore", "â Files to exclude"),
(".gitignore", "â Files to exclude from Git"),
]
for name, desc in structure_display:
suffix = f" {desc}" if desc else ""
print(f" âââ {name}{suffix}")
# âââ ØĢŲØ§Ų
Øą Ø§ŲØŠØīØšŲŲ ââââââââââââââââââââââââââââââââââââââââ
print(f"\nð ØŪØ·ŲØ§ØŠ ØŠØīØšŲŲ Ø§ŲŲ
ØīØąŲØđ:")
steps = [
("Ø§ŲØģØŪ Ų
ŲØŠØ§Ø API", "cp .env.example .env && nano .env"),
("ØĻŲØ§ØĄ ŲØŠØīØšŲŲ", "docker compose up -d --build"),
("ØŠØŲŲ Ų
Ų Ø§ŲØģØŽŲØ§ØŠ", "docker compose logs -f api"),
("اØŪØŠØĻØą اŲŲ API", "curl http://localhost:8080/health"),
("اØŪØŠØĻØą Claude", 'curl -X POST http://localhost:8080/chat -H "Content-Type: application/json" -d \'{"message": "Ų
ØąØØĻØ§"}\''),
("ØĨŲŲØ§Ų Ø§ŲØŠØ·ØĻŲŲ", "docker compose down"),
]
for i, (desc, cmd) in enumerate(steps, 1):
print(f"\n {i}. {desc}:")
print(f" $ {cmd[:70]}")
# âââ ØŠŲØļŲŲ ââââââââââââââââââââââââââââââââââââââââââââââââ
import shutil
shutil.rmtree(project_path, ignore_errors=True)
print(f"\nâ
ØŠŲ
ØŠŲŲŲØŊ {len(FILES)} Ų
ŲŲ ØĻŲØŽØ§Ø!")
print(f"ð Ų
ØĻØąŲŲ! ØĢŲŲ
ŲØŠ ØŊŲØąØĐ Docker & Linux")