Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
c53f754
fix(oauth): fall back to system proxy when OAuth session has no proxy…
DeliciousBuding May 17, 2026
bdb6c19
fix(billing): correct GPT-5.5 pricing to $5.00/$30.00/M standard
DeliciousBuding May 19, 2026
0514b19
fix(docs): bind SQLite compose ports to 127.0.0.1 by default
DeliciousBuding May 19, 2026
fd7b5a2
feat: credit quota, scheduler_mode, image_studio improvements
DeliciousBuding May 19, 2026
4898191
feat(frontend): complete image-to-image UI in ImageStudio
DeliciousBuding May 19, 2026
36efb74
fix: address Haiku review findings (CRITICAL + HIGH)
DeliciousBuding May 19, 2026
13278c8
fix(docker): restore BIND_HOST env var support in SQLite compose
DeliciousBuding May 19, 2026
b454b48
fix(database): correct Scan argument order for credit fields
DeliciousBuding May 19, 2026
bee1e3c
fix: address all Haiku review findings (round 2)
DeliciousBuding May 19, 2026
3df1848
fix: round 2 review findings - api.ts syntax and billing tests
DeliciousBuding May 19, 2026
7524ff2
fix(proxy): prevent SSE stream mixing across retry accounts
DeliciousBuding May 19, 2026
bb60437
fix(proxy): add usage logging for read error paths in image generation
DeliciousBuding May 19, 2026
7f0f815
feat(frontend): add per-account USD cost column to accounts table
DeliciousBuding May 19, 2026
8eb8123
feat: add 5h/7d windowed USD cost per account
DeliciousBuding May 19, 2026
2bb5fdc
fix(docs): add explicit BIND_HOST commented variable to .env examples
DeliciousBuding May 19, 2026
d15a97b
fix(auth): restore modelMapping initialization removed by scheduler_m…
DeliciousBuding May 19, 2026
4bd024b
fix(proxy): use c.Writer.Written() instead of streamStarted for retry…
DeliciousBuding May 19, 2026
9e7b6b0
fix: round 5 findings - credit PATCH partial update + validation + Cr…
DeliciousBuding May 19, 2026
7e52fec
test(scheduler): add SetSchedulerMode re-sort and validation tests
DeliciousBuding May 20, 2026
5586599
fix(proxy): write error response when stream error cannot retry and n…
DeliciousBuding May 20, 2026
7c7ca08
docs: comprehensive refresh - CONFIGURATION, API, CHANGELOG, README
DeliciousBuding May 20, 2026
7593696
fix(billing): add gpt-4o cache input pricing + gpt-4.1 + o-series fam…
DeliciousBuding May 20, 2026
652b2b0
feat(billing): add long context (>272K tokens) premium pricing
DeliciousBuding May 20, 2026
d372209
fix(billing): add pro model matching in normalizeCodexBillingModel
DeliciousBuding May 20, 2026
5cbfe80
docs: document long context pricing and billing model expansion in CH…
DeliciousBuding May 20, 2026
0bfbf54
feat(models): add codex-auto-review model to registry and billing
DeliciousBuding May 20, 2026
aa387c1
fix(billing): map codex-auto-review to gpt-5.4 pricing (272K context …
DeliciousBuding May 20, 2026
5990824
fix(models): codex-auto-review disabled, requires ChatGPT backend API
DeliciousBuding May 20, 2026
90ce678
fix(models): codex-auto-review confirmed as gpt-5.4 alias via live test
DeliciousBuding May 20, 2026
e172e77
test(billing): add long context pricing and pro model tests
DeliciousBuding May 20, 2026
632de69
fix(test): normalizeCodexBillingModel test uses lowercased input
DeliciousBuding May 20, 2026
b36e3a4
fix(scheduler): reset zeroCursor per-tier in remaining_quota mode
DeliciousBuding May 20, 2026
ae48745
chore(billing): remove gpt-4.1 and o-series families from pricing
DeliciousBuding May 20, 2026
c2f1432
chore(billing): revert gpt-4o/gpt-4o-mini cache pricing to original
DeliciousBuding May 20, 2026
a8df800
feat(proxy): forward X-Codex-Beta-Features header to upstream
DeliciousBuding May 20, 2026
78fe653
fix: address bot review comments — stale credit response, a11y, inden…
DeliciousBuding May 20, 2026
8df8e43
fix: case-insensitive codex model matching and edit-mode submit routing
DeliciousBuding May 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
# ============================================================

# HTTP 服务端口
# Note: the standard compose files bind to all interfaces (0.0.0.0).
# Set BIND_HOST=127.0.0.1 in .env to restrict to localhost only.
# BIND_HOST=0.0.0.0
CODEX_PORT=8080

# 监听地址(默认 0.0.0.0,兼容 Docker 端口映射 / 反向代理 / 公网部署)
Expand Down
3 changes: 3 additions & 0 deletions .env.sqlite.example
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
# ============================================================

# HTTP 服务端口
# Note: the SQLite compose files bind to 127.0.0.1 by default for security.
# Override with BIND_HOST=0.0.0.0 in .env if you need external access.
# BIND_HOST=127.0.0.1
CODEX_PORT=8080

# 监听地址(默认 0.0.0.0,兼容 Docker 端口映射 / 反向代理 / 公网部署)
Expand Down
55 changes: 49 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,10 @@ Run it as a full **PostgreSQL + Redis** production stack or as a single-containe

<table>
<tr><td width="210"><b>One compatible gateway</b></td><td>OpenAI-style Chat Completions / Responses / Images, Anthropic Messages, prefixless compatibility routes, and native Codex Responses forwarding are all exposed through one service.</td></tr>
<tr><td><b>Account-pool scheduler</b></td><td>Selection is driven by account status, health tier, scheduler score, dynamic concurrency, cooldown recovery, and recent usage so unhealthy accounts are avoided automatically.</td></tr>
<tr><td><b>Visual admin console</b></td><td>The embedded React / Vite dashboard covers account import and testing, API keys, proxy pools, image studio, prompt filtering, usage analytics, operations, scheduler board, and system settings.</td></tr>
<tr><td><b>Two deployment shapes</b></td><td>Use PostgreSQL + Redis for production or SQLite + Memory for lightweight single-node deployments; Docker images, source builds, local development, and the interactive deploy script are ready to use.</td></tr>
<tr><td><b>Account-pool scheduler</b></td><td>Selection is driven by account status, health tier, scheduler score, dynamic concurrency, cooldown recovery, and recent usage so unhealthy accounts are avoided automatically. Supports <code>round_robin</code> and <code>remaining_quota</code> modes, with per-account credit billing flags.</td></tr>
<tr><td><b>Visual admin console</b></td><td>The embedded React / Vite dashboard covers account import and testing, API keys, proxy pools, image studio (text-to-image + image-to-image), prompt filtering, usage analytics, operations, scheduler board, and system settings.</td></tr>
<tr><td><b>Two deployment shapes</b></td><td>Use PostgreSQL + Redis for production or SQLite + Memory for lightweight single-node deployments; Docker images, source builds, local development, and the interactive deploy script are ready to use. SQLite mode binds to <code>127.0.0.1</code> by default for security.</td></tr>
<tr><td><b>Billing and observability</b></td><td>Per-account 5h/7d windowed USD cost tracking, credit quota support, API key usage tracking, OAuth PKCE token acquisition, prompt filtering, and a usage dashboard with request logs and trend charts.</td></tr>
</table>

---
Expand Down Expand Up @@ -164,6 +165,7 @@ Notes:
- Standard and SQLite modes both read `.env`.
- Before switching deployment modes, replace `.env` with the matching example file.
- The SQLite lightweight mode runs a single `codex2api` container and stores data at `/data/codex2api.db`.
- **SQLite compose files bind to `127.0.0.1` by default for security.** To expose the SQLite service on all interfaces, set `BIND_HOST=0.0.0.0` in `.env` or override the port binding in the compose file. The standard compose files bind to `0.0.0.0` by default.
- The image studio library is stored under `/data/images`; Docker configurations persist `/data`.
- `docker compose down` does not delete named volumes by default. Data is removed only by commands such as `docker compose down -v`, `docker volume rm`, or `docker volume prune`.

Expand Down Expand Up @@ -262,7 +264,7 @@ The standard `.env.example` declares `DATABASE_DRIVER=postgres` and `CACHE_DRIVE

Runtime business settings are stored in the database `SystemSettings` table and can be updated from the admin settings page.

Examples include `MaxConcurrency`, `GlobalRPM`, `TestModel`, `TestConcurrency`, `ProxyURL`, `PgMaxConns`, `RedisPoolSize`, `AdminSecret`, and auto-cleanup switches.
Examples include `MaxConcurrency`, `GlobalRPM`, `TestModel`, `TestConcurrency`, `ProxyURL`, `PgMaxConns`, `RedisPoolSize`, `AdminSecret`, `SchedulerMode`, and auto-cleanup switches.

Default settings are written automatically on first startup.

Expand All @@ -284,9 +286,11 @@ Default settings are written automatically on first startup.
| `POST /v1/responses` | Responses style endpoint |
| `POST /v1/images/generations` | OpenAI Images generation endpoint |
| `POST /v1/images/edits` | OpenAI Images edit endpoint |
| `GET /v1/models` | List available models |
| `GET /v1/models` | List available models (includes gpt-5.5, gpt-5.4, gpt-5.4-mini, gpt-5.3-codex, gpt-image-2, etc.) |
| `GET /health` | Health check |

> **Pricing**: gpt-5.5 is billed at $5.00/M input and $30.00/M output (standard tier). Priority tier: $12.50/M input, $75.00/M output. Other models follow pricing rules in the billing engine.

See [API.md](docs/API.md) for full request formats, response formats, and error codes.

### Token Upload and Account Management
Expand Down Expand Up @@ -349,6 +353,27 @@ curl -X POST http://localhost:8080/api/admin/accounts/import \

Import endpoints deduplicate tokens automatically. Existing tokens are not inserted again.

#### OAuth PKCE Authorization

Codex2API supports acquiring Refresh Tokens through the OAuth PKCE flow, useful when manual token extraction is impractical:

```bash
# Step 1: Generate an authorization URL
curl -X POST http://localhost:8080/api/admin/oauth/generate-auth-url \
-H "X-Admin-Key: your-admin-secret" \
-H "Content-Type: application/json" \
-d '{}'

# Step 2: Open the returned auth_url in a browser, complete authorization
# Step 3: Exchange the authorization code for a token (auto-creates account)
curl -X POST http://localhost:8080/api/admin/oauth/exchange-code \
-H "X-Admin-Key: your-admin-secret" \
-H "Content-Type: application/json" \
-d '{"session_id": "...", "code": "...", "state": "..."}'
```

See [API.md](docs/API.md) for the full OAuth flow and all admin endpoints.

---

## Admin Dashboard
Expand All @@ -361,7 +386,7 @@ Open `/admin/` in a browser.
| Accounts | `/admin/accounts` | Import, test, batch actions, scheduler state |
| API Keys | `/admin/api-keys` | API key creation, inspection, deletion, and credential management |
| Proxies | `/admin/proxies` | Proxy pool management, account proxy assignment, connectivity checks |
| Image Studio | `/admin/images/studio` | Text-to-image, prompt templates, task history, server-side image library |
| Image Studio | `/admin/images/studio` | Text-to-image, image-to-image, prompt templates, task history, server-side image library |
| Prompt Filter | `/admin/prompt-filter/overview` | Rules, hit logs, testing, and handling mode configuration |
| Usage | `/admin/usage` | Request logs, metric cards, charts, log cleanup |
| Operations | `/admin/ops` | Runtime monitoring and system overview |
Expand Down Expand Up @@ -431,6 +456,24 @@ Observability:
- `GET /api/admin/ops/overview` shows runtime and connection pool state.
- `/admin/ops/scheduler` provides the scheduler board.

**Scheduler mode** (`scheduler_mode`, via Admin Settings):

| Mode | Behavior |
| --- | --- |
| `round_robin` (default) | Round-robin across available accounts per health tier, weighted by dispatch score |
| `remaining_quota` | Prioritizes accounts with lower usage percent; round-robin for ties |

**Credit accounts** (per-account flags):

When an account has a credit-based billing model instead of a usage-based Free/Pro plan, you can mark it so the scheduler skips usage-window penalties:

| Field | Type | Effect |
| --- | --- | --- |
| `credit_enabled` | bool | Mark account as credit-based billing |
| `credit_skip_usage_window` | bool | When true, skip 7d/5h usage-window penalties for this account |

**Windowed USD cost**: The accounts table displays per-account billed cost over two windows -- the past 5 hours and the past 7 days -- aligned with each account's usage reset boundaries. This shows actual spending per account rather than estimated token costs.

---

## Project Structure
Expand Down
55 changes: 49 additions & 6 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,10 @@

<table>
<tr><td width="210"><b>统一兼容入口</b></td><td>同时覆盖 OpenAI 风格 Chat Completions / Responses / Images、Anthropic Messages、无前缀兼容路由和 Codex 原生 Responses 转发,客户端侧少改配置即可接入。</td></tr>
<tr><td><b>账号池调度核心</b></td><td>围绕账号状态、健康层级、调度分、动态并发、冷却恢复和近期用量做选择,自动避开不可用账号,减少单账号打满和反复失败。</td></tr>
<tr><td><b>可视化管理后台</b></td><td>内置 React / Vite 管理台,提供账号导入测试、API Key、代理池、生图、Prompt 检查、用量统计、运维概览、调度看板和系统设置。</td></tr>
<tr><td><b>两种部署形态</b></td><td>生产环境用 PostgreSQL + Redis,单机测试用 SQLite + Memory;Docker 镜像、源码构建、本地开发和一键交互部署脚本都已准备好。</td></tr>
<tr><td><b>账号池调度核心</b></td><td>围绕账号状态、健康层级、调度分、动态并发、冷却恢复和近期用量做选择,自动避开不可用账号,减少单账号打满和反复失败。支持 <code>round_robin</code> 和 <code>remaining_quota</code> 两种调度模式,以及单账号信用计费标记。</td></tr>
<tr><td><b>可视化管理后台</b></td><td>内置 React / Vite 管理台,提供账号导入测试、API Key、代理池、生图(文生图 + 图生图)、Prompt 检查、用量统计、运维概览、调度看板和系统设置。</td></tr>
<tr><td><b>两种部署形态</b></td><td>生产环境用 PostgreSQL + Redis,单机测试用 SQLite + Memory;Docker 镜像、源码构建、本地开发和一键交互部署脚本都已准备好。SQLite 模式默认绑定 <code>127.0.0.1</code> 以提升安全性。</td></tr>
<tr><td><b>计费与可观测性</b></td><td>单账号 5h/7d 窗口化 USD 费用追踪、信用配额支持、API Key 用量追踪、OAuth PKCE 获取 Token、Prompt 过滤,以及含请求日志与趋势图表的用量仪表盘。</td></tr>
</table>

---
Expand Down Expand Up @@ -209,6 +210,7 @@ docker compose -f docker-compose.sqlite.local.yml logs -f codex2api
- SQLite 镜像版容器名:`codex2api-sqlite`
- SQLite 本地构建版容器名:`codex2api-sqlite-local`
- SQLite 轻量版只启动 `codex2api` 单容器,数据保存在 `/data/codex2api.db`
- **SQLite compose 文件默认绑定 `127.0.0.1`,仅本机可访问。** 如需暴露给外部,请在 `.env` 中设置 `BIND_HOST=0.0.0.0` 或修改 compose 文件中的端口绑定。标准版 compose 文件默认绑定 `0.0.0.0`(所有网络接口)。
- 生图工作台图库默认保存在 `/data/images`,标准版和 SQLite 版 Docker 配置都会持久化 `/data`
- `docker compose down` 默认不会删除命名卷;只有 `docker compose down -v`、`docker volume rm` 或 `docker volume prune` 才会删除持久化数据
- 不同部署模式的数据卷彼此隔离;切换 compose 文件后看到空数据,通常是切到了另一组卷,而不是原卷被自动删除
Expand Down Expand Up @@ -313,7 +315,7 @@ Vite 会自动代理 `/api` 和 `/health` 到后端,开发时访问 `http://lo

以下参数**保存在数据库 `SystemSettings` 中**,通过管理台设置页面修改:

`MaxConcurrency`、`GlobalRPM`、`TestModel`、`TestConcurrency`、`ProxyURL`、`PgMaxConns`、`RedisPoolSize`、`AdminSecret`、自动清理开关等。
`MaxConcurrency`、`GlobalRPM`、`TestModel`、`TestConcurrency`、`ProxyURL`、`PgMaxConns`、`RedisPoolSize`、`AdminSecret`、`SchedulerMode`、自动清理开关等。

首次启动时程序会自动写入默认设置。

Expand All @@ -335,9 +337,11 @@ Vite 会自动代理 `/api` 和 `/health` 到后端,开发时访问 `http://lo
| `POST /v1/responses` | Responses 风格入口 |
| `POST /v1/images/generations` | OpenAI Images 生成入口 |
| `POST /v1/images/edits` | OpenAI Images 编辑入口 |
| `GET /v1/models` | 返回可用模型列表 |
| `GET /v1/models` | 返回可用模型列表(含 gpt-5.5、gpt-5.4、gpt-5.4-mini、gpt-5.3-codex、gpt-image-2 等) |
| `GET /health` | 健康检查 |

> **计费提示**:gpt-5.5 标准 tier 计费为 $5.00/M 输入 / $30.00/M 输出,priority tier 为 $12.50/M 输入 / $75.00/M 输出。其他模型按 billing 引擎规则计费。

> 完整请求/响应格式、错误码参见 [API 文档](docs/API.md)。

### Token 上传与账号管理
Expand Down Expand Up @@ -400,6 +404,27 @@ curl -X POST http://localhost:8080/api/admin/accounts/import \

> 所有导入接口自动去重,已存在的 Token 不会重复写入。更多管理接口(导出、迁移、OAuth 授权等)参见 [API 文档](docs/API.md)。

#### OAuth PKCE 授权

Codex2API 支持通过 OAuth PKCE 流程获取 Refresh Token,适用于无法手动提取 Token 的场景:

```bash
# 步骤 1:生成授权 URL
curl -X POST http://localhost:8080/api/admin/oauth/generate-auth-url \
-H "X-Admin-Key: your-admin-secret" \
-H "Content-Type: application/json" \
-d '{}'

# 步骤 2:在浏览器中打开返回的 auth_url,完成授权
# 步骤 3:用授权码兑换 Token(自动创建账号)
curl -X POST http://localhost:8080/api/admin/oauth/exchange-code \
-H "X-Admin-Key: your-admin-secret" \
-H "Content-Type: application/json" \
-d '{"session_id": "...", "code": "...", "state": "..."}'
```

> 完整 OAuth 流程及所有管理接口参见 [API 文档](docs/API.md)。

---

## 管理后台
Expand All @@ -412,7 +437,7 @@ curl -X POST http://localhost:8080/api/admin/accounts/import \
| 账号管理 | `/admin/accounts` | 导入、测试、批量处理、调度信息查看 |
| API 密钥 | `/admin/api-keys` | API Key 创建、查看、删除与调用凭据管理 |
| 代理管理 | `/admin/proxies` | 代理池维护、账号代理分配与连通性管理 |
| 生图工作台 | `/admin/images/studio` | 文生图、提示词模板、任务历史和服务器图库 |
| 生图工作台 | `/admin/images/studio` | 文生图、图生图、提示词模板、任务历史和服务器图库 |
| Prompt 检查 | `/admin/prompt-filter/overview` | Prompt 规则、触发日志、测试和处理模式配置 |
| 使用统计 | `/admin/usage` | 请求日志、统计卡片、图表、日志清空 |
| 运维概览 | `/admin/ops` | 运行态监控与系统概览 |
Expand Down Expand Up @@ -495,6 +520,24 @@ curl -X POST http://localhost:8080/api/admin/accounts/import \
- `GET /api/admin/ops/overview` — 系统运行态与连接池概览
- `/admin/ops/scheduler` — 前端调度看板

**调度模式**(`scheduler_mode`,通过管理后台设置):

| 模式 | 行为 |
| --- | --- |
| `round_robin`(默认) | 按健康层级轮询可用账号,权重按调度分排序 |
| `remaining_quota` | 优先使用用量较低的账号;用量相同时轮询 |

**信用账号**(单账号标记):

对采用信用计费而非 Free/Pro 用量计费的账号,可标记为信用账号以跳过用量窗口惩罚:

| 字段 | 类型 | 作用 |
| --- | --- | --- |
| `credit_enabled` | bool | 标记账号为信用计费模式 |
| `credit_skip_usage_window` | bool | 开启后跳过 7 天/5 小时用量窗口惩罚 |

**窗口化 USD 费用**:账号列表展示每个账号在两个时间窗口内的累计计费金额——过去 5 小时和过去 7 天,窗口对齐各账号的用量重置边界。这反映的是实际扣费金额而非估算的 Token 费用。

---

## 目录结构
Expand Down
Loading
Loading