feat(compare): 外卖比价 2 端点透传到 pricebot-backend (food MVP)
仿 coupon_step 在 app/api/v1/compare.py 加纯 body 透传 2 端点(MVP 不鉴权,只读
device_id/trace_id/step 打日志,不做 schema 校验)。client /api/v1/{intent/recognize,
price/step} → backend 去掉 /v1 转发到 PRICEBOT_BASE_URL,接通外卖比价
client→server→pricebot-backend 链路。
- compare.py: _passthrough helper + intent/recognize + price/step
- config.py: PRICEBOT_COMPARE_TIMEOUT_SEC=60(意图识别大上下文 LLM、price/step
每帧 LLM,比领券 30s 长;对齐客户端 agent ApiClient 的 60s 读超时)
- main.py: 注册 compare_router
- tests/test_compare_proxy.py: 2 端点参数化测试(透传/5xx→502/不可达→502/坏 JSON→400)
- docs/api/{compare-intent-recognize,compare-price-step}.md + 更新 README 索引
- 待办与技术债.md P2 外卖 2 端点标 ✅(2026-05-27);电商 2 个待接(compare.py
加两行即可)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+4
-2
@@ -18,13 +18,15 @@
|
||||
| 5 | `POST /api/v1/auth/refresh` | 无 | [详情](./auth-refresh.md) |
|
||||
| 6 | `GET /api/v1/auth/me` | Bearer | [详情](./auth-me.md) |
|
||||
| 7 | `POST /api/v1/auth/logout` | Bearer | [详情](./auth-logout.md) |
|
||||
| 8 | `POST /api/v1/coupon/step` | Bearer | [详情](./coupon-step.md) |
|
||||
| 8 | `POST /api/v1/coupon/step` | 无 | [详情](./coupon-step.md) |
|
||||
| 9 | `POST /api/v1/meituan/coupons` | 无 | [详情](./meituan-coupons.md) |
|
||||
| 10 | `POST /api/v1/meituan/feed` | 无 | [详情](./meituan-feed.md) |
|
||||
| 11 | `POST /api/v1/meituan/referral-link` | 无 | [详情](./meituan-referral-link.md) |
|
||||
| 12 | `POST /api/v1/intent/recognize` | 无 | [详情](./compare-intent-recognize.md) |
|
||||
| 13 | `POST /api/v1/price/step` | 无 | [详情](./compare-price-step.md) |
|
||||
|
||||
> ⚠️ 美团三个接口当前**无鉴权**,且 `referral-link` 的 `sid` 允许客户端传值覆盖默认渠道——见各接口"备注"。
|
||||
> `coupon/step` 是后端**唯一需要 JWT 鉴权的业务接口**。
|
||||
> `coupon/step` 及外卖比价的 `intent/recognize` / `price/step` 都透传到 pricebot-backend,**MVP 阶段均不鉴权**(device_id 透传,待补 JWT——见各接口详情)。当前**所有业务接口均无鉴权**,只有 `/me`、`/logout` 需 Bearer。
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
# POST /api/v1/intent/recognize — 外卖比价 Phase 1 意图识别(透传到 pricebot)
|
||||
|
||||
> 所属:Compare 组(前缀 `/api/v1`,外卖比价) | 鉴权:**无(MVP 阶段不鉴权)** | [← 返回 API 索引](./README.md)
|
||||
|
||||
## 入参
|
||||
任意 JSON body,**不做 schema 校验**,原样透传给上游。后端仅从中读 `device_id`、`trace_id`、`step` 用于日志。
|
||||
客户端实际传源平台购物车页的无障碍树采集结果(pricebot 协议里的 `screens`:`cart_page_1` / `cart_page_2`)。
|
||||
|
||||
## 出参
|
||||
pricebot-backend 的响应**原样返回**(JSON object)。典型含 `result`(店名)、`calibration`(含 `source_platform_id` / `items` / `price`),客户端在 `step=0` 把它透传进 `/price/step`。
|
||||
|
||||
## 错误码
|
||||
- `400` body 不是合法 JSON
|
||||
- `502` pricebot 上游不可达(网络错误)或返回 5xx
|
||||
|
||||
## 说明
|
||||
把请求体原样转发到 `PRICEBOT_BASE_URL` 的 `/api/intent/recognize`(去掉 `/v1`,async httpx)。**一次比价只调一次**。真正的识别逻辑(剪枝 + 索引 + LLM)在 **pricebot-backend(另一个 repo,GoalEngine)**,本接口只是"透传壳"。
|
||||
|
||||
外卖比价由客户端无障碍引擎在源平台(淘宝闪购 / 美团 / 京东外卖)购物车页点悬浮球触发 → 调本接口拿 `query` + `calibration` → 进入 `/price/step` 循环。
|
||||
|
||||
⚠️ **MVP 阶段不鉴权**(同 `coupon/step`):`device_id` 透传给 pricebot 区分设备,后端拿不到 `user_id` → 行为暂绑不到登录用户。待补 JWT,见 [待办与技术债.md](../待办与技术债.md) P1。
|
||||
|
||||
**相关配置**:
|
||||
- `PRICEBOT_BASE_URL`(默认 `http://localhost:8000`)
|
||||
- `PRICEBOT_COMPARE_TIMEOUT_SEC`(默认 60s,意图识别是大上下文 LLM,比领券的 30s 长)
|
||||
@@ -0,0 +1,23 @@
|
||||
# POST /api/v1/price/step — 外卖比价 Phase 2 步进(透传到 pricebot)
|
||||
|
||||
> 所属:Compare 组(前缀 `/api/v1`,外卖比价) | 鉴权:**无(MVP 阶段不鉴权)** | [← 返回 API 索引](./README.md)
|
||||
|
||||
## 入参
|
||||
任意 JSON body,**不做 schema 校验**,原样透传给上游。后端仅从中读 `device_id`、`trace_id`、`step` 用于日志。
|
||||
客户端逐帧上报 `screen_state` + 上一步 `action_result`;`step=0` 还带 `query` + `calibration`(来自 Phase 1)。
|
||||
|
||||
## 出参
|
||||
pricebot-backend 的响应**原样返回**(JSON object)。含 `action`(tap / set_text / launch / wait / done…)、`continue`、`status`;最终 `done` 帧带 `comparison_results`(源 + 各目标平台到手价,按价升序)。
|
||||
|
||||
## 错误码
|
||||
- `400` body 不是合法 JSON
|
||||
- `502` pricebot 上游不可达(网络错误)或返回 5xx
|
||||
|
||||
## 说明
|
||||
把请求体原样转发到 `PRICEBOT_BASE_URL` 的 `/api/price/step`(去掉 `/v1`,async httpx)。**多轮循环**:客户端按返回的 `action` 操作手机、再上报下一帧,直到 `continue=false`。真正的目标驱动比价逻辑(多目标平台串行复现订单、读到手价、聚合排序)在 **pricebot-backend**,本接口只是"透传壳"。
|
||||
|
||||
⚠️ **MVP 阶段不鉴权**(同 `coupon/step`)。
|
||||
|
||||
**相关配置**:
|
||||
- `PRICEBOT_BASE_URL`(默认 `http://localhost:8000`;生产部署应与 pricebot-backend 同内网——比价一单 30~80 步、逐帧多一跳,走公网延迟会累积)
|
||||
- `PRICEBOT_COMPARE_TIMEOUT_SEC`(默认 60s,price/step 每帧都是 LLM)
|
||||
+18
-11
@@ -9,7 +9,7 @@
|
||||
|
||||
## P1 · 鉴权与用户绑定(最该补)
|
||||
|
||||
- **现状**:agent 系列接口 MVP 阶段**全部不鉴权**——领券 `coupon/step` + 比价 4 个(`intent/recognize`、`price/step`、`ecom/intent/recognize`、`ecom/step`)。落地时现有 `coupon-step` 路由的 `CurrentUser` 依赖要先去掉。
|
||||
- **现状**:agent 系列接口 MVP 阶段**全部不鉴权**。领券 `coupon/step` **已落地不鉴权**(✅ 已去掉 `CurrentUser` 依赖);比价 4 个(`intent/recognize`、`price/step`、`ecom/intent/recognize`、`ecom/step`)端点尚未建(见 P2),建时同样先不加鉴权。
|
||||
- **代价(为什么记这笔账)**:不验 JWT → 转发时 server 拿不到 `user_id` → agent 行为只能绑到 `device_id`(设备级),**采集不到"哪个用户领了/买了什么"的用户级画像**。而精准人群画像、私域分群运营是商业模式的核心资产,靠的就是这份用户级行为数据。`device_id` 仍照传(后端按设备串领券队列够用)。
|
||||
- **待补**:① agent 接口加 JWT 鉴权;② 建立 `device_id ↔ user_id` 绑定(登录后上报一次即可);③ 领券/比价记录按 user 维度落库。
|
||||
- **连带**:补鉴权后,客户端引擎 `ApiClient` 要接回 JWT(复用 app 现有 `AuthInterceptor` 思路:注入带鉴权头的 OkHttpClient)。
|
||||
@@ -18,20 +18,21 @@
|
||||
|
||||
## P2 · 引擎移植 · 后端转发层(本仓)
|
||||
|
||||
- **加 4 个比价透传端点**:`intent/recognize`、`price/step`、`ecom/intent/recognize`、`ecom/step`。仿 `coupon_step` **纯 body 透传、不加 Pydantic schema**(协议归 pricebot 校验,否则它一改字段本仓就得跟着改,白白耦合)。client `/api/v1/xxx` → 转发 backend `/api/xxx`(去掉 v1,同 `coupon_step`)。
|
||||
- **转发超时要调大**:`coupon_step` 现 `PRICEBOT_REQUEST_TIMEOUT_SEC=30`(领券单帧 wait 6s)。但意图识别是一次大上下文 LLM、`price/step` 每帧也是 LLM,可能 >30s;客户端 `ApiClient` 读超时是 60s。→ 转发超时对齐 60s,**待测 pricebot 各接口真实耗时**再定终值。
|
||||
- **比价透传端点**:仿 `coupon_step` **纯 body 透传、不加 Pydantic schema**(协议归 pricebot 校验,否则它一改字段本仓就得跟着改,白白耦合)。client `/api/v1/xxx` → 转发 backend `/api/xxx`(去掉 v1,同 `coupon_step`)。
|
||||
- ✅ **外卖 2 个已落地**(food MVP,2026-05-27):`intent/recognize` + `price/step`,在 `app/api/v1/compare.py`(不鉴权、超时 60s),测试 `tests/test_compare_proxy.py`,文档 `docs/api/compare-*.md`。
|
||||
- 电商 2 个待接:`ecom/intent/recognize` + `ecom/step`——放开电商 scene 时在 `compare.py` 加两行即可。
|
||||
- ✅ **转发超时已分离**(2026-05-27):比价用新增的 `PRICEBOT_COMPARE_TIMEOUT_SEC=60`(意图识别大上下文 LLM、price/step 每帧 LLM),与领券的 `PRICEBOT_REQUEST_TIMEOUT_SEC=30` 区分;真实耗时待真机实测再定终值。
|
||||
- **生产 server 与 backend 同内网**:`PRICEBOT_BASE_URL` 部署时设内网地址。比价是 30~80 步循环,每步多一跳,走公网延迟会累积。
|
||||
- **nginx body 上限**:比价 debug 包带 `screenshot`(webp base64,几百 KB)。若 debug 联调走线上域名经 nginx,注意 `client_max_body_size`(release 不带截图、debug 直连本地都无此问题,仅"debug 走域名"才撞)。
|
||||
|
||||
---
|
||||
|
||||
## P2 · 引擎移植 · 客户端(android 仓,在此备忘)
|
||||
## P2 · 引擎移植 · 客户端(android 仓)
|
||||
|
||||
- **无障碍身份统一为傻瓜比价**:服务名/图标自动继承 application(`<service>` 不单独设 label/icon);需显式改的 3 处文案——`accessibility_service_description`、前台常驻通知文案("PriceBot 正在待命"等)、`GuideCopy` 里引导高亮的系统列表条目名("PriceBot"→"傻瓜比价")。
|
||||
- **BuildConfig 包名**:代码里 `com.pricebot.app.BuildConfig` 的 import 必须改成本 app 包名,否则编译不过。
|
||||
- **领券入口**:首页"一键领券"从 `ComparingScreen` 假动画 → 真 `startCouponClaim()`。
|
||||
- **比价悬浮球**:`SUPPORTED_BIZ_PACKAGES`(购物 App 前台才显示悬浮球)逻辑照搬。
|
||||
- **权限引导融入 Compose**:把 pricebot `MainActivity` 里申请无障碍/悬浮窗/电池优化的逻辑抽出,接到傻瓜比价的 Compose 页(权限引导 Activity 那几个可照搬,改包名+文案)。
|
||||
**领券链路相关已完成**(详见文末「已解决」):无障碍身份改名、BuildConfig 包名、领券入口、SettingsScreen 权限卡、ApiClient 改址。剩余:
|
||||
|
||||
- ✅ **比价悬浮球(外卖)已接**(2026-05-27):`SUPPORTED_BIZ_PACKAGES` 收窄到 3 个外卖源(美团/淘宝闪购/京东外卖);scene 写死 food(`getSceneMode` 默认改「外卖比价」)。点球 → `startTask` → Phase1/2 → 比价结果悬浮窗,这条链客户端本就齐(随引擎移植搬入),本次只收窄入口 + 写死场景 + 接通 server。电商放开时再加回 PDD/抖音 + scene 选择。
|
||||
- **仿腾讯权限引导**:搬来的 `AccessibilityGuideActivity`/`PermissionGuide*`/`GuideOverlayService` 尚未接入口;当前是"跳系统设置页"最简版(SettingsScreen 权限卡 + 领券前检查已用)。体验后续可升级成仿腾讯浮层。
|
||||
- **类名可选改名**:`PriceBotService` 等用户不可见,保留无妨;想整洁可改 `ShaguaAccessibilityService`(牵动引用,不急)。
|
||||
|
||||
---
|
||||
@@ -48,9 +49,15 @@
|
||||
- **FloatingButton 死代码**:Running 面板已换成 ComposeView 承载 `CouponProgressPanel`(=复用 AgentFloat)。旧原生面板字段(`line1~4View`/`elapsedView`/`progressBarView`/`historyContainerView` 等)+ `updateStatus(StepStatus)` 里保留的那段更新逻辑 + `appendActionLine`/`markCurrentActionDone`/`markPlatformDone`/`addCancelButton` 全部 no-op,待删。
|
||||
- **ComparingScreen / CompResultScreen 弃用**:领券改走悬浮窗,不再走全屏假动画。`Routes.COMPARING` / `COMP_RESULT` 成死路由,连同两个 Screen 文件待删(`CouponPromptDialog` 已抽到 `ui/coupon/`,删 ComparingScreen 不影响它)。
|
||||
- **ApiClient 常量 unused**:`getBackendUrl()` 改用 `BuildConfig.BASE_URL` 后,`DEFAULT_BACKEND_URL`/`KEY_BACKEND_URL` 常量 unused,待清。
|
||||
- **权限引导是最简版**:缺权限时直接跳系统设置页(`ACTION_ACCESSIBILITY_SETTINGS` / overlay 设置)。搬来的仿腾讯引导(`AccessibilityGuideActivity`/`PermissionGuide*`)尚未接入,体验后续可升级。
|
||||
- **领券大数字语义**:悬浮窗左侧"已领券"大数字目前接 `progress.current`(正在领第几张),非"已成功数"。中间帧后端不回传已领明细,要精确需后端在 status.progress 加 `completed[]`(协议文档第四节已留扩展点)。
|
||||
- **正式版 versionCode 必须 > 占坑版线上最高**:占坑版(`shaguabijia-android`)与正式版同包名 `com.jishisongfu.shaguabijia` 原地覆盖。正式版当前 `versionCode=1`,真机占坑版是 5 → 同签名降级被 Android 拒装,**正式版无法覆盖更新线上占坑版用户**。上线前 versionCode 要提到 > 线上占坑版最高值。
|
||||
|
||||
## 已解决
|
||||
|
||||
(暂无)
|
||||
- ✅ **领券链路接通**(阶段 1):首页「去领取」→ `CouponPromptDialog` → 权限检查 → `startCouponClaim` → 循环 `/api/v1/coupon/step`;Running 悬浮窗换皮(ComposeView 承载 `CouponProgressPanel`/AgentFloat,`OverlayLifecycleOwner` 撑 Compose)。
|
||||
- ✅ **coupon/step 去鉴权**:去掉 `CurrentUser`,MVP 不鉴权(device_id 透传)。
|
||||
- ✅ **ApiClient 改址**:`BuildConfig.BASE_URL` + `/api/v1/` 前缀。
|
||||
- ✅ **SettingsScreen 权限卡**:5 项(无障碍/悬浮窗/录屏<API30/电池/自启动)真实检测 + 点击跳转 + 自启动无法检测态 + onResume 自动刷新 + 刷新按钮;逻辑抽到 `PermissionHelper`(HomeScreen 领券前检查复用)。
|
||||
- ✅ **无障碍身份统一傻瓜比价**:服务名/图标继承 app;`accessibility_service_description`/前台通知/`GuideCopy`/引导 Activity 里的 "PriceBot" 全改「傻瓜比价」;app 图标换成完整 `logo1`(adaptive 居中+黄边,不裁切)。
|
||||
- ✅ **GuideOverlayService 组件名 bug**:批量 sed 改包名误把无障碍服务 ComponentName 的 packageName 改成 `…shaguabijia.agent`(应是 applicationId `…shaguabijia`)→ 无障碍开启检测永远 false;改用 `PermissionHelper.isAccessibilityEnabled` 动态构造。
|
||||
- ✅ **BuildConfig 包名**:`com.pricebot.app.BuildConfig` import 改本 app 包名。
|
||||
|
||||
Reference in New Issue
Block a user