Skip to main content

OpenAI & Ollama compatible API powered by your ChatGPT account

Project description

GPTMock banner

GPTMock

OpenAI & Ollama compatible API powered by your ChatGPT account.

Tests Coverage Python 3.13+ License: MIT

This is a fork of RayBytes/chatmock. The original Flask + synchronous requests stack has been replaced with FastAPI + async httpx, a layered architecture (router / service / infra), pydantic-settings configuration, and uv as the build system.

Integration and coverage badges are updated from local runs. Refresh both by running scripts/test.sh with GIST_TOKEN available in your environment or .env.

gptmock runs a local server that proxies requests to the ChatGPT Codex backend, exposing an OpenAI/Ollama compatible API. Use GPT-5, GPT-5-Codex, and other models directly from your ChatGPT Plus/Pro subscription — no API key required.

Migration note: --reasoning-compat now defaults to standard, which emits reasoning via delta.reasoning_content / message.reasoning_content instead of injecting <think> tags into content. Set --reasoning-compat think-tags (or GPTMOCK_REASONING_COMPAT=think-tags) to keep the old behavior.

Requirements

  • Python 3.13+
  • Paid ChatGPT account (Plus / Pro / Team / Enterprise)
  • uv (for uvx usage)

Quick Start (uvx)

The fastest way to run gptmock. No clone, no install — just uvx.

1. Login

uvx gptmock login

A browser window will open for ChatGPT OAuth. After login, tokens are saved to ~/.config/gptmock/auth.json.

2. Start the server

uvx gptmock serve

The server starts at http://127.0.0.1:8000. Use http://127.0.0.1:8000/v1 as your OpenAI base URL.

3. Verify

uvx gptmock info

Tip: Shell Alias

alias gptmock='uvx gptmock'

gptmock login
gptmock serve --port 9000
gptmock info

Note: To install directly from the GitHub repository instead of PyPI:

uvx --from "git+https://github.com/rapidrabbit76/GPTMock" gptmock login
uvx --from "git+https://github.com/rapidrabbit76/GPTMock" gptmock serve

Quick Start (Docker)

No build required — pull the pre-built image and run.

1. Create docker-compose.yml

services:
  serve:
    image: rapidrabbit76/gptmock:latest
    container_name: gptmock
    command: ["serve", "--verbose", "--host", "0.0.0.0"]
    ports:
      - "8000:8000"
      - "1455:1455"  # OAuth callback port (needed during first-time login)
    volumes:
      - gptmock-data:/data
    environment:
      - GPTMOCK_HOME=/data
      - GPTMOCK_LOGIN_BIND=0.0.0.0
    healthcheck:
      test: ["CMD-SHELL", "python -c \"import urllib.request,sys; sys.exit(0 if urllib.request.urlopen('http://127.0.0.1:8000/health').status==200 else 1)\""]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 120s  # Allows time for first-time login before health checks begin

volumes:
  gptmock-data:

2. Start (first run — login + serve in one step)

Run the container interactively. If no credentials are found, the login flow starts automatically:

docker compose run --rm --service-ports serve

A URL will be printed in the terminal:

No credentials found. Starting login flow...
Starting local login server on http://localhost:1455
If your browser did not open, navigate to:
  https://auth.openai.com/oauth/authorize?...

If the browser can't reach this machine, paste the full redirect URL here and press Enter:

Two ways to complete login:

  1. Browser on the same machine — the URL opens automatically and the OAuth callback is caught on port 1455.
  2. Browser on a different machine — open the URL, complete login, then copy the full redirect URL from the browser address bar (starts with http://localhost:1455/auth/callback?code=...) and paste it into the terminal.

Once login succeeds, the server starts automatically.

3. Subsequent starts

Once credentials are saved in the volume, just run in the background:

docker compose up -d serve

4. Verify

curl -s http://localhost:8000/health | jq .

Docker Environment Variables

All server options below are also available as environment variables. Use the GPTMOCK_* canonical names (see Server Options).

Additional Docker-specific variables:

Variable Default Description
GPTMOCK_HOME /data Auth file directory — mount a volume here
GPTMOCK_LOGIN_BIND 0.0.0.0 OAuth callback server bind address
GPTMOCK_OLLAMA_VERSION 0.12.10 Ollama API compatibility header version

Usage Examples

Python (OpenAI SDK)

from openai import OpenAI

client = OpenAI(
    base_url="http://127.0.0.1:8000/v1",
    api_key="anything"  # ignored by gptmock
)

resp = client.chat.completions.create(
    model="gpt-5.4",
    messages=[{"role": "user", "content": "hello world"}]
)
print(resp.choices[0].message.content)

Python (LangChain)

from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
    base_url="http://127.0.0.1:8000/v1",
    api_key="anything",
    model="gpt-5.4",
)
response = llm.invoke("hello world")
print(response.content)

