Initial project import

This commit is contained in:
XM
2026-09-18 03:46:58 +08:00
commit b600da4b76
209 changed files with 45904 additions and 0 deletions
+359
View File
@@ -0,0 +1,359 @@
# 部署与升级指南
本文介绍 ChatGPT2API 的常见部署方式,以及后续升级项目时需要保留的数据和执行步骤。
## 部署前准备
服务器需要安装:
- Docker
- Docker Compose v2
- Git
首次部署前建议确认:
```bash
docker version
docker compose version
git --version
```
项目核心持久化文件:
| 路径 | 作用 |
| --- | --- |
| `config.json` | 主配置、后台密钥、代理、图片、备份等配置 |
| `.env` | Docker compose 环境变量 |
| `data/` | 账号、日志、图片、任务记录等运行数据 |
升级和迁移时重点保留以上内容。
## 方式一:普通 Docker 部署
适合不需要 WARP / FlareSolverr 清障的场景。
```bash
git clone git@github.com:basketikun/chatgpt2api.git
cd chatgpt2api
```
设置 `config.json` 中的 `auth-key`,或在 `docker-compose.yml` 中配置:
```yaml
environment:
- CHATGPT2API_AUTH_KEY=your_secret_key
```
启动:
```bash
docker compose up -d
```
访问:
```text
http://localhost:3000
```
API 基础地址:
```text
http://localhost:3000/v1
```
查看日志:
```bash
docker logs -f chatgpt2api
```
停止:
```bash
docker compose down
```
## 方式二:WARP / FlareSolverr 部署
适合上游请求经常遇到 Cloudflare 拦截的场景。该方式会启动:
- `warp-proxy`
- `privoxy`
- `flaresolverr`
- `init-config`
- `app`
复制环境变量模板:
```bash
cp .env.example .env
```
至少修改 `.env` 中的:
```text
CHATGPT2API_AUTH_KEY=your_secret_key_here
```
启动:
```bash
docker compose -f docker-compose.warp.yml up -d --build
```
访问:
```text
http://localhost:3000
```
FlareSolverr 相关配置可以在后台设置页的 `FlareSolverr` tab 中查看和测试。
查看容器状态:
```bash
docker compose -f docker-compose.warp.yml ps
```
查看日志:
```bash
docker logs -f chatgpt2api-warp
docker logs -f chatgpt2api-flaresolverr
```
停止:
```bash
docker compose -f docker-compose.warp.yml down
```
## 方式三:源码运行
适合本地开发或临时调试。
后端:
```bash
git clone git@github.com:basketikun/chatgpt2api.git
cd chatgpt2api
uv sync
uv run main.py
```
前端开发服务:
```bash
cd web
bun install
bun run dev
```
源码方式运行时,后端默认读取项目根目录的 `config.json` 和 `data/`。
## 存储后端
默认使用本地 JSON 文件:
```text
STORAGE_BACKEND=json
```
可选值:
| 值 | 说明 |
| --- | --- |
| `json` | 本地 JSON 文件,默认方式 |
| `sqlite` | 本地 SQLite,通常存放在 `data/accounts.db` |
| `postgres` | 外部 PostgreSQL |
| `git` | Git 私有仓库存储账号数据 |
PostgreSQL 示例:
```yaml
environment:
- STORAGE_BACKEND=postgres
- DATABASE_URL=postgresql://user:password@host:5432/dbname
```
SQLite 示例:
```yaml
environment:
- STORAGE_BACKEND=sqlite
- DATABASE_URL=sqlite:////app/data/accounts.db
```
## 升级前备份
升级前建议备份:
```bash
mkdir -p backups
tar -czf backups/chatgpt2api-$(date +%Y%m%d-%H%M%S).tgz config.json .env data
```
如果没有 `.env`,可以去掉:
```bash
tar -czf backups/chatgpt2api-$(date +%Y%m%d-%H%M%S).tgz config.json data
```
也可以在后台设置页配置 Cloudflare R2 备份,用于定时备份关键数据。
## 升级:普通 Docker 部署
进入项目目录:
```bash
cd chatgpt2api
```
备份:
```bash
mkdir -p backups
tar -czf backups/chatgpt2api-$(date +%Y%m%d-%H%M%S).tgz config.json .env data
```
拉取最新代码和镜像:
```bash
git pull
docker compose pull
docker compose up -d
```
查看状态:
```bash
docker compose ps
docker logs -f chatgpt2api
```
## 升级:WARP / FlareSolverr 部署
进入项目目录:
```bash
cd chatgpt2api
```
备份:
```bash
mkdir -p backups
tar -czf backups/chatgpt2api-$(date +%Y%m%d-%H%M%S).tgz config.json .env data
```
拉取最新代码并重新构建:
```bash
git pull
docker compose -f docker-compose.warp.yml up -d --build
```
查看状态:
```bash
docker compose -f docker-compose.warp.yml ps
docker logs -f chatgpt2api-warp
```
## 升级:源码运行
```bash
cd chatgpt2api
git pull
uv sync
```
如果需要重新构建前端静态产物:
```bash
cd web
bun install
bun run build
```
然后按你的进程管理方式重启后端服务。
## 回滚
如果升级后需要回滚代码:
```bash
git log --oneline -n 20
git checkout <旧版本commit>
```
普通 Docker 部署:
```bash
docker compose up -d
```
WARP / FlareSolverr 部署:
```bash
docker compose -f docker-compose.warp.yml up -d --build
```
如果需要恢复数据:
```bash
tar -xzf backups/你的备份文件.tgz
```
恢复数据前建议先停止容器,避免运行中写入覆盖:
```bash
docker compose down
```
或:
```bash
docker compose -f docker-compose.warp.yml down
```
## 常用维护命令
查看容器:
```bash
docker compose ps
```
查看主服务日志:
```bash
docker logs -f chatgpt2api
```
查看 WARP 部署主服务日志:
```bash
docker logs -f chatgpt2api-warp
```
重启普通部署:
```bash
docker compose restart
```
重启 WARP 部署:
```bash
docker compose -f docker-compose.warp.yml restart
```
清理未使用镜像:
```bash
docker image prune
```
不要直接删除 `data/`、`config.json`、`.env`,除非已经确认有可用备份。
+45
View File
@@ -0,0 +1,45 @@
# 功能状态
本文基于当前仓库当前实现整理,用于帮助用户快速了解哪些功能已经可用、哪些仍在完善、哪些待实现。
| 功能 | 状态 | 说明 |
|:----------------------------------------|:--:|:--------------------------------------------------------------|
| OpenAI 兼容 `POST /v1/images/generations` | ✅ | 已支持,用于图片生成,并可通过 `n` 返回多张图片。 |
| OpenAI 兼容 `POST /v1/images/edits` | ✅ | 已支持,可上传图片进行编辑。 |
| 面向图片工作流的 `POST /v1/chat/completions` | ✅ | 已支持图片相关请求。 |
| 面向图片工作流的 `POST /v1/responses` | ✅ | 已支持图片生成工具调用。 |
| `GET /v1/models` 接口 | ✅ | 当前返回 `gpt-image-2`、`codex-gpt-image-2`、`auto`、`gpt-5`、`gpt-5-1`、`gpt-5-2`、`gpt-5-3`、`gpt-5-3-mini`、`gpt-5-mini`。 |
| 同时生成多张图片 | ✅ | 已支持,后端与前端都可进行多图生成。 |
| 图片并行生成 | ✅ | 多张图片使用独立线程和账号同时生成,可通过 `image_parallel_generation` 配置关闭。 |
| 图片生成进度追踪 | ✅ | 任务显示当前步骤(上传/预热/获取token/生成中等),支持耗时统计。 |
| 图片超时续轮询 | ✅ | 超时任务可继续等待,前端显示"继续等待"按钮,后端 resume-poll API。 |
| 图片二次确认与先check再hit | ✅ | 可通过 `image_settle_enabled` 和 `image_check_before_hit_enabled` 配置,关闭后跳过等待直接返回。 |
| 前端图片工作台 | ✅ | 已支持图片生成、图片编辑、模型选择、历史记录与查看大图。 |
| 前端图片懒加载与滚动优化 | ✅ | LazyImage 懒加载、会话切换滚动位置保存与恢复、bfcache 页面恢复同步。 |
| 前端图片输入 / 参考图交互 | ✅ | 已支持参考图上传、预览、移除和编辑模式工作流。 |
| Codex 画图接口逆向 | ✅ | 已支持,仅 `Plus` / `Team` / `Pro` 订阅可用,模型别名为 `codex-gpt-image-2`;如有需要可自行在其他场景映射回 `gpt-image-2`。这是 Codex 逆向链路,用于和官网画图区分,同一账号通常会同时支持官网和 Codex 两份生图额度。 |
| Cherry Studio 接入 | ✅ | 已支持作为绘图接口接入 Cherry Studio。 |
| New API 接入 | ✅ | 已支持接入 New API。 |
| 账号池管理 | ✅ | 已支持列表、筛选、批量操作、导出、手动编辑、刷新和删除。 |
| 手动账号状态保护 | ✅ | 手动设置“禁用”或“限流”后,账号刷新、令牌轮换和生图结束不会覆盖状态,也不会自动清理该账号;手动改回“正常”可恢复自动状态管理。旧数据中的“禁用”自动保留,旧“限流”因无法判断来源,需要重新手动保存一次。 |
| 账号刷新异步进度追踪 | ✅ | 刷新和重新登录改为异步模式,前端轮询显示进度。 |
| 密码重新登录恢复异常账号 | ✅ | 号池管理页面支持重新登录,刷新后可自动重登异常账号。 |
| 账号额度刷新与恢复时间同步 | ✅ | 已支持账号信息刷新,限流账号也会自动继续检查。 |
| 失效 Token 自动清理 | ✅ | 已支持自动移除失效 Token。 |
| CPA 连接管理 | ✅ | 已支持 CPA 连接的新增、修改、查询和删除。 |
| CPA 文件浏览与按需导入 | ✅ | 已支持读取远程文件列表、筛选、勾选并导入到本地号池。 |
| CPA 导入进度跟踪 | ✅ | 已支持导入进度展示与轮询更新。 |
| `sub2api` 连接管理与账号浏览 | ✅ | 已支持 `sub2api` 服务器的新增、修改、删除、分组查询和 OpenAI OAuth 账号列表读取。 |
| `sub2api` 导入 | ✅ | 已支持勾选 `sub2api` 中的 OpenAI OAuth 账号,批量拉取 `access_token` 导入本地号池,并展示导入进度。 |
| Docker 自托管部署 | ✅ | 已支持 Docker Compose 部署,并提供多架构镜像。 |
| 兼容接口中的多参考图能力 | ✅ | 已实现,支持在兼容接口中传入多参考图。 |
| 更高级的 Token 调度策略 | ⚠️ | 当前已有基础轮询与限流刷新机制,更复杂的调度策略仍在完善中。 |
| Render / Vercel 等部署表述 | ⚠️ | 当前主要以 Docker 部署为主,其他平台部署方式暂未重点说明。 |
| `/v1/complete` 文本补全与流式输出 | ✅ | 已实现。 |
| 流式输出支持 | ✅ | 已实现。 |
| 文本补全缓存与重复请求合并 | ✅ | `/v1/chat/completions` 文本链路默认启用 60 秒短缓存、流式结果回放、in-flight 请求合并和相邻重复消息清理;可通过 `chat_completion_cache` 配置关闭或调整。 |
| 图片尺寸参数 | ❌ | 待实现。 |
| 服务端图片 URL 缓存 | ✅ | 已实现。 |
| `rt_token` 刷新 | ❌ | 待实现。 |
| 代理配置功能 | ✅ | 已支持网页端配置全局 HTTP / HTTPS / SOCKS5 / SOCKS5H 代理,并应用到出站请求。 |
| Anthropic 协议支持 | ❌ | 待实现。 |
+271
View File
@@ -0,0 +1,271 @@
# 上游 Conversation SSE 协议说明
Conversation SSE 是上游对话链路的流式返回协议。每条 SSE `data:` 通常是一段 JSON payload,也可能是协议标记或结束标记。客户端需要按顺序消费这些 payload,维护当前会话状态、文本内容、工具调用状态和图片结果指针。
## 基本形态
常见 payload 示例:
```text
"v1"
{"type":"resume_conversation_token",...}
{"p":"","o":"add","v":{...}}
{"v":{...}}
{"p":"/message/content/parts/0","o":"append","v":"..."}
{"type":"server_ste_metadata","metadata":{...}}
[DONE]
```
处理建议:
| payload | 含义 | 处理方式 |
|:--|:--|:--|
| `"v1"` | 协议版本标记 | 可记录,通常不影响业务 |
| `[DONE]` | 当前 SSE 流结束 | 停止继续读取 |
| JSON object | 事件、消息或 patch | 按字段更新会话状态 |
| JSON string | 短文本 patch 或协议标记 | 结合上下文处理 |
| 非 JSON 内容 | 原始内容 | 保留为 raw 事件,避免中断流 |
## 常用字段
| 字段 | 说明 |
|:--|:--|
| `type` | 上游事件类型,如 `resume_conversation_token`、`input_message`、`message_marker`、`title_generation`、`server_ste_metadata` |
| `conversation_id` | 当前会话 ID,可从多个事件中获得 |
| `p` | patch 路径,例如 `/message/content/parts/0` |
| `o` | patch 操作,例如 `add`、`append`、`replace`、`patch` |
| `v` | patch 值,可能是字符串、数组,也可能包含完整 message |
| `c` | 消息序号或游标,常见于 add 类事件 |
| `message.id` | 消息 ID |
| `message.author.role` | 消息角色,常见 `system`、`user`、`assistant`、`tool` |
| `message.content.content_type` | 内容类型,如 `text`、`multimodal_text`、`model_editable_context` |
| `message.content.parts` | 内容片段,可能包含文本、图片指针或多模态对象 |
| `message.status` | 消息状态,如 `in_progress`、`finished_successfully` |
| `message.end_turn` | 是否结束当前轮次 |
| `metadata.tool_invoked` | 本轮是否调用工具 |
| `metadata.turn_use_case` | 本轮用途,如 `text`、`multimodal` |
| `metadata.async_task_type` | 异步工具任务类型,图片生成通常为 `image_gen` |
## 会话启动事件
上游通常会先返回恢复令牌或会话令牌:
```json
{
"type": "resume_conversation_token",
"kind": "topic",
"token": "...",
"conversation_id": "..."
}
```
这个事件主要用于标识会话和恢复上下文。业务层通常只需要保存 `conversation_id`,`token` 不应该暴露给下游用户。
## 消息 add 场景
完整消息可能通过 `add` 或带 `v.message` 的事件出现:
```json
{
"p": "",
"o": "add",
"v": {
"message": {
"author": {"role": "assistant"},
"content": {"content_type": "text", "parts": [""]},
"status": "in_progress"
},
"conversation_id": "..."
},
"c": 3
}
```
此类事件常用于创建一条新消息。若消息角色为 `assistant`,后续文本通常会通过 patch 继续追加。
## 文本增量场景
文本输出通常由多条 patch 组成:
```json
{"p":"/message/content/parts/0","o":"append","v":"Hello"}
{"v":" world"}
{"p":"","o":"patch","v":[
{"p":"/message/content/parts/0","o":"append","v":"!"},
{"p":"/message/status","o":"replace","v":"finished_successfully"},
{"p":"/message/end_turn","o":"replace","v":true}
]}
```
处理要点:
| 形态 | 含义 |
|:--|:--|
| `p == "/message/content/parts/0"` 且 `o == "append"` | 向当前文本追加内容 |
| `o == "replace"` | 用新值替换目标字段 |
| `o == "patch"` 且 `v` 是数组 | 批量 patch,需要按数组顺序处理 |
| 只有 `v` 且 `v` 是字符串 | 可能是省略路径的文本增量,应结合当前文本流处理 |
## 输入消息场景
用户输入会以 `input_message` 或普通 `user` message 出现。图片编辑请求会包含用户上传的参考图:
```json
{
"type": "input_message",
"input_message": {
"author": {"role": "user"},
"content": {
"content_type": "multimodal_text",
"parts": [
{"asset_pointer": "sediment://file_input"},
"编辑提示词"
]
}
},
"conversation_id": "..."
}
```
这类 `sediment://...` 表示输入附件,不是生成结果。即使它可以被下载,也不能当作输出图片返回。
## 图片工具成功场景
图片生成或图片编辑成功时,上游一般会出现工具消息:
```json
{
"v": {
"message": {
"author": {"role": "tool"},
"content": {
"content_type": "multimodal_text",
"parts": [
{"asset_pointer": "file-service://file_result"},
{"asset_pointer": "sediment://file_result"}
]
},
"metadata": {"async_task_type": "image_gen"}
}
},
"conversation_id": "..."
}
```
只有同时满足以下条件的图片指针,才应该视为输出结果:
| 条件 | 说明 |
|:--|:--|
| `message.author.role == "tool"` | 来源是工具消息 |
| `metadata.async_task_type == "image_gen"` | 工具任务是图片生成 |
| `asset_pointer` 为 `file-service://...` 或 `sediment://...` | 指向可解析图片资源 |
## 图片指针类型
| 指针 | 常见来源 | 说明 |
|:--|:--|:--|
| `file-service://file_xxx` | 图片工具输出 | 可通过文件下载接口解析 |
| `sediment://file_xxx` | 输入附件或图片工具输出 | 需要结合消息角色判断来源 |
| `file_upload` | 上传过程占位 | 通常不应作为输出 |
不要只凭字符串里出现 `file_` 或 `sediment://` 就判定为输出图。必须结合消息角色和任务类型。
## 策略拒绝场景
当上游拒绝请求时,通常不会产生图片工具消息,而是返回普通 assistant 文本:
```text
I can't assist with that request. If you have another type of modification...
```
常见伴随事件:
```json
{"type":"title_generation","title":"Request Denied","conversation_id":"..."}
```
```json
{
"type": "server_ste_metadata",
"metadata": {
"tool_invoked": false,
"turn_use_case": "multimodal",
"did_prompt_contain_image": true
},
"conversation_id": "..."
}
```
处理要点:
| 条件 | 行为 |
|:--|:--|
| 有 assistant 拒绝文本 | 应返回文本消息 |
| `tool_invoked == false` | 说明没有实际工具结果 |
| 没有 `role=tool` 且 `async_task_type=image_gen` 的消息 | 不应收集输出图片 |
| 用户输入消息里有图片指针 | 仍然只视为输入附件 |
## moderation 场景
部分请求可能返回 moderation 事件:
```json
{
"type": "moderation",
"moderation_response": {
"blocked": true
},
"conversation_id": "..."
}
```
若 `blocked == true`,应认为本轮被策略拦截。后续如有 assistant 文本,应优先返回该文本;若没有文本,可返回合适的错误信息。
## marker 和 title 事件
上游会返回一些辅助事件:
```json
{"type":"message_marker","marker":"user_visible_token","event":"first"}
{"type":"message_marker","marker":"last_token","event":"last"}
{"type":"title_generation","title":"...","conversation_id":"..."}
```
这些事件通常用于前端展示、标题生成或流式状态标记,不代表实际文本内容或图片结果。
## metadata 事件
`server_ste_metadata` 用于描述本轮调度和工具状态:
```json
{
"type": "server_ste_metadata",
"metadata": {
"tool_invoked": true,
"turn_use_case": "multimodal",
"model_slug": "i-mini-m",
"did_prompt_contain_image": true
}
}
```
常用判断:
| 字段 | 说明 |
|:--|:--|
| `tool_invoked == true` | 上游认为本轮调用过工具 |
| `tool_invoked == false` | 上游未调用工具,常见于拒绝或纯文本响应 |
| `turn_use_case == "text"` | 按文本响应处理 |
| `turn_use_case == "multimodal"` | 多模态请求,不代表一定有图片输出 |
| `did_prompt_contain_image == true` | 输入包含图片,不代表输出包含图片 |
## 结束后的结果判断
SSE 结束后可按以下顺序判断结果:
1. 如果已经收集到图片工具输出指针,解析并下载输出图片。
2. 如果没有输出图片指针,但有 assistant 文本,并且本轮被拦截或未调用工具,返回文本消息。
3. 如果没有输出图片指针,但有 `conversation_id`,可查询完整会话明细,继续寻找图片工具输出。
4. 查询完整会话时,仍然只读取 `role=tool` 且 `async_task_type=image_gen` 的消息。
5. 如果没有图片结果也没有文本,返回上游异常或空结果错误。