cd api
pip install -r requirements.txt# Migrate existing database (adds credits column)
python api/migrate_add_credits.py
# Or with custom database path
python api/migrate_add_credits.py /path/to/database.dbuvicorn api.main:app --reload --host 0.0.0.0 --port 8000curl -X POST "http://localhost:8000/register" \
-H "Content-Type: application/json" \
-d '{
"username": "alice",
"email": "alice@example.com",
"password": "password123"
}'
# Save the access_token from responsecurl -X POST "http://localhost:8000/login?username=alice&password=password123"
# Save the access_token from responsecurl -X GET "http://localhost:8000/credits" \
-H "Authorization: Bearer YOUR_TOKEN_HERE"curl -X POST "http://localhost:8000/predict" \
-H "Authorization: Bearer YOUR_TOKEN_HERE" \
-H "Content-Type: application/json" \
-d '{
"features": {
"Age": 45,
"Gender": "Male",
"Tenure": 24,
"MonthlyCharges": 75.50
}
}'python api/test_credit_system.pyimport sqlite3
conn = sqlite3.connect('api/churn_api.db')
cursor = conn.cursor()
cursor.execute("PRAGMA table_info(users)")
for row in cursor.fetchall():
print(row)
conn.close()import sqlite3
conn = sqlite3.connect('api/churn_api.db')
cursor = conn.cursor()
cursor.execute("SELECT id, username, email, credits FROM users")
for row in cursor.fetchall():
print(f"ID: {row[0]}, User: {row[1]}, Email: {row[2]}, Credits: {row[3]}")
conn.close()# Start server, then visit:
# Swagger UI: http://localhost:8000/docs
# ReDoc: http://localhost:8000/redoccp api/churn_api.db api/churn_api.db.backup_$(date +%Y%m%d_%H%M%S)cp api/churn_api.db.backup_TIMESTAMP api/churn_api.dbrm api/churn_api.db
# Tables will be recreated on next API startimport sqlite3
conn = sqlite3.connect('api/churn_api.db')
cursor = conn.cursor()
# Set specific user to 0 credits (to test 402 error)
cursor.execute("UPDATE users SET credits = 0 WHERE username = 'alice'")
conn.commit()
# Give user more credits
cursor.execute("UPDATE users SET credits = 100 WHERE username = 'alice'")
conn.commit()
conn.close()# Activate virtual environment
.\.venv\Scripts\Activate.ps1
# Install dependencies
cd api
pip install -r requirements.txt
# Run migration
python migrate_add_credits.py
# Start server
uvicorn main:app --reload --host 0.0.0.0 --port 8000# Register user
$body = @{
username = "alice"
email = "alice@example.com"
password = "password123"
} | ConvertTo-Json
Invoke-RestMethod -Uri "http://localhost:8000/register" `
-Method POST `
-ContentType "application/json" `
-Body $body
# Save token
$token = "YOUR_TOKEN_HERE"
# Check credits
Invoke-RestMethod -Uri "http://localhost:8000/credits" `
-Method GET `
-Headers @{Authorization="Bearer $token"}
# Make prediction
$features = @{
features = @{
Age = 45
Gender = "Male"
Tenure = 24
}
} | ConvertTo-Json
Invoke-RestMethod -Uri "http://localhost:8000/predict" `
-Method POST `
-ContentType "application/json" `
-Headers @{Authorization="Bearer $token"} `
-Body $featuresimport requests
class ChurnAPIClient:
def __init__(self, base_url="http://localhost:8000"):
self.base_url = base_url
self.token = None
def register(self, username, email, password):
"""Register new user with 100 free credits."""
response = requests.post(
f"{self.base_url}/register",
json={"username": username, "email": email, "password": password}
)
self.token = response.json()["access_token"]
return self.token
def login(self, username, password):
"""Login existing user."""
response = requests.post(
f"{self.base_url}/login",
params={"username": username, "password": password}
)
self.token = response.json()["access_token"]
return self.token
def get_credits(self):
"""Check current credit balance."""
response = requests.get(
f"{self.base_url}/credits",
headers={"Authorization": f"Bearer {self.token}"}
)
return response.json()
def predict(self, features):
"""Make a prediction (costs 1 credit)."""
response = requests.post(
f"{self.base_url}/predict",
headers={"Authorization": f"Bearer {self.token}"},
json={"features": features}
)
return response.json()
# Usage
client = ChurnAPIClient()
client.register("alice", "alice@example.com", "password123")
# Check credits
credits = client.get_credits()
print(f"Credits: {credits['credits']}")
# Make prediction
result = client.predict({
"Age": 45,
"Gender": "Male",
"Tenure": 24
})
print(f"Prediction: {result['prediction']}")
print(f"Remaining: {result['remaining_credits']}")# Linux/Mac
watch -n 2 'curl -s -H "Authorization: Bearer TOKEN" http://localhost:8000/credits'
# Windows PowerShell
while($true) {
Invoke-RestMethod -Uri "http://localhost:8000/credits" `
-Headers @{Authorization="Bearer $token"}
Start-Sleep -Seconds 2
Clear-Host
}sqlite3 api/churn_api.db "SELECT COUNT(*) FROM users"sqlite3 api/churn_api.db "SELECT username, credits FROM users WHERE credits < 10"curl http://localhost:8000/health
# Expected: {"status": "ok"}curl http://localhost:8000/schema
# Expected: {"expects": "...", "required_columns": [...]}curl -X POST "http://localhost:8000/predict" \
-H "Content-Type: application/json" \
-d '{"features": {}}'
# Expected: 401 Unauthorized or 403 Forbidden# If running with uvicorn --reload
# Logs appear in terminal
# If running in background
tail -f nohup.out # Linux/Mac
Get-Content -Path .\logs.txt -Wait # Windows# Complete test in one command
python api/test_credit_system.py && echo "β
All tests passed!" || echo "β Tests failed"import sqlite3
import csv
conn = sqlite3.connect('api/churn_api.db')
cursor = conn.cursor()
cursor.execute("SELECT id, username, email, credits FROM users")
with open('users_export.csv', 'w', newline='') as f:
writer = csv.writer(f)
writer.writerow(['ID', 'Username', 'Email', 'Credits'])
writer.writerows(cursor.fetchall())
conn.close()
print("β
Exported to users_export.csv")import sqlite3
import csv
conn = sqlite3.connect('api/churn_api.db')
cursor = conn.cursor()
with open('users_update.csv', 'r') as f:
reader = csv.DictReader(f)
for row in reader:
cursor.execute(
"UPDATE users SET credits = ? WHERE username = ?",
(row['credits'], row['username'])
)
conn.commit()
conn.close()
print("β
Credits updated from CSV")# .env file (optional)
DATABASE_URL=sqlite:///./churn_api.db
SECRET_KEY=your-secret-key-change-in-production
MLFLOW_EXPERIMENT_NAME=customer_churn_optimization
BEST_MODEL_METRIC=f1
# Load in shell
export $(cat .env | xargs) # Linux/Mac
Get-Content .env | ForEach-Object { [System.Environment]::SetEnvironmentVariable($_.Split('=')[0], $_.Split('=')[1]) } # WindowsFor more details, see FINALIZATION_GUIDE.md