70 lines
11 KiB
Markdown
70 lines
11 KiB
Markdown
# 技术栈(Tech Stack)
|
||
|
||
> “用什么”的统一速查表。选型与理由在此集中维护;“怎么把它们搭起来”见 [架构设计](04-architecture.md)。
|
||
> 未定项必须标为待定,不要让 agent 在代码里自行决定。
|
||
|
||
## 一、技术栈一览
|
||
|
||
| 维度 | 选型 | 状态 | 理由 / 说明 |
|
||
| --- | --- | --- | --- |
|
||
| 语言 | Python 3.12(锁定 `>=3.12,<3.14`) | 已定 | 复用 `cmbot` 的 Python AI 调用代码(cmbot 为 3.11+,向上兼容);3.12 稳定、库全、性能好,落在 Django 5.2 支持窗口内 |
|
||
| Web 框架 | Django 5.2 LTS | 已定 | 自带 ORM、迁移、admin,适合「API + 运营后台」;选 LTS 维护到 2028,安全更新窗口最长。**禁用已 EOL 的 4.0/4.1**(无安全补丁,资金服务不可用) |
|
||
| API 框架 | Django REST Framework (DRF) | 已定 | 鉴权、序列化、参数校验、限流现成 |
|
||
| 运营后台 | django-admin | 已定 | 近零代码即得用户/点数/记录的增删改查与检索,省 80% 后台工作量 |
|
||
| 用户端 | Django 模板 SSR + Bootstrap 5 + django-allauth + crispy-forms | 已定 | 自助注册/登录/充值/API Key 管理/记录页;allauth 出注册登录邮箱验证,crispy + 现成 Bootstrap 模板出页面,单体不引前端框架 |
|
||
| 后台美化 | django-unfold 或 simpleui | 待定 | 仅外观,MVP 可先用原生 admin,后期按需引入 |
|
||
| AI 上游对接 | **Provider 适配器层**(按 `api_type` 注册)+ **能力别名** 映射 + `requests` HTTP 客户端 | 已定 | 对外只暴露 `generate text/image` 两接口与别名;换供应商改后台映射,不动对外契约。移植 `cmbot` 的调用逻辑到各适配器。当前 3 模型机制不同:文本 chat、`nano-banana2` chat 多模态返图、`gpt-image-2` images/edits 改图(详见 `04` 3.1) |
|
||
| 供应商密钥存储 | 应用层 Fernet 加密(`cryptography`) | 已定 | `AiModel.api_key_encrypted` 加密入库、admin 写入型字段不回显;加密主密钥 `AI_KEY_ENCRYPTION_KEY` 走环境变量,配置清单见 `env.md` |
|
||
| 图片结果存储 | 对象存储(S3 兼容 / 本地存储)返回 URL | 待定 | 同步响应默认返回 `image_url`,避免大 base64 进响应体 |
|
||
| 配置变更审计 | django-admin LogEntry 或自建审计表 | 待定 | 模型/别名/密钥变更留痕,与「账目对得上」一致 |
|
||
| 数据库 | MySQL 8.4 LTS(cmhub 专用独立实例) | 已定 | 满足 Django 5.2 的 MySQL ≥8.0.11;引擎 InnoDB + 字符集 utf8mb4;行锁 `select_for_update` / 条件更新保并发扣点。**不复用 VPS 已有的 MySQL 5.7**(跑不了 Django 5.2、无 CHECK 约束)。开发亦用 MySQL,勿用 SQLite(不支持 `select_for_update`) |
|
||
| MySQL 驱动 | PyMySQL + cryptography | 已定 | PyMySQL 负责 Django 连接 MySQL;MySQL 8 默认 `caching_sha2_password` 认证需要 `cryptography` 支持 |
|
||
| 对外鉴权 | API Key(DRF 自定义 Authentication,哈希存储比对) | 已定 | 用户自助生成 Key;**API 只认 Key、不挂 SessionAuthentication**,防浏览器 cookie 绕过计费 |
|
||
| 用户端鉴权 | Django Session(+ allauth 注册登录邮箱验证) | 已定 | 用户端页面与 `recharge/create` 走 session + CSRF;后台账号也用 Session 登录 |
|
||
| 充值对接 | 自助扫码:微信 V3 native + 支付宝当面付;下单取二维码 + 服务端回调(验签 + 幂等) | 已定 | 库 `wechatpayv3` / `python-alipay-sdk`;协议对齐同支付系统 PHP 实现(见 `api.md`);仅商户密钥/证书待提供 |
|
||
| 生成返回方式 | 同步 HTTP(无任务队列) | 已定 | MVP 简化;图片接口需调大网关/服务超时 |
|
||
| 任务队列 | 暂不引入(Celery/RQ) | 待定 | V2 异步化时再评估 |
|
||
| 部署方式 | Docker + Gunicorn(gthread) + Nginx,单体 | 待定 | MVP 先 `runserver`;生产 Nginx 按路径把 `/api/generate/*`(图片长请求)与用户端页面**分流到不同 gunicorn/worker 池**,避免图片阻塞拖慢页面(见 `04-architecture.md` 5.1) |
|
||
| 测试 | Django 自带 `manage.py test`(unittest)/ 可选 pytest-django | 已定 | 先用内置 test runner,重点覆盖计费与回调 |
|
||
| 依赖管理 | 系统 Python 3.12 + pip + `requirements.txt` + `pyproject.toml` | 已定 | 不使用虚拟环境;Windows 用 `py -3.12`,Unix/WSL 用 `python3.12`;运行依赖仍由 `requirements.txt` 管理,`pyproject.toml` 只落地 `requires-python` 元数据;init 会显式校验解释器版本在 `>=3.12,<3.14` |
|
||
|
||
## 二、决策记录与演进
|
||
|
||
- **Django 而非 FastAPI**:核心收益是 django-admin 直接满足「运营后台」需求;FastAPI 需自建后台。代价是异步生态较弱,但 MVP 同步返回,不受影响。
|
||
- **锁定 Django 5.2 LTS + Python 3.12**:① 版本红线属安全而非性能——生文/图生图瓶颈在「等上游 + worker 并发 + 超时」,不在框架版本(详见 [架构设计](04-architecture.md) 5.1),故版本选择只按安全与维护窗口定;② Django 4.0/4.1 已 EOL、无安全补丁,涉资金服务禁用;4.2 LTS 支持窗口临近尾声,不从其起步;5.2 LTS 维护到 2028,窗口最长。③ Django 5.2 支持 Python 3.10–3.13,锁 3.12 取「稳定 + 库全 + 性能」的平衡,避开 3.10(临近 EOL)与 3.14(不在 5.2 官方矩阵)。T-001 已按用户要求固定使用系统 Python 3.12:Windows PowerShell 用 `py -3.12`,Unix/WSL 用 `python3.12`;T-004 起 init 脚本在安装依赖前显式断言运行解释器版本在 `>=3.12,<3.14`。
|
||
- **预付费点数而非实时查支付余额**:充值时按汇率把金额转点数存本地,解耦支付系统、降低调用延迟、并发扣减用本地数据库事务即可保证。代价是需处理充值幂等与对账。
|
||
- **稳定接口 + 可插拔供应商**:对外只 `generate text/image` 两接口 + 能力别名;具体模型在后台配置并经适配器调用。收益是换供应商对调用方零改动、计费按别名稳定、可加授权与故障转移;代价是需维护适配器层与别名映射。**调用方不绑具体模型 SKU**。
|
||
- **供应商密钥存储采用 Fernet 应用层加密**:T-102 已落地 `AiModel.api_key_encrypted`,密文带 `fernet:` 前缀;明文只在 admin 表单提交或调用 `resolve_alias()` 后进入内存,不入库、不回显。主密钥来自 `AI_KEY_ENCRYPTION_KEY`,生产不可随意更换,除非后续做密钥轮换。
|
||
- **同步生成而非任务队列**:MVP 不引入 Celery/Redis,降低复杂度;图片耗时长,靠调大超时支撑,V2 再异步化。
|
||
- **桌面端可不改、全同步接入**:cmbot 现有批处理引擎(后台线程池 + 进度/心跳/重试/停止)只需把 service 层 URL/密钥从直连中转站换成 cmhub 的 `base_url + API Key`,即可正常使用;`桌面端 → cmhub → 中转站` 多一跳不影响可用性,点数一致性反而更简单(一次请求闭环:预扣→同步调→成功/失败退点)。
|
||
- **同步可用的前提是「超时链路 + worker 容量」配对**,否则会「小量正常、上量假死」:① 每模型 `timeout_seconds` 设有限值(`ai_models.json` 现为 `0`,迁入须改);② Gunicorn `--timeout` 与网关 `proxy_read_timeout` 按最慢图片放大(别用默认 30s / 60s);③ worker/线程数按**峰值总并发**预留。详见 [架构设计](04-architecture.md) 第五节结论。
|
||
- **何时转 V2 异步**:worker 被长连接占满拖慢快接口/后台、接入方总并发明显上涨、或需要「关窗重连/任务持久化」体验——在此之前保持同步。
|
||
- **数据库:MySQL 8.4 LTS,cmhub 专用独立实例**:① 部署环境的 VPS 已装 MySQL 5.7 供其他服务用,但 5.7 跑不了 Django 5.2(需 ≥8.0.11)、已 EOL、且不支持 CHECK 约束,故**不复用**它;② 机器内存宽裕(`available` 7.4G),给 cmhub **单开一个 MySQL 8.4 LTS 实例**(独立端口/容器),与已有 5.7 完全隔离、互不影响;③ 选 8.4 LTS 取长维护窗口 + 完整 CHECK 约束(CHECK 需 MySQL ≥8.0.16 才真正生效);④ 强制 InnoDB + utf8mb4(5.7/老配置默认非 utf8mb4,prompt 的 emoji/生僻字会写失败);⑤ MySQL 默认隔离级别 REPEATABLE READ(不同于 PostgreSQL 的 READ COMMITTED),`select_for_update` 扣点仍安全,但计费实现按此语义验证;⑥ 开发环境同用 MySQL,不要用 SQLite——SQLite 会静默忽略 `FOR UPDATE`,并发扣点逻辑测不出来;⑦ 不在代码里写死只适配某一种库的 SQL。
|
||
- **用户端用 Django 模板 SSR 单体,不引前端框架**:需求含终端用户自助(注册/充值/API Key/记录),选 Django 模板 + Bootstrap + allauth 与后端同工程单体部署,复用 Django auth/session,开发部署最快、最契合单机 MVP;代价是交互不如 SPA,可后续加 HTMX。放弃 Vue/React 前后端分离(两套项目/部署,与单体 MVP 调性冲突)。用户模型:`User`(auth) 持登录态、`UserWallet` 持点数(扣点锁 wallet、与 auth 解耦)、`ApiKey`(User 1:N,哈希存储)。注册不送免费点数。
|
||
|
||
## 三、构建与运行命令
|
||
|
||
> 以下为当前真实命令;Windows 原生 PowerShell 使用 `py -3.12`,Unix/WSL 使用 `python3.12`。
|
||
|
||
| 用途 | 命令 |
|
||
| --- | --- |
|
||
| 安装依赖(Windows) | `py -3.12 -m pip install -r requirements.txt` |
|
||
| 安装依赖(Unix/WSL) | `python3.12 -m pip install -r requirements.txt` |
|
||
| 基础检查(Windows) | `py -3.12 manage.py check` |
|
||
| 基础检查(Unix/WSL) | `python3.12 manage.py check` |
|
||
| 测试(Windows) | `py -3.12 manage.py test` |
|
||
| 本地开发(Windows) | `py -3.12 manage.py runserver` |
|
||
| 创建后台管理员 | T-003 后执行 `py -3.12 manage.py createsuperuser` |
|
||
| 数据库迁移 | T-002 接入 MySQL 后执行 `makemigrations` / `migrate` |
|
||
| 导入 cmbot AI 模型配置 | `py -3.12 manage.py import_ai_models path\to\ai_models.json --create-default-aliases` |
|
||
| 格式化 / 静态检查 | `ruff check .`(待定,确定后写死) |
|
||
|
||
统一入口仍是根目录 `./init.ps1`(Windows)或 `./init.sh`(Unix/WSL)。T-001 阶段只做框架检查,不跑迁移;T-002 接入 MySQL 与自定义 User 后再启用迁移路径。
|
||
|
||
## 四、依赖纪律
|
||
|
||
- 新增第三方依赖前,先说明用途、替代方案和维护成本。
|
||
- 不确定的技术选型先更新本文,再进入代码(如 Celery、unfold、pytest)。
|
||
- 不允许同一职责并存两套方案(如两套鉴权、两套 HTTP 客户端)。
|
||
- 敏感配置(上游 api_key、支付密钥、SECRET_KEY、数据库密码)只走环境变量或后台配置,不写进代码与文档样例;变量名集中维护在 [`env.md`](env.md)。
|