Skip to content

Commit 8754203

Browse files
committed
feat: add responses api, websocket support, and fast mode
1 parent e96db19 commit 8754203

22 files changed

Lines changed: 2146 additions & 117 deletions

DOCKER.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ Set options in `.env` or pass environment variables:
2424
- `CHATGPT_LOCAL_REASONING_EFFORT`: minimal|low|medium|high|xhigh
2525
- `CHATGPT_LOCAL_REASONING_SUMMARY`: auto|concise|detailed|none
2626
- `CHATGPT_LOCAL_REASONING_COMPAT`: legacy|o3|think-tags|current
27+
- `CHATGPT_LOCAL_FAST_MODE`: `true|false` to enable fast mode by default for supported models
2728
- `CHATGPT_LOCAL_DEBUG_MODEL`: force model override (e.g., `gpt-5.4`)
2829
- `CHATGPT_LOCAL_CLIENT_ID`: OAuth client id override (rarely needed)
2930
- `CHATGPT_LOCAL_EXPOSE_REASONING_MODELS`: `true|false` to add reasoning model variants to `/v1/models`

README.md

Lines changed: 90 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1,172 +1,175 @@
11
<div align="center">
2-
<h1>ChatMock
3-
<div align="center">
4-
<a href="https://github.com/RayBytes/ChatMock/stargazers"><img src="https://img.shields.io/github/stars/RayBytes/ChatMock" alt="Stars Badge"/></a>
5-
<a href="https://github.com/RayBytes/ChatMock/network/members"><img src="https://img.shields.io/github/forks/RayBytes/ChatMock" alt="Forks Badge"/></a>
6-
<a href="https://github.com/RayBytes/ChatMock/pulls"><img src="https://img.shields.io/github/issues-pr/RayBytes/ChatMock" alt="Pull Requests Badge"/></a>
7-
<a href="https://github.com/RayBytes/ChatMock/issues"><img src="https://img.shields.io/github/issues/RayBytes/ChatMock" alt="Issues Badge"/></a>
8-
<a href="https://github.com/RayBytes/ChatMock/graphs/contributors"><img alt="GitHub contributors" src="https://img.shields.io/github/contributors/RayBytes/ChatMock?color=2b9348"></a>
9-
<a href="https://github.com/RayBytes/ChatMock/blob/master/LICENSE"><img src="https://img.shields.io/github/license/RayBytes/ChatMock?color=2b9348" alt="License Badge"/></a>
10-
</div>
11-
</h1>
12-
13-
<p><b>OpenAI & Ollama compatible API powered by your ChatGPT plan.</b></p>
14-
<p>Use your ChatGPT Plus/Pro account to call OpenAI models from code or alternate chat UIs.</p>
15-
<br>
16-
</div>
172