curl

curl http://127.0.0.1:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-5.4",
    "messages": [{"role": "user", "content": "hello world"}]
  }'

Image Generation (Responses API)

GPTMock can expose the ChatGPT Codex backend's built-in image generation tool through POST /v1/responses. This uses your existing GPTMock / Codex OAuth credentials; no separate OpenAI API key is required.

Pass an image_generation tool in the Responses API request:

curl http://127.0.0.1:8000/v1/responses \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-5.4",
    "input": [
      {
        "type": "message",
        "role": "user",
        "content": [
          {
            "type": "input_text",
            "text": "Use the image_generation tool to create a cute illustration of a fluffy orange tabby cat sitting on a white background. Return only the generated image."
          }
        ]
      }
    ],
    "tools": [{"type": "image_generation", "output_format": "png"}],
    "tool_choice": "auto",
    "stream": false
  }'

For non-streaming requests, generated images are returned as image_generation_call items in output. The result field is a base64-encoded PNG payload:

{
  "output": [
    {
      "type": "message",
      "status": "completed",
      "role": "assistant",
      "content": [{"type": "output_text", "text": ""}]
    },
    {
      "type": "image_generation_call",
      "id": "ig_...",
      "status": "generating",
      "output_format": "png",
      "revised_prompt": "A cute illustration of a fluffy orange tabby cat...",
      "result": "<base64 png>"
    }
  ]
}

Decode and save the first generated image with Python:

import base64

image_b64 = response["output"][1]["result"]
with open("cat.png", "wb") as fp:
    fp.write(base64.b64decode(image_b64))

You can also run the included live probe script from a checked-out repository:

uv run python scripts/probe_image_generation.py \
  --model gpt-5.4 \
  --prompt "Use the image_generation tool to create a cute cat illustration. Return only the generated image." \
  --output .omx/logs/cat.png

Notes: gpt-5.4 and gpt-5.4-mini have been verified with this flow. The model interprets the request and invokes the built-in tool; the image bytes come back in the image_generation_call.result field. Model availability and image-generation entitlements are controlled by the upstream ChatGPT Codex backend and can vary by account.

Local Image Inspection (view_image)

GPTMock also supports a Codex-compatible view_image client-side tool for POST /v1/responses. Unlike image_generation, this is not executed by the upstream backend: GPTMock reads the local file, returns it to the model as an input_image function-call output, and then continues the Responses turn.

Enable it per request by passing the shorthand tool:

curl http://127.0.0.1:8000/v1/responses \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-5.4-mini",
    "input": [
      {
        "type": "message",
        "role": "user",
        "content": [
          {
            "type": "input_text",
            "text": "Use view_image to inspect this local image path: assets/banner.png. Describe it briefly."
          }
        ]
      }
    ],
    "tools": [{"type": "view_image"}],
    "tool_choice": "auto",
    "stream": false
  }'

The shorthand is normalized to a Responses function tool named view_image. You can also provide an explicit function tool with the same name.

By default, view_image can read files under the server's current working directory only. Configure the readable roots when needed:

GPTMOCK_VIEW_IMAGE_ROOTS="/path/to/images:/another/root" gptmock serve

Additional knobs:

Variable Default Description
GPTMOCK_VIEW_IMAGE_ROOTS server cwd os.pathsep-separated list of readable image roots
GPTMOCK_VIEW_IMAGE_ALLOW_ANY_PATH off Set to 1 to allow any local path readable by the server process
GPTMOCK_VIEW_IMAGE_MAX_BYTES 20971520 Maximum image file size in bytes

Supported image content types are PNG, JPEG, GIF, and WebP. detail: "original" is accepted when the model requests original-resolution handling.


Supported Models

