Skip to main content

A proxy layer for OpenAI-compatible APIs with pre/post-processing hooks

Project description

API Model Proxy

A lightweight, extensible proxy layer for OpenAI-compatible APIs. Drop it between your application and any OpenAI-compatible backend to intercept, log, modify, or filter requests and responses — without changing your existing client code.

Python License GitHub

Features

  • OpenAI-compatible — works as a drop-in with any openai.OpenAI client by setting base_url
  • Hook-based — override _preprocess_request and _postprocess_response to customise behaviour
  • Full API coverage — proxies all inference endpoints (chat, completions, responses, embeddings, audio, images, moderations) with hooks; all other endpoints (models, files, fine-tuning, batches, vector stores, etc.) are forwarded transparently
  • Error visibility_postprocess_response is called on both success and error responses, allowing subclasses to inspect or modify errors
  • FastAPI + uvicorn — async, production-ready server with auto-generated docs at /docs

Use Cases

Use case Approach
Request/response logging Override both hooks to log to stdout, a file, or an external service
Model gating / filtering Raise in _preprocess_request to block disallowed models or prompt patterns
Response caching Cache response dicts in _postprocess_response and serve from _preprocess_request
Rate limiting / usage tracking Track request counts or token usage per user in _postprocess_response
Prompt augmentation Inject system messages or rewrite user messages in _preprocess_request
A/B testing Route requests to different model versions conditionally in _preprocess_request

Installation

pip install api-model-proxy

Quick Start

1. Deploy the proxy

from openai import OpenAI
from api_model_proxy import APIModelProxy

class LoggingProxy(APIModelProxy):
    def _preprocess_request(self, request):
        print(f"Request: {request}")
        return request

    def _postprocess_response(self, response):
        print(f"Response: {response}")
        return response

client = OpenAI(
    api_key="your-api-key",
    base_url="https://api.openai.com/v1",  # or any OpenAI-compatible endpoint
)
proxy = LoggingProxy(client)
proxy.deploy(host="localhost", port=8000)

2. Point your client at the proxy

from openai import OpenAI

client = OpenAI(base_url="http://localhost:8000", api_key="EMPTY")
response = client.chat.completions.create(
    model="gpt-4o",
    messages=[{"role": "user", "content": "Hello, world!"}]
)
print(response.choices[0].message.content)

No other changes needed — the proxy is fully transparent to the client.

Deployment

Docker

FROM python:3.12-slim

WORKDIR /app
COPY . .
RUN pip install --no-cache-dir -e .

CMD ["python", "-c", "
from openai import OpenAI
from api_model_proxy import APIModelProxy

class LoggingProxy(APIModelProxy):
    def _preprocess_request(self, request):
        print(f'Request: {request}')
        return request
    def _postprocess_response(self, response):
        print(f'Response: {response}')
        return response

client = OpenAI(api_key='your-api-key', base_url='https://api.openai.com/v1')
LoggingProxy(client).deploy(host='0.0.0.0', port=8000)
"]

docker-compose

version: "3.9"
services:
  proxy:
    build: .
    ports:
      - "8000:8000"
    environment:
      - OPENAI_API_KEY=${OPENAI_API_KEY:?required}

Run with:

OPENAI_API_KEY=sk-... docker compose up

Customisation

Subclass APIModelProxy and override either or both hooks:

Method Called on Default behaviour
_preprocess_request(request: dict) -> dict Every inference request, before forwarding No-op (return as-is)
_postprocess_response(response: dict) -> dict Every inference response (success and error) No-op (return as-is)

Example: request filtering

class FilterProxy(APIModelProxy):
    _BLOCKED = {"gpt-4o", "gpt-4-turbo"}

    def _preprocess_request(self, request):
        if request.get("model") in self._BLOCKED:
            raise ValueError(f"Model {request['model']} is not allowed.")
        return request

Example: response caching

import hashlib, json

class CachingProxy(APIModelProxy):
    def __init__(self, client):
        super().__init__(client)
        self._cache = {}
        self._last_key = None

    def _preprocess_request(self, request):
        self._last_key = hashlib.sha256(json.dumps(request, sort_keys=True).encode()).hexdigest()
        return request

    def _postprocess_response(self, response):
        if self._last_key:
            self._cache[self._last_key] = response
        return response

More examples

See the examples/ directory for ready-to-use proxy implementations:

Endpoints

Inference (hooks fire)

Method Path
POST /chat/completions
POST /completions
POST /responses
POST /embeddings
POST /audio/transcriptions
POST /audio/translations
POST /audio/speech
POST /images/generations
POST /images/edits
POST /images/variations
POST /moderations

All paths are also available with a /v1/ prefix.

Passthrough (no hooks, forwarded verbatim)

All other endpoints — models, files, fine-tuning, batches, vector stores, evals, organisation admin, and any future OpenAI endpoints — are forwarded transparently using the upstream client's base URL and API key.

Streaming

Streaming (stream=True) is not yet supported. Requests with stream=True will receive a 501 Not Implemented response. Streaming support is planned for the next version.

Running Tests

The test suite uses pytest. Install the development dependencies and run:

pip install pytest pytest-mock
pytest tests/ -v

The tests use a mocked OpenAI client so no API key or network access is required.

Project Structure

src/api_model_proxy/
├── __init__.py          # exports APIModelProxy
├── proxy.py             # APIModelProxy base class
├── server.py            # FastAPI app factory
└── routes/
    ├── chat.py          # POST /chat/completions
    ├── completions.py   # POST /completions
    ├── responses.py     # POST /responses
    ├── embeddings.py    # POST /embeddings
    ├── audio.py         # POST /audio/*
    ├── images.py        # POST /images/*
    ├── moderations.py   # POST /moderations
    └── passthrough.py   # catch-all transparent proxy

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

api_model_proxy-0.1.2.tar.gz (16.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

api_model_proxy-0.1.2-py3-none-any.whl (15.9 kB view details)

Uploaded Python 3

File details

Details for the file api_model_proxy-0.1.2.tar.gz.

File metadata

  • Download URL: api_model_proxy-0.1.2.tar.gz
  • Upload date:
  • Size: 16.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for api_model_proxy-0.1.2.tar.gz
Algorithm Hash digest
SHA256 f2d0018d60416ea7f351b7c1ba8c4f4309f8b4a1607c1d0c866e416bd825ae6d
MD5 57c7a5919a0d26c6217d4cf6b3518a5a
BLAKE2b-256 f40e9c49c08472dfab61ce9c0f2ff955e3b8141e7862b304dd32809c91d80de3

See more details on using hashes here.

Provenance

The following attestation bundles were made for api_model_proxy-0.1.2.tar.gz:

Publisher: python-publish.yml on panuthept/api-model-proxy

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file api_model_proxy-0.1.2-py3-none-any.whl.

File metadata

File hashes

Hashes for api_model_proxy-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 d0fd818790f70d2f52c38efba58a425c8996b9d8e6fbe81ac63716dd46a1d7f3
MD5 75125fe1bd6e3777f94b2f175f59851b
BLAKE2b-256 9658a894ff9b9b47e00d700ab43f1c3909054270226de9d9675a7dffbaf8f311

See more details on using hashes here.

Provenance

The following attestation bundles were made for api_model_proxy-0.1.2-py3-none-any.whl:

Publisher: python-publish.yml on panuthept/api-model-proxy

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page