18-
## What It Does
3+
# ChatMock
4+
5+
**Allows Codex to work in your favourite chat apps and coding tools.**
6+
7+
[![PyPI](https://img.shields.io/pypi/v/chatmock?color=blue&label=pypi)](https://pypi.org/project/chatmock/)
8+
[![Python](https://img.shields.io/pypi/pyversions/chatmock)](https://pypi.org/project/chatmock/)
9+
[![License](https://img.shields.io/github/license/RayBytes/ChatMock)](LICENSE)
10+
[![Stars](https://img.shields.io/github/stars/RayBytes/ChatMock?style=flat)](https://github.com/RayBytes/ChatMock/stargazers)
11+
[![Last Commit](https://img.shields.io/github/last-commit/RayBytes/ChatMock)](https://github.com/RayBytes/ChatMock/commits/main)
12+
[![Issues](https://img.shields.io/github/issues/RayBytes/ChatMock)](https://github.com/RayBytes/ChatMock/issues)
1913

20-
ChatMock runs a local server that creates an OpenAI/Ollama compatible API, and requests are then fulfilled using your authenticated ChatGPT login with the oauth client of Codex, OpenAI's coding CLI tool. This allows you to use GPT-5, GPT-5-Codex, and other models right through your OpenAI account, without requiring an api key. You are then able to use it in other chat apps or other coding tools. <br>
21-
This does require a paid ChatGPT account.
14+
<br>
15+
16+
17+
</div>
2218

23-
## Quickstart
19+
<br>
2420

25-
### Homebrew
21+
## Install
2622

23+
#### Homebrew
2724
```bash
2825
brew tap RayBytes/chatmock
2926
brew install chatmock
3027
```
3128

32-
### CLI
33-
29+
#### pipx / pip
3430
```bash
3531
pipx install chatmock
3632
```
3733

38-
### GUI
34+
#### GUI
35+
Download from [releases](https://github.com/RayBytes/ChatMock/releases) (macOS & Windows)
3936

40-
If you're on **macOS** or **Windows**, you can download the GUI app from the [GitHub releases](https://github.com/RayBytes/ChatMock/releases).
37+
#### Docker
38+
See [DOCKER.md](DOCKER.md)
4139

42-
### Python
43-
If you wish to just simply run this as a python flask server, you are also freely welcome too.
40+
<br>
4441

45-
Clone or download this repository, then cd into the project directory. Then follow the instrunctions listed below.
42+
## Getting Started
4643

47-
1. Sign in with your ChatGPT account and follow the prompts
4844
```bash
49-
python chatmock.py login
50-
```
51-
You can make sure this worked by running `python chatmock.py info`
52-
53-
2. After the login completes successfully, you can just simply start the local server
45+
# 1. Sign in with your ChatGPT account
46+
chatmock login
5447

55-
```bash
56-
python chatmock.py serve
48+
# 2. Start the server
49+
chatmock serve
5750
```
58-
Then, you can simply use the address and port as the baseURL as you require (http://127.0.0.1:8000 by default)
59-
60-
**Reminder:** When setting a baseURL in other applications, make you sure you include /v1/ at the end of the URL if you're using this as a OpenAI compatible endpoint (e.g http://127.0.0.1:8000/v1)
6151

62-
### Docker
52+
The server runs at `http://127.0.0.1:8000` by default. Use `http://127.0.0.1:8000/v1` as your base URL for OpenAI-compatible apps.
6353

64-
Read [the docker instrunctions here](https://github.com/RayBytes/ChatMock/blob/main/DOCKER.md)
54+
<br>
6555

66-
# Examples
56+
## Usage
6757

68-
### Python
58+
<details open>
59+
<summary><b>Python</b></summary>
6960

7061
```python
7162
from openai import OpenAI
7263

7364
client = OpenAI(
7465
base_url="http://127.0.0.1:8000/v1",
75-
api_key="key" # ignored
66+
api_key="anything" # not checked
7667
)
7768

78-
resp = client.chat.completions.create(
69+
response = client.chat.completions.create(
7970
model="gpt-5.4",
80-
messages=[{"role": "user", "content": "hello world"}]
71+
messages=[{"role": "user", "content": "hello"}]
8172
)
82-
83-
print(resp.choices[0].message.content)
73+
print(response.choices[0].message.content)
8474
```
8575

86-
### curl
76+
</details>
77+
78+
<details>
79+
<summary><b>cURL</b></summary>
8780

8881
```bash
8982
curl http://127.0.0.1:8000/v1/chat/completions \
90-
-H "Authorization: Bearer key" \
9183
-H "Content-Type: application/json" \
9284
-d '{
9385
"model": "gpt-5.4",
94-
"messages": [{"role":"user","content":"hello world"}]
86+
"messages": [{"role": "user", "content": "hello"}]
9587
}'
9688
```
9789

98-
# What's supported
99-
100-
- Tool/Function calling
101-
- Vision/Image understanding
102-
- Thinking summaries (through thinking tags)
103-
- Thinking effort
90+
</details>
10491

105-
## Notes & Limits
92+
<br>
10693

107-
- Requires an active, paid ChatGPT account.
108-
- Some context length might be taken up by internal instructions (but they dont seem to degrade the model)
109-
- Use responsibly and at your own risk. This project is not affiliated with OpenAI, and is a educational exercise.
94+
## Supported Models
11095

111-
# Supported models
11296
- `gpt-5.4`
11397
- `gpt-5.4-mini`
11498
- `gpt-5.2`
11599
- `gpt-5.1`
116100
- `gpt-5`
117101
- `gpt-5.3-codex`
118-
- `gpt-5-codex`
102+
- `gpt-5.3-codex-spark`
119103
- `gpt-5.2-codex`
104+
- `gpt-5-codex`
120105
- `gpt-5.1-codex`
121106
- `gpt-5.1-codex-max`
122107
- `gpt-5.1-codex-mini`
123108
- `codex-mini`
124109

125-
# Customisation / Configuration
110+
<br>
126111

127-
### Thinking effort
112+
## Features
128113

129-
- `--reasoning-effort` (choice of none,minimal,low,medium,high,xhigh)<br>
130-
GPT-5 has a configurable amount of "effort" it can put into thinking, which may cause it to take more time for a response to return, but may overall give a smarter answer. Applying this parameter after `serve` forces the server to use this reasoning effort by default, unless overrided by the API request with a different effort set. The default reasoning effort without setting this parameter is `medium`.<br>
131-
The `gpt-5.1` family (including codex) supports `low`, `medium`, and `high` while `gpt-5.1-codex-max` adds `xhigh`. The `gpt-5.2` and `gpt-5.3` families (including codex) support `low`, `medium`, `high`, and `xhigh`. `gpt-5.4` supports `none`, `low`, `medium`, `high`, and `xhigh`.
114+
- Tool / function calling
115+
- Vision / image input
116+
- Thinking summaries (via think tags)
117+
- Configurable thinking effort
118+
- Fast mode for supported models
119+
- Web search tool
120+
- OpenAI-compatible `/v1/responses` (HTTP + WebSocket)
121+
- Ollama-compatible endpoints
122+
- Reasoning effort exposed as separate models (optional)
132123

133-
### Thinking summaries
124+
<br>
134125

135-
- `--reasoning-summary` (choice of auto,concise,detailed,none)<br>
136-
Models like GPT-5 do not return raw thinking content, but instead return thinking summaries. These can also be customised by you.
126+
## Configuration
137127

138-
### OpenAI Tools
128+
All flags go after `chatmock serve`. These can also be set as environment variables.
139129

140-
- `--enable-web-search`<br>
141-
You can also access OpenAI tools through this project. Currently, only web search is available.
142-
You can enable it by starting the server with this parameter, which will allow OpenAI to determine when a request requires a web search, or you can use the following parameters during a request to the API to enable web search:
143-
<br><br>
144-
`responses_tools`: supports `[{"type":"web_search"}]` / `{ "type": "web_search_preview" }`<br>
145-
`responses_tool_choice`: `"auto"` or `"none"`
130+
| Flag | Env var | Options | Default | Description |
131+
|------|---------|---------|---------|-------------|
132+
| `--reasoning-effort` | `CHATGPT_LOCAL_REASONING_EFFORT` | none, minimal, low, medium, high, xhigh | medium | How hard the model thinks |
133+
| `--reasoning-summary` | `CHATGPT_LOCAL_REASONING_SUMMARY` | auto, concise, detailed, none | auto | Thinking summary verbosity |
134+
| `--reasoning-compat` | `CHATGPT_LOCAL_REASONING_COMPAT` | legacy, o3, think-tags | think-tags | How reasoning is returned to the client |
135+
| `--fast-mode` | `CHATGPT_LOCAL_FAST_MODE` | true/false | false | Priority processing for supported models |
136+
| `--enable-web-search` | `CHATGPT_LOCAL_ENABLE_WEB_SEARCH` | true/false | false | Allow the model to search the web |
137+
| `--expose-reasoning-models` | `CHATGPT_LOCAL_EXPOSE_REASONING_MODELS` | true/false | false | List each reasoning level as its own model |
138+
139+
<details>
140+
<summary><b>Web search in a request</b></summary>
146141

147-
#### Example usage
148142
```json
149143
{
150144
"model": "gpt-5.4",
151-
"messages": [{"role":"user","content":"Find current METAR rules"}],
152-
"stream": true,
145+
"messages": [{"role": "user", "content": "latest news on ..."}],
153146
"responses_tools": [{"type": "web_search"}],
154147
"responses_tool_choice": "auto"
155148
}
156149
```
157150

158-
### Expose reasoning models
151+
</details>
152+
153+
<details>
154+
<summary><b>Fast mode in a request</b></summary>
155+
156+
```json
157+
{
158+
"model": "gpt-5.4",
159+
"input": "summarize this",
160+
"fast_mode": true
161+
}
162+
```
163+
164+
</details>
159165

160-
- `--expose-reasoning-models`<br>
161-
If your preferred app doesn’t support selecting reasoning effort, or you just want a simpler approach, this parameter exposes each reasoning level as a separate, queryable model. Each reasoning level also appears individually under ⁠/v1/models, so model pickers in your favorite chat apps will list all reasoning options as distinct models you can switch between.
166+
<br>
162167

163168
## Notes
164-
If you wish to have the fastest responses, I'd recommend setting `--reasoning-effort` to low, and `--reasoning-summary` to none. <br>
165-
All parameters and choices can be seen by sending `python chatmock.py serve --h`<br>
166-
The context size of this route is also larger than what you get access to in the regular ChatGPT app.<br>
167169

168-
When the model returns a thinking summary, the model will send back thinking tags to make it compatible with chat apps. **If you don't like this behavior, you can instead set `--reasoning-compat` to legacy, and reasoning will be set in the reasoning tag instead of being returned in the actual response text.**
170+
Use responsibly and at your own risk. This project is not affiliated with OpenAI.
169171

172+
<br>
170173

171174
## Star History
172175

chatmock/app.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
from __future__ import annotations
22

33
from flask import Flask, jsonify
4+
from flask_sock import Sock
45

56
from .config import BASE_INSTRUCTIONS, GPT5_CODEX_INSTRUCTIONS
67
from .http import build_cors_headers
78
from .routes_openai import openai_bp
89
from .routes_ollama import ollama_bp
10+
from .websocket_routes import register_websocket_routes
911

1012

1113
def create_app(
@@ -14,6 +16,7 @@ def create_app(
1416
reasoning_effort: str = "medium",
1517
reasoning_summary: str = "auto",
1618
reasoning_compat: str = "think-tags",
19+
fast_mode: bool = False,
1720
debug_model: str | None = None,
1821
expose_reasoning_models: bool = False,
1922
default_web_search: bool = False,
@@ -26,6 +29,7 @@ def create_app(
2629
REASONING_EFFORT=reasoning_effort,
2730
REASONING_SUMMARY=reasoning_summary,
2831
REASONING_COMPAT=reasoning_compat,
32+
FAST_MODE=bool(fast_mode),
2933
DEBUG_MODEL=debug_model,
3034
BASE_INSTRUCTIONS=BASE_INSTRUCTIONS,
3135
GPT5_CODEX_INSTRUCTIONS=GPT5_CODEX_INSTRUCTIONS,
@@ -46,5 +50,7 @@ def _cors(resp):
4650

4751
app.register_blueprint(openai_bp)
4852
app.register_blueprint(ollama_bp)
53+
sock = Sock(app)
54+
register_websocket_routes(sock)
4955

5056
return app

chatmock/cli.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,7 @@ def cmd_serve(
267267
reasoning_effort: str,
268268
reasoning_summary: str,
269269
reasoning_compat: str,
270+
fast_mode: bool,
270271
debug_model: str | None,
271272
expose_reasoning_models: bool,
272273
default_web_search: bool,
@@ -277,6 +278,7 @@ def cmd_serve(
277278
reasoning_effort=reasoning_effort,
278279
reasoning_summary=reasoning_summary,
279280
reasoning_compat=reasoning_compat,
281+
fast_mode=fast_mode,
280282
debug_model=debug_model,
281283
expose_reasoning_models=expose_reasoning_models,
282284
default_web_search=default_web_search,
@@ -309,6 +311,12 @@ def main() -> None:
309311
default=os.getenv("CHATGPT_LOCAL_DEBUG_MODEL"),
310312
help="Forcibly override requested 'model' with this value",
311313
)
314+
p_serve.add_argument(
315+
"--fast-mode",
316+
action=argparse.BooleanOptionalAction,
317+
default=(os.getenv("CHATGPT_LOCAL_FAST_MODE") or "").strip().lower() in ("1", "true", "yes", "on"),
318+
help="Enable GPT fast mode by default for supported models; request-level overrides still take precedence.",
319+
)
312320
p_serve.add_argument(
313321
"--reasoning-effort",
314322
choices=["none", "minimal", "low", "medium", "high", "xhigh"],
@@ -366,6 +374,7 @@ def main() -> None:
366374
reasoning_effort=args.reasoning_effort,
367375
reasoning_summary=args.reasoning_summary,
368376
reasoning_compat=args.reasoning_compat,
377+
fast_mode=args.fast_mode,
369378
debug_model=args.debug_model,
370379
expose_reasoning_models=args.expose_reasoning_models,
371380
default_web_search=args.enable_web_search,

0 commit comments

Comments
 (0)