Model Reasoning Efforts Status
gpt-5 minimal / low / medium / high ⚠️ Recognized by GPTMock, currently rejected upstream for ChatGPT Codex accounts
gpt-5.1 low / medium / high ⚠️ Recognized by GPTMock, currently rejected upstream for ChatGPT Codex accounts
gpt-5.2 low / medium / high / xhigh ✅ Verified upstream
gpt-5-codex low / medium / high ⚠️ Recognized by GPTMock, currently rejected upstream for ChatGPT Codex accounts
gpt-5.1-codex low / medium / high ⚠️ Recognized by GPTMock, currently rejected upstream for ChatGPT Codex accounts
gpt-5.1-codex-mini low / medium / high ⚠️ Recognized by GPTMock, currently rejected upstream for ChatGPT Codex accounts
gpt-5.1-codex-max low / medium / high / xhigh ⚠️ Recognized by GPTMock, currently rejected upstream for ChatGPT Codex accounts
gpt-5.2-codex low / medium / high / xhigh ⚠️ Recognized by GPTMock, currently rejected upstream for ChatGPT Codex accounts
gpt-5.3-codex low / medium / high / xhigh ✅ Verified upstream
gpt-5.3-codex-spark low / medium / high / xhigh ✅ Verified upstream
gpt-5.4 low / medium / high / xhigh ✅ Verified upstream
gpt-5.5 low / medium / high / xhigh ⚠️ Recognized by GPTMock, upstream availability depends on account rollout
gpt-5.4-mini low / medium / high / xhigh ✅ Verified upstream
gpt-5.4-fast low / medium / high / xhigh ✅ Supported (priority tier alias of gpt-5.4)
gpt-5.5-fast low / medium / high / xhigh ✅ Supported (priority tier alias of gpt-5.5)
gpt-5.4-mini-fast low / medium / high / xhigh ✅ Supported (priority tier alias of gpt-5.4-mini)

Fast variants (*-fast) are synthetic aliases that map to the base model plus service_tier="priority" in the upstream payload. No separate endpoint or auth is required — the ChatGPT backend accepts them as paid-tier priority requests.

Upstream availability note: model availability can change independently of GPTMock releases. GPTMock may recognize a model ID even when the current ChatGPT Codex backend rejects it for a specific account or subscription. On 2026-04-17, direct probe requests against the current upstream accepted gpt-5.2, gpt-5.3-codex, gpt-5.3-codex-spark, gpt-5.4, and gpt-5.4-mini, while rejecting gpt-5, gpt-5.1, gpt-5-codex, gpt-5.1-codex, gpt-5.1-codex-mini, gpt-5.1-codex-max, and gpt-5.2-codex with: The '<model>' model is not supported when using Codex with a ChatGPT account.

Deprecated / Unsupported Models

None hardcoded in GPTMock at this time. See the upstream availability note above for models that are currently rejected by the ChatGPT Codex backend.

API Endpoints

Method Path Description
POST /v1/chat/completions OpenAI Chat Completions (stream / non-stream)
POST /v1/completions OpenAI Text Completions
POST /v1/responses OpenAI Responses API (for LangChain codex routing)
GET /v1/models List available models
GET /api/version Ollama-compatible version info
POST /api/chat Ollama-compatible chat
POST /api/show Ollama-compatible model details
GET /api/tags Ollama model list
GET /health Health check

Features

  • Streaming & Non-streaming — real-time SSE and buffered JSON responses
  • Structured Outputresponse_format with json_schema / json_object support
  • Tool / Function Calling — including web search with URL citation annotations via responses_tools
  • Image Generation — Responses API image_generation tool support with base64 PNG output
  • Local Image Inspection — Codex-compatible view_image function tool for allowed local image paths
  • Thinking Summaries<think> tags, o3 reasoning format, or legacy mode
  • Responses APIPOST /v1/responses for LangChain and other clients that auto-route codex models
  • Ollama Compatibility — drop-in replacement for Ollama API consumers
  • Auto Token Refresh — JWT tokens are refreshed automatically before expiry

Server Options

gptmock serve [OPTIONS]

Each option can also be set via environment variable. Precedence: CLI flag > GPTMOCK_* env > CHATGPT_LOCAL_* legacy env > default.

Option Env var Default Description
--host GPTMOCK_HOST 127.0.0.1 Bind address
--port GPTMOCK_PORT 8000 Bind port
--verbose GPTMOCK_VERBOSE off Log request/response payloads
--verbose-obfuscation GPTMOCK_VERBOSE_OBFUSCATION off Also dump raw SSE/obfuscation events
--debug-model GPTMOCK_DEBUG_MODEL Force all requests to use this model name
--reasoning-effort GPTMOCK_REASONING_EFFORT medium minimal / low / medium / high / xhigh
--reasoning-summary GPTMOCK_REASONING_SUMMARY auto auto / concise / detailed / none
--reasoning-compat GPTMOCK_REASONING_COMPAT standard How reasoning is exposed: standard / think-tags / o3 / legacy (openai is accepted as an alias for standard, current as an alias for legacy)
--expose-reasoning-models GPTMOCK_EXPOSE_REASONING_MODELS off Show effort variants as separate models in /v1/models
--enable-web-search GPTMOCK_DEFAULT_WEB_SEARCH off Enable web search by default when responses_tools is omitted
--cors-origins GPTMOCK_CORS_ORIGINS * Comma-separated allowed CORS origins

