Skip to content

About

πŸ‘‰ A production-oriented FastAPI backend for LLM generation, structured AI output, token usage, cost estimation, and provider error handling.

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Latest commit

Β 

History

6 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

🧠 AI Playground API

Project 01 | AI Backend Engineering

A small API with real engineering underneath. βš™οΈπŸ—Ώ

Python FastAPI OpenAI Tests CI License


πŸš€ The Idea

AI Playground API is a FastAPI backend built to establish the first foundation of an AI-powered backend system.

Instead of stopping at:

Client β†’ LLM β†’ Response

the project introduces the backend engineering around that interaction:

Client
  ↓
FastAPI
  ↓
Validation
  ↓
AI Service
  ↓
OpenAI Responses API
  ↓
Usage + Cost
  ↓
Clean API Response

The goal is simple:

Make communication with an LLM behave like a proper backend service.


✨ What It Can Do

Capability Included
πŸ€– LLM generation βœ…
🧩 Structured AI output βœ…
πŸŽ›οΈ Reasoning control βœ…
πŸ”’ Token usage βœ…
πŸ’° Cost estimation βœ…
πŸ›‘οΈ Provider error handling βœ…
πŸ“ Application logging βœ…
πŸ” Environment secrets βœ…
πŸ§ͺ Automated testing βœ…
βš™οΈ GitHub Actions CI βœ…

🌐 API

GET /

Basic service response.

GET /health

Returns the application's health status and version.

POST /generate

Generates a normal LLM response.

Example request:

{
  "prompt": "Explain dependency injection in FastAPI.",
  "model": "gpt-5.6-luna",
  "reasoning_effort": "low",
  "max_output_tokens": 300
}

Example response shape:

{
  "text": "Dependency injection in FastAPI...",
  "model": "gpt-5.6-luna",
  "usage": {
    "input_tokens": 12,
    "output_tokens": 95,
    "total_tokens": 107,
    "reasoning_tokens": 0
  },
  "estimated_cost": 0.000116
}

🧩 Structured Generation

POST /generate/structured

Instead of relying on arbitrary model text, the endpoint returns data through a Pydantic schema.

class StructuredAIResponse(BaseModel):
    answer: str
    summary: str

Example:

{
  "answer": "An API allows software systems to communicate.",
  "summary": "APIs provide structured software communication."
}

This creates a predictable boundary between model output and backend data.


πŸŽ›οΈ Request Controls

The request schema supports:

model
reasoning_effort
max_output_tokens

Valid reasoning levels:

none
low
medium
high
xhigh
max

Input constraints are enforced before requests reach the provider.


πŸ›‘οΈ Reliability

External services fail.

This project treats those failures as part of the API design.

Provider Timeout
      ↓
AIServiceTimeoutError
      ↓
504 Gateway Timeout
Rate Limit
      ↓
AIServiceRateLimitError
      ↓
429 Too Many Requests
Connection / Provider Failure
      ↓
Application Exception
      ↓
502 Bad Gateway

Provider-specific exceptions are translated into application-level errors instead of leaking implementation details to API consumers.


πŸ’° Usage & Cost

Every normal generation response exposes token usage:

Input Tokens
Output Tokens
Total Tokens
Reasoning Tokens

The service also calculates an estimated request cost from input and output token usage.

Cost calculation is isolated in:

app/utils/cost.py

The returned cost is an estimate, not a billing statement.


πŸ“ Logging

Important AI service events are logged:

Request
  ↓
Provider call
  ↓
Provider response
  ↓
Usage calculation
  ↓
API response

Errors are logged without exposing API credentials.

Logging configuration is centralized in:

app/logging_config.py

πŸ—οΈ Architecture

                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚    Client     β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜
                            ↓
                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚    FastAPI    β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜
                            ↓
                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚   Pydantic    β”‚
                    β”‚  Validation   β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜
                            ↓
                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚  AI Service   β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜
                            ↓
                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚    OpenAI     β”‚
                    β”‚ Responses API β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

The main separation is:

HTTP Layer
    ↓
Service Layer
    ↓
Provider Layer

This keeps API routing separate from AI-provider communication.


πŸ“ Project Structure

