新增美团 CPS 券定时抓取入库(北京试点),作为"销量/佣金排序"的本地数据源 #18

Merged
marco merged 5 commits from intern/chenshuobo/meituan-coupon-etl-20260606 into main 2026-06-08 00:16:26 +08:00
Owner

背景:美团搜索/供给对销量排序支持差(实测乱序)、且有 402 限流和单次召回上限,不适合
每次实时打接口排序。改为定时把券抓进本地 meituan_coupon 表,查询时从库里捞、自己按
销量/佣金排。

本次内容:

  • app/models/meituan_coupon.py:新表模型。字段尽量全(售价/原价/销量档/佣金率/佣金额/
    门店/距离/品牌/图 等),raw 列存整条原始返回避免漏字段;(source, product_view_sign) 唯一。
  • alembic/versions/meituan_coupon_table.py:建表迁移(挂在 withdraw_review_ad_watch 之后)。
  • scripts/pull_meituan_coupons.py:ETL,抓 3 路并按 (source, product_view_sign) upsert:
    1. 外卖·搜"外卖"(platform=1)翻到尽头
    2. 外卖·搜"美食"(platform=1)翻到尽头
    3. 到店·多业务线供给(到餐+到综+酒店+门票)翻到尽头
      支持 --once(单轮,给 cron;线上每 1h)/ --loop --interval(本地循环,默认 10min)
    • 运行锁防重叠 + --prune-hours 清理陈旧券(默认 24h)。
  • app/models/__init__.py:注册新模型。

实测:北京一轮约 2.5 分钟、入库约 2700 条;销量/佣金可直接从库里排序。

给接手同事:

  • 仅北京(city_id 固定);v2 再加 per商圈 union 突破全城单次召回上限。
  • 销量仅粗档位且约 51% 的券才有,查询需 WHERE sale_volume_num IS NOT NULL
    (PG 的 DESC 默认把 NULL 排最前);佣金、价格 100% 有值。
  • productViewSign/skuViewId 跨渠道会变,不能当全局 id;跨源去重用 dedup_key=md5(品牌|名|价)。
  • 待做:查询接口(从库捞 + dedup_key 去重 + 按销量/佣金排,返回前端)。

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

背景:美团搜索/供给对销量排序支持差(实测乱序)、且有 402 限流和单次召回上限,不适合 每次实时打接口排序。改为定时把券抓进本地 meituan_coupon 表,查询时从库里捞、自己按 销量/佣金排。 本次内容: - app/models/meituan_coupon.py:新表模型。字段尽量全(售价/原价/销量档/佣金率/佣金额/ 门店/距离/品牌/图 等),raw 列存整条原始返回避免漏字段;(source, product_view_sign) 唯一。 - alembic/versions/meituan_coupon_table.py:建表迁移(挂在 withdraw_review_ad_watch 之后)。 - scripts/pull_meituan_coupons.py:ETL,抓 3 路并按 (source, product_view_sign) upsert: 1) 外卖·搜"外卖"(platform=1)翻到尽头 2) 外卖·搜"美食"(platform=1)翻到尽头 3) 到店·多业务线供给(到餐+到综+酒店+门票)翻到尽头 支持 --once(单轮,给 cron;线上每 1h)/ --loop --interval(本地循环,默认 10min) + 运行锁防重叠 + --prune-hours 清理陈旧券(默认 24h)。 - app/models/__init__.py:注册新模型。 实测:北京一轮约 2.5 分钟、入库约 2700 条;销量/佣金可直接从库里排序。 给接手同事: - 仅北京(city_id 固定);v2 再加 per商圈 union 突破全城单次召回上限。 - 销量仅粗档位且约 51% 的券才有,查询需 WHERE sale_volume_num IS NOT NULL (PG 的 DESC 默认把 NULL 排最前);佣金、价格 100% 有值。 - productViewSign/skuViewId 跨渠道会变,不能当全局 id;跨源去重用 dedup_key=md5(品牌|名|价)。 - 待做:查询接口(从库捞 + dedup_key 去重 + 按销量/佣金排,返回前端)。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
marco added 1 commit 2026-06-06 23:26:30 +08:00
背景:美团搜索/供给对销量排序支持差(实测乱序)、且有 402 限流和单次召回上限,不适合
每次实时打接口排序。改为定时把券抓进本地 meituan_coupon 表,查询时从库里捞、自己按
销量/佣金排。

本次内容:
- app/models/meituan_coupon.py:新表模型。字段尽量全(售价/原价/销量档/佣金率/佣金额/
  门店/距离/品牌/图 等),raw 列存整条原始返回避免漏字段;(source, product_view_sign) 唯一。
- alembic/versions/meituan_coupon_table.py:建表迁移(挂在 withdraw_review_ad_watch 之后)。
- scripts/pull_meituan_coupons.py:ETL,抓 3 路并按 (source, product_view_sign) upsert:
  1) 外卖·搜"外卖"(platform=1)翻到尽头
  2) 外卖·搜"美食"(platform=1)翻到尽头
  3) 到店·多业务线供给(到餐+到综+酒店+门票)翻到尽头
  支持 --once(单轮,给 cron;线上每 1h)/ --loop --interval(本地循环,默认 10min)
  + 运行锁防重叠 + --prune-hours 清理陈旧券(默认 24h)。
- app/models/__init__.py:注册新模型。

实测:北京一轮约 2.5 分钟、入库约 2700 条;销量/佣金可直接从库里排序。

给接手同事:
- 仅北京(city_id 固定);v2 再加 per商圈 union 突破全城单次召回上限。
- 销量仅粗档位且约 51% 的券才有,查询需 WHERE sale_volume_num IS NOT NULL
  (PG 的 DESC 默认把 NULL 排最前);佣金、价格 100% 有值。
- productViewSign/skuViewId 跨渠道会变,不能当全局 id;跨源去重用 dedup_key=md5(品牌|名|价)。
- 待做:查询接口(从库捞 + dedup_key 去重 + 按销量/佣金排,返回前端)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Ghost added 3 commits 2026-06-07 23:22:25 +08:00
mentor 指出筛选放前端不合理:前端只能筛"已加载的几十条",不是完整池子。改为 /feed 加 tab 参数,
后端按 tab 处理后返回,前端只渲染:
- tab=rec(智能推荐):榜单混合 feed 过滤掉佣金率 < 3%(分页)
- tab=distance(距离最近):拉齐全部榜单轮次,在【完整池】上全局按距离由近及远排,一次性返回(has_next=False)
- 留空/其它:返回原混合 feed 不筛(老客户端兼容;新 app 会显式传 tab)
(销量最高走 /coupons 同城热销,已是后端,不在本次)

实测北京:distance 拉到 118 条且全局升序;rec 第1页佣金率全部 ≥3%。

改动:app/schemas/meituan.py(FeedRequest.tab)、app/api/v1/meituan.py(feed 按 tab 筛选/排序 + _commission_pct)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
本机/内网开发直连美团(media.meituan.com)会 SSL EOF,必须走本地代理;线上国内服务器直连正常。
- config.py 加 MT_CPS_PROXY(默认空)
- integrations/meituan.py 的 _call 改用 httpx.Client(proxy=MT_CPS_PROXY, trust_env=False):
  显式走配置的代理、不读进程环境 HTTP_PROXY(避免被失效代理误导)
- .env.example 注明:开发填 http://127.0.0.1:7897,线上留空=直连

效果:本地起后端不用再每次手动 set HTTP_PROXY,uvicorn 直接起即可。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
「销量最高」改为从本地离线库按销量降序返回,替代实时打美团同城热销(外卖只有~20条还波动):
- POST /api/v1/meituan/top-sales:WHERE sale_volume_num IS NOT NULL,按 sale_volume_num 降序、
  同销量再按 commission_percent 降序;用 dedup_key 跨源去重;用 raw(整条原始返回)重建 CouponCard,
  字段与实时接口完全一致,前端无需改渲染。
- schemas 加 TopSalesRequest(page / page_size / 可选 platform)

离线库由定时 ETL(scripts/pull_meituan_coupons.py)灌入(见本分支前序提交)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Ghost added 1 commit 2026-06-08 00:14:44 +08:00
main 新增 ops_marquee_seed/ops_stat_config/price_observation 等模型,本分支加 meituan_coupon,
两边都往 app/models/__init__.py 插导入 → 冲突,合并保留两边(按字母序)。
迁移分叉(本分支 meituan_coupon_table 头 vs main 的 opsrename01 头)→ 加 alembic merge 迁移
11a1d08c6f55 合两头,alembic upgrade head 恢复单头。
config.py / .env.example 自动合并(MT_CPS_PROXY 与 main 的 pricebot 多实例 / 内部密钥配置共存)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
marco merged commit ece41086cd into main 2026-06-08 00:16:26 +08:00
Sign in to join this conversation.
No Reviewers
No Label
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: WonderableAI/shaguabijia-app-server#18