WackyDawg/free-gpt-api
GitHub: WackyDawg/free-gpt-api
一个基于 Node.js 和 Puppeteer 的代理服务,将 ChatGPT 网页会话封装为 OpenAI 兼容的免费 REST API,支持工具调用和多种 ChatGPT 特殊模式。
Stars: 1 | Forks: 0
# ChatGPT OpenAI 兼容代理
**目标:** 我致力于实现完全的 Anthropic API 对等性,以便该代理可以连接到**泄露的 Claude Code 源代码**,从而作为 Anthropic API 的完整替代品。
一个 Node.js 代理服务器,通过基于无头 ChatGPT 浏览器会话,暴露一个与 **OpenAI 兼容的 REST API**。支持普通聊天补全以及通过结构化提示转换层实现的完整**工具/函数调用**。
## 工作原理
```
Client (OpenAI SDK / curl)
│ POST /v1/chat/completions
▼
proxy.controller.js
│ buildPromptWithTools()
│ Serialises messages + tool schemas → plain text prompt
▼
browser.util.js (ChatGPTClient)
│ Types prompt into chatgpt.com, intercepts auth headers,
│ calls /backend-anon/f/conversation via in-page fetch
▼
ChatGPT (chatgpt.com)
│ Returns plain text — either an answer or a block
▼
tools.utils.js → parseToolCallReply()
│ Detects tags → OpenAI tool_calls shape
│ OR passes text through as content
▼
OpenAI-format JSON response → Client
```
## 项目结构
```
src/
├── server.js # Entry point — starts Express, initialises browser
├── app.js # Express app, mounts routes
├── routes/
│ └── proxy.route.js # POST /v1/chat/completions
├── controller/
│ └── proxy.controller.js # Request validation, orchestration, response shaping
└── utils/
├── browser.util.js # ChatGPTClient — Puppeteer browser automation
├── tools.utils.js # Tool schema serialisation + tool_call reply parsing
├── token.util.js # Token counting via js-tiktoken (cl100k_base)
└── proxy.util.js # Proxy utilities
```
## 设置
```
npm install
npm start # starts on PORT env var or 3000
```
启动时,服务器会启动一个 Chromium 窗口,导航到 `chatgpt.com`,并等待提示文本框出现。如果 Cloudflare 处于激活状态,这可能需要长达 60 秒。浏览器将保持活动状态,并用于所有后续请求。
```
Server running on port 3000
Initializing browser...
[init] waiting for #prompt-textarea...
[init] ready
```
## Docker
您也可以将代理作为 Docker 容器运行。包含的 Dockerfile 会处理所有依赖项并设置虚拟显示器,以便浏览器可以在无头环境中运行。
### 1. 构建镜像
```
docker build -t chatgpt-proxy .
```
### 2. 运行容器
```
docker run -d \
--name chatgpt-proxy \
-p 3000:3000 \
--shm-size=2gb \
chatgpt-proxy
```
## 端点
### `GET /health`
存活检查。立即返回,不接触浏览器。
**响应**
```
{ "status": "ok" }
```
### `POST /v1/chat/completions`
OpenAI 兼容的聊天补全端点。支持普通对话和工具/函数调用。
**请求头**
```
Content-Type: application/json
```
## 请求格式
### 普通聊天(无工具)
```
{
"model": "gpt-5.3",
"messages": [
{ "role": "system", "content": "You are a helpful assistant." },
{ "role": "user", "content": "What is the capital of France?" }
]
}
```
| 字段 | 类型 | 必需 | 描述 |
| ---------- | ------ | -------- | -------------------------------------------------------------- |
| `messages` | array | ✅ 是 | 对话历史。参见 [消息角色](#message-roles) |
| `model` | string | 否 | 响应的标签。默认值:`"chatgpt-proxy"` |
| `mode` | string | 否 | 触发特定功能。参见 [ChatGPT 模式](#chatgpt-modes) |
## ChatGPT 模式
请求体中的 `mode` 字段可用于触发特定的 ChatGPT 功能。
| `mode` 值 | 描述 | 底层 ChatGPT 功能 |
| :--------------- | :----------------------------------------- | :------------------------------- |
| `reasoning` | 高级推理模式 | `system_hints: ["reason"]` |
| `deep-research` | ChatGPT 深度研究 | `connector_openai_deep_research` |
| `tatertot` | 特殊的“tatertot”提示(学习模式) | `system_hints: ["tatertot"]` |
| `quiz` | QuizGPT 连接器 | `connector_openai_quizgpt_v2` |
| (空或其他) | 标准助手 | `primary_assistant` |
## 限制
- **不支持流式传输** — `stream: true` 会返回 400 错误。基于浏览器的传输在转发之前会接收到完整的响应。
- **单一并发请求** — `ChatGPTClient` 通过队列序列化所有调用。并发请求按顺序等待。
- **认证会话** — 代理依赖于浏览器中活动的 ChatGPT 会话。如果会话过期,则需要重启浏览器或重新登录。
- **无头模式** — 虽然通过 `HEADLESS=true` 环境变量支持,但在完全无头的环境中,Cloudflare 检查失败的可能性要大得多。如果在没有 GUI 的服务器上运行,请考虑使用 `xvfb-run` 或类似的虚拟显示器。
## 消息角色
支持所有四种 OpenAI 消息角色。
### system
```
{ "role": "system", "content": "You are a concise assistant." }
```
### user
```
{ "role": "user", "content": "Read the file notes.txt" }
```
### `assistant` — 普通回复
```
{ "role": "assistant", "content": "The file contains your shopping list." }
```
### `assistant` — 带有工具调用
```
{
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_tuefggdxl",
"type": "function",
"function": {
"name": "Read",
"arguments": "{\"path\":\"notes.txt\"}"
}
}
]
}
```
### `tool` — 工具结果
```
{
"role": "tool",
"tool_call_id": "call_tuefggdxl",
"content": "Buy milk\nCall dentist"
}
```
## 工具调用
### 1. 在请求中定义工具
```
{
"model": "gpt-5.3",
"tools": [
{
"type": "function",
"function": {
"name": "Read",
"description": "Read the contents of a file",
"parameters": {
"type": "object",
"properties": {
"path": { "type": "string", "description": "The file path to read" }
},
"required": ["path"]
}
}
}
],
"messages": [{ "role": "user", "content": "What is in notes.txt?" }]
}
```
### 2. 代理响应工具调用
当模型决定使用工具时,`finish_reason` 为 `"tool_calls"` 且 `content` 为 `null`:
```
{
"id": "chatcmpl-abc123",
"object": "chat.completion",
"created": 1716000000,
"model": "gpt-5.3",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_tuefggdxl",
"type": "function",
"function": {
"name": "Read",
"arguments": "{\"path\":\"notes.txt\"}"
}
}
]
},
"finish_reason": "tool_calls"
}
],
"usage": {
"prompt_tokens": 142,
"completion_tokens": 18,
"total_tokens": 160
}
}
```
### 3. 执行工具并发回结果
将助手的工具调用消息和工具结果附加到您的消息数组中,然后再次调用端点:
```
{
"model": "gpt-5.3",
"tools": [
/* same tools array */
],
"messages": [
{ "role": "user", "content": "What is in notes.txt?" },
{
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_tuefggdxl",
"type": "function",
"function": {
"name": "Read",
"arguments": "{\"path\":\"notes.txt\"}"
}
}
]
},
{
"role": "tool",
"tool_call_id": "call_tuefggdxl",
"content": "Buy milk\nCall dentist"
}
]
}
```
### 4. 代理返回最终答案
```
{
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "The file notes.txt contains two items: Buy milk and Call dentist."
},
"finish_reason": "stop"
}
]
}
```
## 响应格式
所有成功的响应都遵循 OpenAI `chat.completion` 形状:
```
{
"id": "chatcmpl-",
"object": "chat.completion",
"created": 1716000000,
"model": "",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "...", // string on stop, null on tool_calls
"tool_calls": [ ... ] // present only when finish_reason is tool_calls
},
"finish_reason": "stop" | "tool_calls"
}
],
"usage": {
"prompt_tokens": 0,
"completion_tokens": 0,
"total_tokens": 0
}
}
```
## 错误响应
所有错误均使用 OpenAI 错误信封格式:
```
{
"error": {
"message": "Human-readable description",
"type": "invalid_request_error" | "proxy_error"
}
}
```
| 状态 | `type` | 原因 |
| ------ | ----------------------- | ---------------------------------------------------------- |
| `400` | `invalid_request_error` | `messages` 缺失或为空 |
| `400` | `invalid_request_error` | 请求中包含 `stream: true` |
| `500` | `proxy_error` | 浏览器/ChatGPT 错误(认证过期、响应为空等) |
## 配合 OpenAI SDK 使用
通过覆盖 `baseURL` 将 SDK 指向此服务器:
```
import OpenAI from "openai";
const client = new OpenAI({
apiKey: "not-needed", // required by SDK but ignored by proxy
baseURL: "http://localhost:3000/v1",
});
// Plain chat
const res = await client.chat.completions.create({
model: "gpt-5.3",
messages: [{ role: "user", content: "Hello!" }],
});
// With tools
const res2 = await client.chat.completions.create({
model: "gpt-5.3",
tools: [
{
type: "function",
function: {
name: "Read",
description: "Read a file",
parameters: {
type: "object",
properties: { path: { type: "string" } },
required: ["path"],
},
},
},
],
messages: [{ role: "user", content: "What is in notes.txt?" }],
});
```
## 限制
- **不支持流式传输** — `stream: true` 会返回 400 错误。基于浏览器的传输在转发之前会接收到完整的响应。
- **单一并发请求** — `ChatGPTClient` 通过队列序列化所有调用。并发请求按顺序等待。
- **认证会话** — 代理依赖于浏览器中活动的 ChatGPT 会话。如果会话过期,则需要重启浏览器或重新登录。
- **支持无头模式** — 默认以 `headless: true` 模式运行,同时仍能通过机器人检测。
## 测试
```
npm install -D vitest supertest
npm test
```
测试模拟了 `ChatGPTClient`,因此不需要浏览器。有关涵盖 `tools.utils.js` 的单元测试和涵盖完整 HTTP 堆栈的集成测试,请参见 `src/tests/`。
标签:Anthropic API, API 兼容层, ChatGPT 逆向工程, Claude Code, Docker 部署, GNU通用公共许可证, MITM代理, Node.js, OpenAI API 代理, Puppeteer, REST API, Web 抓取, 函数调用, 大语言模型工具, 安全合规, 安全监控, 工具使用, 数字取证, 无需 API Key, 浏览器自动化, 绕过验证, 网络代理, 网络运维, 自动化脚本, 自定义脚本, 请求拦截