FastAPI 服務 · 個人 / 開發測試用 · MIT

一個 ChatGPT 訂閱,
一個自架圖片 API

把 Codex CLI 內建的 $imagegen 包成簡單的 FastAPI 服務。 在後台幫每個內部腳本、CI 工作、Side Project 各發一把 bearer key, 它們就能共用一份 ChatGPT 訂閱的產圖額度,不用各自燒 OpenAI Images API credits。

1為什麼需要它

你已經付了 ChatGPT 訂閱費。Codex CLI 也已經裝在你 homelab 那台機器上、 codex login 過了。但每一個想產圖的內部腳本、CI workflow、 Discord/Telegram bot 要不就要 ssh 進你的機器跑 codex exec、要不就得另外花 OpenAI Images API 的錢。

這個服務提供第三條路:把 $imagegen 包成一條 Authorization: Bearer cimg_<random-token> 的小 HTTP API, 搭配一個 admin 後台讓你可以隨時發 key、停 key、刪 key。 一個 ChatGPT 帳號、多個 caller、不必多花一塊錢。

2它會產出什麼

背後跑的是 gpt-image-2,也就是 Codex CLI 內建 image_gen 工具的模型。這個服務 對輸出做二次處理或過濾, $imagegen 產出什麼就回傳什麼,並把這次產圖的歷史記到 SQLite。

3安裝

前置:Codex CLI 已裝好、 codex login 完成。要跑 container 的話再加 Docker + Docker Compose。

A. 本機測試 — 不需要 nginx

git clone https://github.com/yazelin/codex-image-service
cd codex-image-service
cp .env.example .env
# 編輯 .env:設好 ADMIN_PASSWORD、ADMIN_SESSION_SECRET 即可

docker compose -f docker-compose.local.yml up -d --build
open http://localhost:8000/admin

Port 8000 直接 bind 到你主機,不用 reverse proxy。 API 回傳的圖片網址會是 http://localhost:8000/generated/...

B. 正式環境 — 接到既有 nginx 後面

# .env 還要加:
# PUBLIC_BASE_URL=https://YOUR-DOMAIN/codex-image
# ADMIN_URL_PREFIX=/codex-image

docker compose up -d --build
# 然後把 deploy/nginx.codex-image-service.location.conf.example
# 貼進你既有的 nginx,nginx -s reload

預設的 docker-compose.yml 會把 container 接到一個既有的 Docker network nginx_bridge_network。初次健康檢查:

curl -sf https://YOUR-DOMAIN/codex-image/health
# {"status":"ok"}

C. 完全不用 Docker — 開發最快

python3 -m venv .venv && . .venv/bin/activate
pip install -r requirements.txt
uvicorn app.main:app --reload --port 8000

直接吃主機的 ~/.codex/auth.json,不掛 volume,改 code 自動 reload。

4怎麼用

/codex-image/admin 登入,按 Create API Key, 把跳出來的 cimg_<random-token> 複製起來。 重整或離開這頁之後原始字串就消失了(伺服器只留 sha256 hash),然後就可以打 API:

# shell / GitHub Actions
curl -sS --fail --max-time 650 \
  -X POST https://YOUR-DOMAIN/codex-image/v1/images/generate \
  -H "Authorization: Bearer $CODEX_IMAGE_KEY" \
  -H "Content-Type: application/json" \
  -d '{"prompt":"...","size":"1024x1024","quality":"medium","count":1}'
# python (httpx)
import httpx, os
r = httpx.post(
    "https://YOUR-DOMAIN/codex-image/v1/images/generate",
    headers={"Authorization": f"Bearer {os.environ['CODEX_IMAGE_KEY']}"},
    json={"prompt": "...", "size": "1024x1024", "quality": "medium", "count": 1},
    timeout=httpx.Timeout(connect=10, read=600, write=30, pool=10),
)
images = r.json()["images"]   # [{"url": "...", "expires_at": "..."}]

回傳格式:

{
  "id": "img_3f81...",
  "status": "succeeded",
  "images": [{"url": "https://YOUR-DOMAIN/codex-image/generated/img_3f81....png",
              "expires_at": "..."}],
  "created_at": "..."
}

5多帳號 Round-robin

單一 ChatGPT 訂閱的 per-account 產圖配額才是真正的 throughput 上限。 設兩個以上的 ChatGPT 帳號,服務就會逐請求輪流切 CODEX_HOME; 其中一個失敗時自動 retry 下一個帳號。

# host 端 ~/codex-homes/<label>/ 各放一個
mkdir -p ~/codex-homes/{personal,team}
CODEX_HOME=~/codex-homes/personal codex login   # 登第一個帳號
CODEX_HOME=~/codex-homes/team     codex login   # 登第二個帳號

# .env(路徑是 container 內的觀點)
CODEX_HOMES=/host_codex_homes/personal:/host_codex_homes/team

# 重啟 — ~/codex-homes 父目錄已經被掛進 /host_codex_homes
docker compose up -d --build

子資料夾名稱隨你(personal / team-acme / dev …)。 同一個 ChatGPT 用戶登兩次只會指到同一個 quota 池,**只有用不同 user 帳號** 才會真的多開配額池。

後台 Overview 會每個帳號出一張卡:近 30 天 request 數、成功 / 失敗、 auth token 健康度(綠 ≤6 天、黃 7–9 天、紅 ≥10 天 — access token 剛好 10 天到期),加上 ChatGPT account_id 前 8 碼 讓你辨認。access token 過期前要把 host 端 token 弄新, auth.json 是 read-only 掛載,container 不會自己刷新:

# 每週 cron:touch 每個 home 觸發 codex token refresh
for h in ~/codex-homes/*/; do CODEX_HOME="$h" codex --version >/dev/null; done

6後台有什麼

發 key / 停 key / 刪 key

名稱進 api_keys 表,token 只存 sha256 hash,原始字串只在建立時顯示一次。

後台測試產圖

挑一把 key + 打 prompt + 選 size/quality,從後台直接丟一個 job 進去驗證 key 能用,不用開終端機。

自動過期清掉

每張圖都帶 expires_at(預設 IMAGE_RETENTION_DAYS=7),背景排程定期清 PNG 與工作目錄。

🗑手動逐張刪

Image Requests 表每一列有 Delete,立刻清檔案、工作目錄、DB row,不必等到自動過期。

後台實際操作(19 秒、無聲):

!免責聲明 — 個人 / 實驗性質專用

這個專案是為了我們自己 homelab 的開發與測試而寫的。 與 OpenAI 沒有任何附屬關係,也不在他們的支援範圍內。 它只是包了官方 @openai/codex CLI、把其中的 $imagegen skill 重新導出成 HTTP API; 每一次呼叫都消耗你掛進容器的那一個 ChatGPT 帳號 (~/.codex/auth.json)的額度。

要 fork 或自行架設請先看清楚以下事項: