BirkhoffLee commited on
Commit
a49e322
·
unverified ·
1 Parent(s): 90423c7

docs: 补充了 TODO

Browse files
Files changed (1) hide show
  1. TODO.md +123 -0
TODO.md ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # TODO: PDFMathTranslate-next 重构计划
2
+
3
+ 目标:在不引入过度复杂度的前提下,把当前单体 `gateway.py` 拆成可维护的小块,前端交互更稳、更清晰,后端任务和计费语义更可控。
4
+
5
+ 整个重构分三个阶段推进,每个阶段尽量做到“可随时上线”,避免大爆炸改动。
6
+
7
+ ---
8
+
9
+ ## 阶段 1:结构拆分(尽量零功能变更)
10
+
11
+ ### 1.1 后端模块化
12
+
13
+ - 在 `src/` 下拆出最小模块(文件名可根据实现微调):
14
+ - `auth.py`:用户加载、密码校验、Session 生成/校验相关逻辑。
15
+ - `storage.py`:`sqlite3` 初始化、连接管理、`_db_execute/_db_fetch*` 封装。
16
+ - `jobs.py`:任务表相关的增删改查函数(创建任务、更新任务、按用户查询任务等)。
17
+ - `billing.py`:计费记录写入与查询。
18
+ - `proxy.py`:内部 OpenAI 代理、模型路由表、上游调用逻辑。
19
+ - 调整 `gateway.py`:
20
+ - 只保留 FastAPI `app` 实例、路由注册、`startup/shutdown` 钩子。
21
+ - 业务实现从上述模块导入,避免在 `gateway.py` 内直接操作底层细节(例如直接写 SQL)。
22
+
23
+ ### 1.2 前端模板与静态资源拆分
24
+
25
+ - 创建前端资源目录(示例):
26
+ - `src/web/templates/login.html`
27
+ - `src/web/templates/dashboard.html`
28
+ - `src/web/static/dashboard.js`
29
+ - 将 `_LOGIN_HTML` 与 `_dashboard_page` 中的 HTML/CSS/JS 内容搬迁到对应文件:
30
+ - 登录页:只保留错误提示占位符(例如 `__ERROR_BLOCK__`)由后端替换。
31
+ - 控制台页:将 `<script>...</script>` 中 JS 拆到 `dashboard.js`,HTML 中只通过 `<script src="/static/dashboard.js"></script>` 引入。
32
+ - 不引入模板引擎,保持 KISS:
33
+ - 在后端用最简单的文件读取+`str.replace` 或 `format` 注入 `username/lang_in/lang_out`。
34
+ - 为模板文件路径增加最小封装函数,例如 `load_template("dashboard.html")`。
35
+
36
+ ### 1.3 HTTP 路由边界梳理
37
+
38
+ - 显式整理路由分组(哪一块由哪个模块负责),避免日后继续往一个文件堆:
39
+ - 认证相关:`/login`, `/logout`, `/_session` 类逻辑。
40
+ - 页面渲染:`/`(Dashboard)、`/login` HTML。
41
+ - 任务 API:`/api/jobs*`。
42
+ - 计费 API:`/api/billing*`。
43
+ - 内部 OpenAI API:`/internal/openai/v1/*`。
44
+ - 在代码注释中说明“这些路由不保证向后兼容,仅用于当前 Space 原型”,避免后续误用。
45
+
46
+ ---
47
+
48
+ ## 阶段 2:任务状态机 + 实时刷新
49
+
50
+ ### 2.1 后端任务状态机收敛
51
+
52
+ - 将任务状态限定为有限集合(例如):`queued/running/succeeded/failed/cancelled`。
53
+ - 抽象出状态迁移函数而不是在各处随意 `_update_job(status=...)`:
54
+ - 示例:`transition_job(job_id, event, **kwargs)`,内部根据 `event` 决定可接受的状态变化并写库。
55
+ - 常见事件:`queued`, `start`, `progress`, `finish_ok`, `finish_error`, `cancel_requested`, `cancel_immediate`, `restart_failed`。
56
+ - 对非法状态迁移(例如从 `succeeded` 再切回 `running`)直接记录错误日志并拒绝更新,避免数据乱掉。
57
+
58
+ ### 2.2 任务状态实时推送(SSE)
59
+
60
+ - 新增 SSE 端点(示例):`GET /api/jobs/stream`:
61
+ - 只推送当前登录用户的任务更新。
62
+ - 事件载荷最小化:`{id, status, progress, message, updated_at, artifact_urls}`。
63
+ - 考虑断线重连:可以用简单方案,从最新更新时间开始重拉最近 N 条记录补齐。
64
+ - 任务执行逻辑中,在关键状态变更点调用“事件推送”钩子:
65
+ - 入队、开始、进度更新、成功、失败、取消等。
66
+ - 保留原有 `/api/jobs` 列表接口用于页面初次加载与 SSE 失败时的兜底。
67
+
68
+ ### 2.3 前端状态机与 UI 行为统一
69
+
70
+ - 在 `dashboard.js` 中定义单一状态映射表,例如:
71
+ - `STATUS_CONFIG = { queued: {...}, running: {...}, succeeded: {...}, failed: {...}, cancelled: {...} }`
72
+ - 每个状态包含:显示文案、颜色/样式、可用操作(是否允许“取消”、是否有下载按钮等)。
73
+ - 将当前散落在 DOM 拼接里的逻辑统一改为基于 `STATUS_CONFIG` 渲染:
74
+ - 状态文本:`statusText(status)`。
75
+ - 按钮可见性:从 `STATUS_CONFIG[status].actions` 派生。
76
+ - 行样式(例如失败高亮红色、运行中高亮)。
77
+ - 使用 `EventSource` 订阅 `/api/jobs/stream`:
78
+ - 收到事件后更新内存中的 `jobs` 映射,并局部更新 DOM,而不是整表重绘。
79
+ - SSE 失败时回退到现有的轮询逻辑(例如每 10 秒调用 `/api/jobs`)。
80
+ - 调整轮询频率:
81
+ - 页面可见时降低频率或完全依赖 SSE。
82
+ - 页面不可见(`document.hidden === true`)时进一步降频或暂停轮询。
83
+
84
+ ---
85
+
86
+ ## 阶段 3:上传限制 + 计费语义修正
87
+
88
+ ### 3.1 上传与执行约束
89
+
90
+ - 为上传文件增加硬性大小上限:
91
+ - 定义常量或环境变量(如 `MAX_UPLOAD_MB`),默认例如 100MB。
92
+ - 在 `api_create_job` 中根据 `Content-Length` 或实际读取的字节数做校验,超���返回 413 / 400。
93
+ - 如可行,增加 PDF 页数或执行时长限制:
94
+ - 在任务启动时尝试读取 PDF 元信息,如失败则只按大小限制。
95
+ - 在 worker 中增加“最大执行时长”(例如 2 小时),超时标记为 `failed` 并附带错误信息。
96
+
97
+ ### 3.2 计费模型与前端展示
98
+
99
+ - 明确不同模型的计费行为:
100
+ - 对可以从上游拿到 `usage` 的 OpenAI 风格模型,保持当前“按 tokens 计价”的策略。
101
+ - 对 `SiliconFlowFree`/chatproxy 这类无法获取准确 usage 的模型:
102
+ - 方案 A:如果上游按请求提供大致的 token 数或成本,则在 `_forward_to_chatproxy` 中解析并写入 `usage_records`。
103
+ - 方案 B:如果无法获得 usage,就明确将该模型标记为“不计费模型”,后端不写 `usage_records` 或只写 0,并在前端加注释说明“本模型不产生可计费账单”。
104
+ - 前端账单页面文案调整:
105
+ - 在“我的账单”区域增加提示:哪些模型的账单是准确计费,哪些只是占位或不计费。
106
+ - 对 cost 为 0 的记录,明确展示为 “$0.000000(不计费模型)” 或类似说明,避免用户误解。
107
+
108
+ ### 3.3 内部代理观测性增强
109
+
110
+ - 在 `/internal/openai/v1/chat/completions` 与上游调用逻辑中添加更细的日志:
111
+ - 每次请求打出 request id(例如 `job_id+uuid`)、模型名、路由目标 URL、耗时、状态码。
112
+ - 将 chatproxy 调用失败原因分类(网络错误 / 非 2xx / JSON 解析失败 / 缺少字段等),方便排查。
113
+ - 对 OpenAI 上游响应中缺失 `usage` 字段的情况增加保护:
114
+ - 避免因字段缺失导致异常中断,对缺失 usage 的请求使用安全默认值(0 或 `prompt+completion` 推算)。
115
+
116
+ ---
117
+
118
+ ## 建议执行顺序与发布策略
119
+
120
+ - 阶段 1 完成后先发布一次,确保结构拆分无副作用,再继续后续阶段。
121
+ - 阶段 2 先在后端实现 SSE 和状态机,再逐步切换前端逻辑到 SSE,保留轮询兜底。
122
+ - 阶段 3 在引入限制和计费变更前,准备好简单的回滚方案(例如环境变量开关),以防止因阈值配置不当影响正常用户。
123
+