feat(web): 新增 Web 观测台(形态 A)+ 抽出 render/targets 共用层
- tcaptcha/web/:FastAPI + SSE + 零构建单页。把同步阻塞的 solve() 包成可观测 后台任务(工作线程 + 全局串行,因 onnxruntime session 非线程安全),用 logging.Handler 零侵入把 client 日志变成事件流;按靶子实测 min_interval 强制节流。 - tcaptcha/render.py:标注图(点击顺序编号 + 质心偏差)与点位量尺,CLI 与 web 共用。 - tcaptcha/targets.py:靶子表提为单一来源(含实测频控间隔 1ms=60s / mliev=3s)。 - fastapi/uvicorn 走 optional extra `web`,核心包零 web 依赖(带回归断言)。 - 修两个真 bug:hook 求解器时 args[0] 是实例自身(真入参从 args[1] 起); client 默认每次新建 solver,预热实例未被复用(每发重载 56MB ONNX)。 - 复验:icon/text/slider 三题型各拿到 errorCode=0;selftest 全绿;依赖隔离通过。 用法:uv run --extra web python -m tcaptcha.web.app
This commit is contained in:
@@ -121,5 +121,25 @@ run8 `[1,4,0]` → `1:0.998 / 4:1.0 / 0:1.0`)。
|
||||
* 1ms 抽到图标题约 1/6,190758559 约 1/10;脚本会按 `accept_kinds` 自动换题(`getsig` 不换题型,
|
||||
只有重新 `prehandle` 才换)。
|
||||
* 靶子会偶发 `Connection reset by peer`(两个靶子都遇到过),那不是判负,统计时要单列。
|
||||
* **1ms 不要连打**:8 连发最后一发触发 `12`(prehandle 累计 14 次)。回归测试用
|
||||
190758559,或对 1ms 拉开间隔。
|
||||
* **1ms 有 aid+IP 级频控**(2026-10-14 标定,实测三次):
|
||||
|
||||
| 打法 | 结果 |
|
||||
| --- | --- |
|
||||
| 间隔 4s × 12 发 | `0,0` + **`12` ×10**(只有前 2 发过;icon/text/slider 三种题型都被打到 12) |
|
||||
| 冷却 2min + 间隔 30s × 6 | **`12` ×6**(冷却不够) |
|
||||
| 冷却 25min + 间隔 60s × 4 | **`0` ×4** ✓(text×2 + slider×2) |
|
||||
|
||||
→ 频控**与题型无关、与 prehandle 次数无关**(每次都是 1 个 prehandle),只与短时间内的请求量有关。
|
||||
**用法:≥60s 一发、连续不超过约 2 发;回归测试一律用 190758559。**
|
||||
|
||||
### 5.1 三种题型在 1ms 上的实测("都能过吗")
|
||||
|
||||
修复轨迹后,三种题型**都拿到过 `errorCode=0`**(含 ticket),链路完好;失败全是频控:
|
||||
|
||||
| 题型 | 修复后成绩 | 备注 |
|
||||
| --- | --- | --- |
|
||||
| 图标 2408 | **7/8 = 0**(前 7 连 0) | 修复轨迹后首次连跑 |
|
||||
| 文字 2404 | 2/3 = 0;冷却后 2/2 = 0 | 与图标共用 collect 链路 |
|
||||
| 滑块 2401/2402 | 1/3 = 0;冷却后 2/2 = 0 | 拖动轨迹另算(不套 61 点) |
|
||||
|
||||
**注意**:成绩好坏取决于"打得多稀疏",不取决于题型——4 秒间隔连打时三种题型**一起**全 12。
|
||||
|
||||
@@ -184,6 +184,8 @@ crypto.build_collect(c1,traj,c2,sd,key) -> 4 段独立加密后拼接
|
||||
| 72 | **1ms 的 `12`/`50` 与"答案质量"无关**(判读图 + 分类器概率双证据) | ① `send_campaign.py --target 1ms --kind icon --n 8`(13:49–13:52):`0,0,0,0,None,12,12,12`;**三次 `12` 的 `solver_diag` 里每个目标类都有 top-1 概率 = 1.0 的候选**(run6 `[2,1,4]`→2:1.0/1:1.0/4:1.0;run7 `[8,9,11]`→8:1.0/9:1.0/11:1.0;run8 `[1,4,0]`→1:0.998/4:1.0/0:1.0)。<br>② `judge_icons.py` 判读图:8 次跑 **24/24 全部落在与提示同序的目标图标上**,`12` 那三次也一样(偏离 0~5px)。<br>③ 点击精度不区分 `0` 与 `12`:`0` 组的质心偏离均值 ≈2.1px、`12` 组 ≈2.4px。<br>④ 同一时段该 aid 在混合题型下 `12` ×6(三题型都不行)。→ **12 是包级/会话级,不是答案级** | 确证 |
|
||||
| 73 | **轨迹的 dt 分布曾与真机严重不符(真 bug,已修)—— 用户"位置没问题那就是轨迹被校验"的判断正确** | 把 4 份真机抓包 / **6 条成功轨迹**(360 个非首点 dt)全部解出汇总:<br>① **点数硬不变量:6/6 全是 61 点**,而旧实现随机 57~65;<br>② **dt 紧密聚集在 16~17ms**(13~20ms 占 79%,0~4ms 仅 0.28%),旧实现 0~16ms 占 50%、0~4ms 占 14% —— 每发一枪都自带时序指纹异常。<br>修复 `tcaptcha/telemetry/values.py`:`_sample_dt()` 按 6 条轨迹重拟合(13~20ms 占 78%)、新增 `_fit_points()` 把点选轨迹**钉死 61 点**(补齐用 `[0,0,dt]` 驻留点,**不能**复制最后位移点——否则净位移被放大,实测 166 vs 139.5)。<br>**修复后 A/B**:1ms 图标 **4/8=0 → 7/8=0**(前 7 连 0);文字 2/3=0、滑块 1/3=0(样本少)。回归:selftest 全绿 | 确证(真 bug + A/B 见效) |
|
||||
| 74 | **61 点不变量只属于点选轨迹,拖动轨迹不适用**(差点犯的错) | 修 61 点时曾把 `drag_trajectory_points`(滑块拖动)也套了 61 点 → 滑块测试立刻红(净位移 166 vs 139.5、点数 61 超范围)。**拖动是另一种交互(按下→横移→松手),61 点是从点选轨迹量出来的,不能外推**。已回退:拖动按 steps 走(实测 34 点、净位移 140≈139.5) | 确证(含一次自我纠错) |
|
||||
| 75 | **1ms 的残余 `12` = aid+IP 级频控,已标定窗口;冷却足够后三种题型全过** | 2026-10-14 实测(`send_campaign.py --kind any --interval N`,每次 `prehandle` 次数都是 1,排除"抽题太多次"这条):<br>① **间隔 4s × 12 发** → `0,0,12,12,12,12,12,12,12,12,12,12`(只有**前 2 发**过,之后 **10 连 12**;icon/text/slider **三种题型都被打到 12**);<br>② **冷却 2 分钟 + 间隔 30s × 6** → **6 发全 12**(冷却不够);<br>③ **冷却 25 分钟 + 间隔 60s × 4** → **4 发全 `0`**(text×2 + slider×2)。<br>→ 频控**与题型无关、与 prehandle 次数无关**,只与"短时间内的请求量"有关。**结论:1ms 必须低频使用(≥60s 一发、连续打不超过 ~2 发),回归测试一律用 190758559。** | 确证(含恢复验证) |
|
||||
| 76 | **Web 观测台上线**(形态 A:观测/调试台)+ 顺带抓到两个真 bug | 新增 `tcaptcha/web/`(FastAPI + SSE + 零构建单页)、`tcaptcha/render.py`(标注图 + 点位量尺,**CLI 与 web 共用**)、`tcaptcha/targets.py`(靶子表,含**实测频控间隔**)。设计要点:`solve()` 同步阻塞 → 工作线程 + **全局串行**(onnxruntime session 非线程安全);用 `logging.Handler` **零侵入**把 client 的日志变成事件流;按靶子 `min_interval` 强制节流。<br>**bug ①**:hook 求解器时把 `args[0]` 当成了题目图 —— 实例方法调用时 `args[0]` 是**求解器实例自身**(真入参从 `args[1]` 起),于是 `'CaptchaSolver' object has no attribute 'convert'`,标注图与点位全丢。<br>**bug ②**:`TencentCaptchaClient` 默认**每次新建** solver,预热加载的实例根本没被复用(每发重载 56MB ONNX)→ 改为把缓存实例传进 `solver=` / `text_solver=`。<br>另:滑块硬套"离笔画质心"量尺会给出 10~40px 噪声(滑块答案是缺口位置),已对滑块置 None。<br>复验:icon/text/slider **三题型各拿到 `errorCode=0`**;SSE 事件序列 + 3 张图全部可取;`import tcaptcha` **不引入 fastapi**(依赖隔离) | 确证 |
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user