OpenAI v1 API compatible HTTP service with pluggable inference backends. Built with FastAPI and supports streaming responses, request queueing, and OpenTelemetry metrics.
- ✅ OpenAI v1 API compatibility (Models, Chat Completions, Completions, Embeddings)
- ✅ Server-Sent Events (SSE) streaming support
- ✅ Request queue with GPU serialization (prevents concurrent GPU access)
- ✅ TOML + environment variable configuration
- ✅ Structured JSON logging with request IDs
- ✅ OpenTelemetry metrics (Prometheus endpoint)
- ✅ Mock backend for testing (1536-dim embeddings, streaming chat, tool calls)
- ✅ Transformers backend example (
examples/transformers-backend/— uses Qwen3.5-0.8B) - ✅ Custom backend SDK (
BackendBaseABC,run_server()entry point) - 🚧 Audio (speech, transcriptions, translations) endpoints
- 🚧 Image generation / editing endpoints
- ✅ Tool calling (function definitions in chat) — supported in transformers backend
- Python 3.12+ (see
.python-version) - uv package manager
# Clone and enter directory
git clone <repo>
cd openai-http
# Create venv and install dependencies
uv sync --all-extras# Start with mock backend (no GPU required)
uv run -m openai_http
# Server runs on http://0.0.0.0:8000# List models
curl http://localhost:8000/v1/models
# Chat completion (non-streaming)
curl -X POST http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "mock-gpt",
"messages": [{"role": "user", "content": "Hello"}]
}'
# Chat completion (streaming)
curl -X POST http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "mock-gpt",
"messages": [{"role": "user", "content": "Hello"}],
"stream": true
}'
# Health check
curl http://localhost:8000/health# Install heavy deps (not included in default install)
uv pip install torch transformers accelerate
# Start with Qwen3.5-0.8B (downloads ~1.6 GB on first run)
uv run python examples/transformers-backend/transformers_backend.py
# Customize model, temperature, or enable thinking mode
uv run python examples/transformers-backend/transformers_backend.py \
--model Qwen/Qwen2.5-0.5B-Instruct \
--temperature 0.7 \
--thinking \
--port 8000See examples/transformers-backend/README.md for details.
Configuration uses config.toml with environment variable overrides.
[server]
host = "0.0.0.0"
port = 8000
[auth]
enabled = false
api_keys = [] # ["sk-..."] when enabled
[queue]
depth = 32 # max queued requests
[observability]
log_level = "info"
log_format = "json" # "json" or "text"Override any config with OPENAI_HTTP__ prefix (double underscore for nesting):
OPENAI_HTTP__SERVER__PORT=9000
OPENAI_HTTP__AUTH__ENABLED=true
OPENAI_HTTP__AUTH__API_KEYS=["sk-test-key"]GET /v1/models— List available modelsGET /v1/models/{model_id}— Get model infoPOST /v1/chat/completions— Chat completion (streaming + non-streaming)POST /v1/completions— Text completionPOST /v1/embeddings— Text embeddingsGET /health— Health check
# All tests
uv run pytest tests/ -v
# SDK tests only (auto-starts server)
uv run pytest tests/sdk/ -v
# Unit tests only
uv run pytest tests/unit/ -v
# Single test
uv run pytest tests/sdk/test_models.py::TestModelsAPI::test_models_list -vNote: SDK tests (tests/sdk/) automatically start a mock server on port 8000 in a background thread. Don't start the server manually before running tests.
uv run ruff check openai_http/ tests/
uv run mypy openai_http/openai_http/
├── __init__.py # Public API: BackendBase, run_server, setup_logging
├── _server.py # run_server() entry point (library mode)
├── app.py # FastAPI factory, lifespan, middleware
├── config.py # pydantic-settings configuration
├── errors.py # OpenAI-format error handlers
├── queue.py # Request queue (asyncio.Semaphore)
├── routers/ # API endpoints
│ ├── chat.py # /v1/chat/completions
│ ├── completions.py # /v1/completions
│ ├── embeddings.py # /v1/embeddings
│ ├── models.py # /v1/models
│ ├── audio.py # /v1/audio/* (stub)
│ ├── images.py # /v1/images/* (stub)
│ └── health.py # /health
├── schemas/ # Pydantic v2 models
├── backends/ # Inference backends
│ ├── base.py # BackendBase ABC
│ └── mock_backend.py # Mock implementation
└── observability/ # Logging + metrics
examples/
└── transformers-backend/ # Real Transformers backend using Qwen2.5-0.5B
tests/
├── conftest.py # Async httpx fixtures
├── unit/ # Unit tests
└── sdk/ # OpenAI SDK compatibility tests
└── conftest.py # Sync OpenAI client fixtures
config.toml # Configuration
specs/ # Feature specs & plans
- Request arrives at FastAPI router
RequestIDMiddlewareassigns unique request IDRequestLoggingMiddlewarelogs request metadata- Router calls
queue.acquire()(waits if GPU busy) - Backend executes inference (mock or transformers)
- Response formatted to OpenAI v1 schema
- Error handlers catch exceptions and format
{"error": {...}}
See .opencode/skills/custom-backend/SKILL.md for a full example.
GPU inference is serialized using asyncio.Semaphore(1) to prevent out-of-memory errors. When the queue reaches queue.depth, new requests receive HTTP 429 (Too Many Requests).
- Unit tests (
tests/unit/): Test individual functions/classes in isolation - Integration tests (
tests/integration/): Test endpoint behavior with httpx - Contract tests (
tests/contract/): Verify OpenAI API contract compliance - SDK tests (
tests/sdk/): Use officialopenaiPython SDK against running server
Unimplemented endpoints use pytest.skip() via _call_or_skip() helper and auto-activate when routes are added.
MIT
See specs/001-openai-http-api/plan.md for implementation roadmap and AGENTS.md for development guidelines.