AI-Playground-API/
β”‚
β”œβ”€β”€ app/
β”‚   β”œβ”€β”€ exceptions/
β”‚   β”‚   β”œβ”€β”€ custom_exceptions.py
β”‚   β”‚   └── handlers.py
β”‚   β”‚
β”‚   β”œβ”€β”€ services/
β”‚   β”‚   └── ai_services.py
β”‚   β”‚
β”‚   β”œβ”€β”€ utils/
β”‚   β”‚   └── cost.py
β”‚   β”‚
β”‚   β”œβ”€β”€ config.py
β”‚   β”œβ”€β”€ logging_config.py
β”‚   β”œβ”€β”€ main.py
β”‚   └── schemas.py
β”‚
β”œβ”€β”€ tests/
β”‚   β”œβ”€β”€ test_ai_service_errors.py
β”‚   β”œβ”€β”€ test_ai_service_request.py
β”‚   β”œβ”€β”€ test_ai_structured_response_errors.py
β”‚   β”œβ”€β”€ test_cost.py
β”‚   β”œβ”€β”€ test_exception_handlers.py
β”‚   β”œβ”€β”€ test_generate.py
β”‚   β”œβ”€β”€ test_structured_response.py
β”‚   └── test_validation.py
β”‚
β”œβ”€β”€ .github/
β”‚   └── workflows/
β”‚       └── ci.yml
β”‚
β”œβ”€β”€ .env.example
β”œβ”€β”€ .gitignore
β”œβ”€β”€ LICENSE
β”œβ”€β”€ pytest.ini
β”œβ”€β”€ README.md
└── requirements.txt

πŸ” Configuration

Create a local .env file:

OPENAI_API_KEY=your_api_key_here

The real .env file is excluded from version control.

A safe template is provided:

.env.example

Never commit real API credentials.


πŸ§ͺ Testing

Run the complete local test suite:

python -m pytest -q

Current result:

19 passed

The real provider test is explicitly marked:

@pytest.mark.integration

Run without external provider access:

python -m pytest -q -m "not integration"

Current CI result:

18 passed
1 deselected

Run the integration test separately when a valid local API key is available:

python -m pytest -q -m integration

βš™οΈ Continuous Integration

GitHub Actions runs automatically on:

push
pull_request

Pipeline:

Checkout
   ↓
Python Setup
   ↓
Install Dependencies
   ↓
Run Tests
   ↓
βœ… Pass

External integration tests are excluded from CI.

CI uses a non-secret placeholder:

OPENAI_API_KEY=ci-test-placeholder

No real provider credential is stored in the workflow.


πŸš€ Run Locally

1. Create environment

python -m venv .venv

2. Activate

source .venv/bin/activate

3. Install dependencies

python -m pip install -r requirements.txt

4. Configure .env

OPENAI_API_KEY=your_api_key_here

5. Start the API

python -m fastapi dev app/main.py

Then explore the generated FastAPI documentation.


🧠 Engineering Decisions

Service layer: keeps provider communication out of route handlers.

Custom exceptions: creates a stable application-level error boundary.

Structured output: turns model output into validated application data.

No database: this project has no persistence requirement.

No Docker: containerization is intentionally deferred because this single-service project has no infrastructure need for it yet.

Synchronous provider client: deeper async provider integration is reserved for workloads where concurrency and streaming actually matter.


🎯 Scope

This project intentionally does not include:

Database
Authentication
Streaming
Redis
File Processing
Embeddings
Vector Search
RAG
Agents
Tool Calling
Production Deployment

Nothing here is accidentally missing.

The project solves its current problem without adding infrastructure for problems it does not have yet.


🏁 Status

Core API              βœ…
LLM Integration       βœ…
Structured Output     βœ…
Validation            βœ…
Error Handling        βœ…
Logging               βœ…
Usage Tracking        βœ…
Cost Estimation       βœ…
Testing               βœ…
CI                    βœ…
Secret Protection     βœ…
Documentation         βœ…
License               βœ…

🟒 Project 01 Complete

The playground started with one simple question:

Can an LLM become a reliable backend dependency instead of just an API call?

This project answers that question with a working, tested, documented service and a clean foundation for everything built on top of it.

Project 01 shipped. βš™οΈπŸ§ πŸ—Ώ

About

πŸ‘‰ A production-oriented FastAPI backend for LLM generation, structured AI output, token usage, cost estimation, and provider error handling.

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages