AAA-EE / mcd-budget-planner
git clone https://github.com/AAA-EE/mcd-budget-planner.git
—
+67
stars, 24h · #584
+~469
stars, 7 days · #463
+464
stars, 30 days · #1,769
464
★ total · +469% this week
30
forks · 0 open issues
Star history (as recorded here)
LanguagePython
LicenseMIT
Created2026-10-09 (14d ago)
Last push2d ago
Watchers0
OwnerUser
Links
README excerpt
# 麦麦省钱营养师 · MCD Budget Planner **「我想吃麦当劳,但想控钠 / 想花 30 块以内 / 别浪费我的券」——说人话,它算出实付最省的组合。** 基于麦当劳 MCP Server 的「预算 + 营养」双约束套餐优选 Skill。 不是券列表查询器,是**点餐决策器**:把「省钱的券」和「健康的餐」放在一起求解。 ### 🎮 **在线试算 → 打开即玩,无需安装** 拖动「预算」和「钠上限」两个滑块,实时算出实付最省且钠可控的组合, 下方同步显示**价格 × 钠的帕累托前沿**。页面算法与仓库内 Python 实现通过 前后端对拍校验,两边结果必须完全一致,否则 CI 会失败。 上图由 `tools/make_preview.py` 依真实求解结果矢量复刻,非截图。 所有数值来自 `optimizer` 的实际计算:预算 ¥30、钠 ≤1200mg 时, 最省方案为麦香鸡 ¥17.00 / 731mg。 --- ## 30 秒看懂 [code] **这条回复背后是 6 次 MCP 调用**,包括门店定位、券可用性二次核验、 带券价格试算(拿到真实 `couponId` 而不是估算),再叠加 158 项营养数据的约束求解。 --- ## 为什么需要它:两个反直觉的实测发现 ### 发现一:卡包里有券 ≠ 此刻能用 联调时实测某用户卡包有 **14 张券**,但在同一时刻、同一门店, `query-store-coupons` 只认得出 **1 张**: | 数据源 | 返回 | |---|---| | `query-my-coupons`(卡包资产) | 14 张「可用」券 | | `query-store-coupons`(同门店同场景) | **1 张** | 差的 10 张是早餐券,有效期限定每日 `05:00–10:29`,而查询时刻是 18:23。 **MCP 文档明确声明 `query-my-coupons` 不做门店、渠道、场景校验**—— 返回的是「我拥有的」,不是「我能用的」。 > 由此得出本项目最关键的一条约束:**券可用性必须以门店维度二次确认为准, > 不得用卡包数据直接推导。** 顺序反了,整个逻辑就是错的。 ### 发现二:营养差异有三个数量级 MCP 营养接口返回 158 项餐品,钠含量跨度极大: | 餐品 | 钠含量 | |---|---| | 纯悦 / 可乐 | **0 mg** | | 火腿扒麦满分 | 608 mg | | 巨无霸 | 961 mg | | 麦辣鸡腿汉堡 | 1208 mg | | 芝士双层安格斯厚牛堡 | **1373 mg** | 一份巨无霸的钠含量是中杯可乐的上千倍。但这些数据以紧凑字符串形式返回, 用户既看不懂,也没法用来做选择。 **本项目做的事**,是把这两类数据交叉起来 —— 让省钱和健康能同时被满足, 而不是二选一。 --- ## 核心能力 | 能力 | 说明 | |---|---| | 🎫 真实可用券核验 | 不轻信卡包数据,以门店维度二次确认券是否真的能用 | | 💰 本地定价引擎 | 菜单标价 + 券规则 + 叠加冲突判定,算价不依赖远程接口 | | 🥗 营养约束求解 | 支持控钠 / 控热量 / 高蛋白 / 高钙多维约束组合枚举 | | 📉 价格 × 钠 帕累托前沿 | 回答「想再便宜就得吃多少钠」这条边界的形状 | | 🔄 同类替代建议 | 「我就想吃巨无霸」→ 同类里有没有更便宜又更少钠的 | | 🏪 四种场景适配 | 到店自取、得来速、麦乐送、企业团餐 | | 🔒 安全边界 | 止步于试算,不自动下单;积分抽奖只算不动 | ### 为什么是「价格 × 钠」,不是「价格 × 热量」 热量是常见维度,但钠更值得关注:中国居民钠摄入普遍超标, 而一份巨无霸的钠含量(961mg)已接近每日建议上限(约 2000mg)的一半。 这个维度上的差异是**数量级**的,不是边际的: | 餐品 | 价格 | 钠 | 热量 | |---|---|---|---| | 纯悦 | ¥7.50 | **0mg** | 0kcal | | 麦香鱼 | ¥22.50 | 556mg | 325kcal | | 麦辣鸡腿汉堡 | **¥22.50** | **1208mg** | 485kcal | | 巨无霸 | ¥25.50 | 961mg | 513kcal | | 双层吉士汉堡 | ¥23.00 | 1017mg | 429kcal | | 芝士安格斯厚牛堡 | ¥31.50 | **1373mg** | 1003kcal | 注意第二行和第三行:**同为 ¥22.50,钠含量差 2.2 倍**。 同样的钱,选哪个更值得,这就是本项目要回答的问题。 --- ## 在线页面 `docs/index.html` 是单文件应用,无后端、无构建、无依赖, 直接部署到 GitHub Pages 即可访问。 页面内嵌: - 41 项「同时具备价格与营养」的餐品数据 - 券的有效期 / 适用星期 / 时段判定逻辑 - 与 Python 完全一致的组合枚举与帕累托求解 **前后端一致性怎么保证**:两份实现独立存在,难免漂移。 `tools/parity_check.mjs` 从 `index.html` 中抽取 JS 算法, 在最小 DOM 桩下执行,用与 Python 相同的 7 组输入跑一遍, 比对帕累托前沿是否逐点一致。CI 中这一步失败即构建失败。 [code] ### 部署到 GitHub Pages 1. 仓库 **Settings → Pages** 2. Source 选 `Deploy from a branch` 3. Branch 选 `main`,目录选 `/docs` 4. 保存后约 1 分钟可访问 `https:// .github.io/mcd-budget-planner/` CI 中有一项检查:若 `docs/` 与 `python tools/build_site.py` 的生成结果不一致, 构建会失败并提示重新生成。这样可以避免改了数据却忘记重建页面。 --- ## 快速开始 ### 方式一:离线体验(无需 MCP、无需网络) [code] `examples/demo_optimize.py` 的核心输出: [code] ### 方式二:作为 WorkBuddy Skill 使用(完整体验) 将`skills/mcd-deal-gen/` 目录复制到 `~/.workbuddy/skills/` 后: [code] 重启会话后,用自然语言触发: [code] Skill 会自动完成:场景确认 → 门店定位 → 券可用性核验 → 餐品与营养匹配 → 带券试算 →排序输出。 ### 方式三:调用试算任务生成器 [code] 输出(已实测与真实成功调用的参数完全一致): [code] --- ## 项目结构 [code] --- ## 算法说明 ### 三个模块的分工 [code] 拆开的理由是:定价逻辑需要密集测试(券时段、星期、叠加规则都