Legacy aliases: CHATGPT_LOCAL_REASONING_EFFORT, CHATGPT_LOCAL_REASONING_SUMMARY, CHATGPT_LOCAL_REASONING_COMPAT, CHATGPT_LOCAL_EXPOSE_REASONING_MODELS, CHATGPT_LOCAL_ENABLE_WEB_SEARCH, CHATGPT_LOCAL_DEBUG_MODEL are still accepted as fallbacks.


Web Search

Use --enable-web-search to enable the web search tool by default for all requests. When enabled, the model decides autonomously whether a query needs a web search. You can also enable web search per-request without the server flag by passing the parameters below.

Request Parameters

Parameter Values Description
responses_tools [{"type":"web_search"}] Enable web search for this request
responses_tool_choice "auto" / "none" Let the model decide, or disable

Annotations (URL Citations)

When web search is active, the model may return annotations containing source URLs. These are included automatically in responses:

Non-streaming (stream: false) — annotations are attached to the message:

{
  "choices": [
    {
      "message": {
        "role": "assistant",
        "content": "SpaceX launched 29 Starlink satellites...",
        "annotations": [
          {
            "type": "url_citation",
            "start_index": 0,
            "end_index": 150,
            "url": "https://spaceflightnow.com/...",
            "title": "SpaceX Falcon 9 launch"
          }
        ]
      }
    }
  ]
}

Streaming (stream: true) — annotations arrive as a dedicated chunk before the final stop chunk:

data: {"choices": [{"delta": {"annotations": [{"type": "url_citation", "start_index": 0, "end_index": 150, "url": "https://...", "title": "..."}]}, "finish_reason": null}]}
data: {"choices": [{"delta": {}, "finish_reason": "stop"}]}

Responses API (POST /v1/responses, non-streaming) — annotations are nested inside the output content:

{
  "output": [
    {
      "type": "message",
      "role": "assistant",
      "content": [
        {
          "type": "output_text",
          "text": "SpaceX launched 29 Starlink satellites...",
          "annotations": [
            {
              "type": "url_citation",
              "start_index": 0,
              "end_index": 150,
              "url": "https://spaceflightnow.com/...",
              "title": "SpaceX Falcon 9 launch"
            }
          ]
        }
      ]
    }
  ]
}

Example Request

curl http://127.0.0.1:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-5",
    "messages": [{"role":"user","content":"Find current METAR rules"}],
    "stream": true,
    "responses_tools": [{"type": "web_search"}],
    "responses_tool_choice": "auto"
  }'

Notes & Limits

  • Requires an active, paid ChatGPT account.
  • Context length may be partially used by internal system instructions.
  • For the fastest responses, set --reasoning-effort to low and --reasoning-summary to none.
  • The context size of this route is larger than what you get in the regular ChatGPT app.
  • When the model returns a thinking summary, the default standard mode emits reasoning_content fields without polluting content. Set --reasoning-compat think-tags to keep <think> tags for older chat apps, or --reasoning-compat legacy for the older reasoning fields.
  • This project is not affiliated with OpenAI. Use responsibly and at your own risk.

Credits

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

gptmock-2026.4.28.tar.gz (5.8 MB view details)

Uploaded Source

Built Distribution

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

gptmock-2026.4.28-py3-none-any.whl (77.4 kB view details)

Uploaded Python 3

File details

Details for the file gptmock-2026.4.28.tar.gz.

File metadata

  • Download URL: gptmock-2026.4.28.tar.gz
  • Upload date:
  • Size: 5.8 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for gptmock-2026.4.28.tar.gz
Algorithm Hash digest
SHA256 f7b3874bf58ed61ef17c879ddd63a75f6f6f183509925e34457e37360705ebc2
MD5 5bdd6683d51f8aadb28f55229e916825
BLAKE2b-256 be50797f80f2c34eb546050238ec35bb08c72faacb0dfb4b5a63c2e5c39a3caa

See more details on using hashes here.

Provenance

The following attestation bundles were made for gptmock-2026.4.28.tar.gz:

Publisher: pypi-publish.yml on rapidrabbit76/GPTMock

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

File details

Details for the file gptmock-2026.4.28-py3-none-any.whl.

File metadata

  • Download URL: gptmock-2026.4.28-py3-none-any.whl
  • Upload date:
  • Size: 77.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for gptmock-2026.4.28-py3-none-any.whl
Algorithm Hash digest
SHA256 ea41d8b2097f9a1ea5bf5363d99daba3e49b91f57ca5393d0707488ccad4e609
MD5 53caeb9dd190407583896aef6f1d078d
BLAKE2b-256 b2b6c9b0e0e6ebe3d8fc3862e4f79307970769dc9f6f049e94d5d7b4ebff43c1

See more details on using hashes here.

Provenance

The following attestation bundles were made for gptmock-2026.4.28-py3-none-any.whl:

Publisher: pypi-publish.yml on rapidrabbit76/GPTMock

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