npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@harrylabsj/chichulaide

v0.1.1

Published

吃出来的 AI 后端代理服务

Readme

吃出来的 AI 后端代理

这是 App 的本地/服务器端 AI 代理。App 只调用这个代理,模型 API Key 放在后端环境变量里,不放在手机里。

结论

  • Claude 视觉模型可以通过 Anthropic API 调用,但当前 App 不能直接调用。App 现在只会调用你配置的后端代理。
  • DeepSeek 官方 deepseek-v4-pro 是文本/推理模型,官方模型表没有标注图像输入能力,不适合作为拍照识别模型。
  • 拍照识别推荐国内视觉模型:阿里云百炼 qwen-vl-plus 或智谱 glm-4.5v。本代理默认使用 qwen-vl-plus 做图片识别,deepseek-v4-pro 做文本解析。

启动

开发模式先用 mock,不需要 API Key:

cd ai_backend
node src/server.mjs

本地真机测试建议使用根目录脚本,方便后台运行和查看状态:

# 在项目根目录
scripts/ai-backend-start.sh
scripts/ai-backend-status.sh
scripts/ai-backend-stop.sh

等价 npm 命令:

cd ai_backend
npm run dev:start
npm run dev:status
npm run dev:stop

脚本会把 pid 和日志写到根目录 .runtime/。该目录已被 git 忽略。

健康检查:

curl http://127.0.0.1:8787/health

文本解析:

curl -X POST http://127.0.0.1:8787/v1/meal/parse-text \
  -H 'Content-Type: application/json' \
  -d '{"text":"午餐一个鸡蛋两个馒头三个肉饼","foods":[{"id":"egg","name":"鸡蛋","aliases":["水煮蛋"],"defaultAmount":1},{"id":"steamed_bun","name":"馒头","aliases":[],"defaultAmount":1},{"id":"meat_patty","name":"肉饼","aliases":[],"defaultAmount":1}]}'

连接真实模型

阿里云百炼千问视觉:

cd ai_backend
AI_PROVIDER=dashscope \
AI_PROVIDER_API_KEY=你的百炼APIKey \
AI_TEXT_MODEL=deepseek-v4-pro \
AI_VISION_MODEL=qwen-vl-plus \
APP_AI_TOKEN=可选的App访问令牌 \
node src/server.mjs

智谱 GLM-4.5V:

cd ai_backend
AI_TEXT_PROVIDER=deepseek \
AI_VISION_PROVIDER=bigmodel \
AI_PROVIDER_API_KEY=你的APIKey \
AI_TEXT_MODEL=deepseek-v4-pro \
AI_VISION_MODEL=glm-4.5v \
node src/server.mjs

如果文本和视觉来自不同厂商,建议部署两个代理或后续拆成 AI_TEXT_API_KEY / AI_VISION_API_KEY。当前 MVP 先保持一个 API Key,便于本地测试。

App 配置

模拟器访问本机:

  • http://127.0.0.1:8787

iPhone 真机访问 Mac:

  • 确保手机和 Mac 在同一 Wi-Fi。
  • 查看 Mac 局域网 IP,例如 ipconfig getifaddr en0 || ipconfig getifaddr en1。
  • ai_backend/.env 里把 HOST 设为 0.0.0.0。
  • 在 App「我的」→「AI 服务」填写 http://<Mac局域网IP>:8787。
  • 如果设置了 APP_AI_TOKEN,访问令牌填写同一个值。
  • iOS MVP 真机测试保留局域网 HTTP;正式发布前后端应使用 HTTPS。
  • Android release 默认只允许 HTTPS 和 localhost HTTP;局域网 HTTP 仅保留在 debug/profile 配置。

也可以在构建时注入配置:

flutter build ios --release \
  --dart-define=AI_BACKEND_URL=http://<Mac局域网IP>:8787 \
  --dart-define=AI_BACKEND_TOKEN=<APP_AI_TOKEN>

API

与根目录 docs-ai-backend-proxy.md 保持一致:

  • POST /v1/meal/parse-text
  • POST /v1/meal/recognize-image

WorkBuddy 饮食教练 API(兼容/调试入口)

注意:v0.1 起 WorkBuddy Skill chichulaide-meal-review 为包内本地确定性计算(模块与 373 条食物数据随包上传,离线自包含),运行时不依赖本后端;部署本服务不是 Skill 上线或 Gate 0 的前置条件。下面两条 API 保留作兼容与本地调试入口(例如对比 Skill 本地输出与后端是否一致),与 Skill 共用同一份领域模块源码,输出语义完全一致。

面向 WorkBuddy Skill 的无状态接口,确定性计算,不调用外部模型,不记录 profile、mealText 或 token:

  • POST /v1/workbuddy/daily-targets:用最少个人信息(性别、年龄、身高、体重、活动水平、目标)估算每日营养所需。严格校验 profile:缺字段/非法枚举返回 400;出现 name、phone、city、idCard、medicalRecord 等无关敏感字段也返回 400。安全转介(未成年、孕哺)返回 dailyTargets: null、energy: null、confidence: "low",不用成人 Mifflin 公式给数值;肾功能关注为 caution,仍返回保守目标。
  • POST /v1/workbuddy/meal-review:接收 profile、mealText(中文文字描述)、可选 mealType、todayBefore(当天此前已累计营养)和 dayComplete(当天记录是否已经完成),返回 dailyTargets、recognizedItems、unrecognizedSegments、mealNutrition、daySoFar、assessment、action、assumptions、confidence、safety。每次只返回一个主要问题和一个行动原则(2–3 个中式饮食例子)。

评估范围(basis-aware):

  • 未提供 todayBefore:assessment.scope = "meal",只评价当前这一餐,对照餐次参考份额(assessment.comparisonTargets = dailyTargets × 份额;早餐 25%、午餐 35%、晚餐 35%、加餐/夜宵 10%、未指定 33%)。单餐只标记明显过量(高脂/高钠按超出倍数取优先、高热量)与内容风险,不输出“今天蛋白质不足”这类全天判断;status 同样只表达过量:proteinG/carbsG/fiberG 固定为 null(单餐不评估不足),calories/fatG/sodiumMg 用上限型分类。
  • 提供 todayBefore:assessment.scope = "day",按截至目前累计评估。默认只判断明显过量,proteinG/carbsG/fiberG 状态为 null;只有同时提供 dayComplete: true,明确当天记录已经完成后,才判断 protein_low/fiber_low 等全天不足。
  • safety.level = "refer" 时真实停止建议:assessment.type = "safety_referral"、status: null、action.examples = [],只给转介原则;保留已识别餐食与 mealNutrition。
  • confidence 按最低可信度聚合:识别条目默认为 medium,整体通常为 medium;无识别或含低可信条目(标记“估算误差大”)时为 low,当前不产生 high。

未识别的食物只列入 unrecognizedSegments,不编造营养数字。安全分流规则(未成年、孕哺、进食障碍、急性症状、诊断/停药请求、肾异常)见 workbuddy/skills/chichulaide-meal-review/references/safety-boundaries.md。

领域层在 src/workbuddy/,与 Flutter App 的 lib/core/(UserProfile、EnergyEngine、NutritionTargetEngine、FoodTextParser、营养汇总、RecommendationEngine)核心规则对齐;改动 Flutter 行为不属于本层职责。有意分歧:多食物分段时 Node 端会剥掉下一个食物的引导份量词(Dart 端保留原行为),并支持“鸡蛋2个”这类食物后数量。

示例:

curl -X POST http://127.0.0.1:8787/v1/workbuddy/meal-review \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $APP_AI_TOKEN" \
  -d '{"profile":{"gender":"male","age":35,"heightCm":175,"weightKg":80,"activityLevel":"light","goal":"fatLoss"},"mealText":"一碗米饭,一份红烧肉","mealType":"lunch"}'

食物库导出与 Skill 同步

WorkBuddy 接口内置加载 ai_backend/data/food-database.json,由 App 的食物库确定性导出(373 个食物):

# 在项目根目录
dart run tool/export_food_database.dart

lib/data/seed_foods.dart 或 lib/data/expanded_chinese_foods.dart 变更后需重新导出。领域模块(src/workbuddy/)或食物库变更后,还需同步到 Skill 包内:

node tool/sync_workbuddy_skill.mjs

npm test 会断言 Skill 包内副本与源逐字节一致。

WorkBuddy Skill 与专家

Skill(含调用脚本、包内计算模块与食物数据、schema、安全边界、示例)和专家系统提示词在根目录 workbuddy/,详见 workbuddy/README.md。

Pay Skill 支付入口(代码完成,待凭证/部署/实机联调)

POST /v1/workbuddy/pay/invoke:付费版 Skill(workbuddy/skills/chichulaide-meal-review-pay)的统一履约入口,body 固定为 {"operation":"daily-targets"|"meal-review","payload":{...}},首次与重试的 body 必须完全一致;首次请求还必须带 Idempotency-Key,生产请求需使用独立的 CHICHULAIDE_PAY_SOURCE_TOKEN 完成来源认证。

流程(SkillHub 官方商户改造最佳实践 + 微信支付 V3):

  1. 无 X-Out-Trade-No:先做领域预检(输入非法 400;安全转介 422 NOT_ELIGIBLE_FOR_PAID_REVIEW;无识别食物 422 INSUFFICIENT_INPUT,均不创建订单、不调支付通道)→ 微信 Native 下单(含必填 appid、notify_url)得 code_url → SkillHub X402 preorder 得 payment_code → 返回 HTTP 402:Header WeixinPay-Required 的值就是 payment_code,另有 X-Out-Trade-No;Body 含 code=PAYMENT_REQUIRED、out_trade_no、amount(元,两位小数字符串)+ amount_total(分)+ currency,以及精确大小写的 WeixinPay 提示块(内含 WeixinPay-Required: payment_code 与官方 prompt)。
  2. Agent 调用 weixinpay_pay(payment_code 作为 paymentCode)完成支付,用语义完全相同的业务 body(字段值不可改)携带两个 Header 重试,两者缺一不可。
  3. 服务端先对 payment_code 做 SHA256 摘要 constant-time 比对(缺失 401、不匹配 409),再按 out_trade_no 查单,trade_state=SUCCESS 且订单号、应用、金额、商户和币种全部一致才计算并交付;重复履约返回首次固化结果(already_fulfilled=true)。
  4. out_trade_no ≤ 32 位;payment_code 最长 15 分钟(L2 expires_at 为 Unix 秒级时间戳字符串)。过期语义:已 fulfilled 的订单重试直接重算返回(不查单、不受过期影响);pending 订单查单为 SUCCESS 即使超过 15 分钟也允许首次履约;只有 pending 且查单非 SUCCESS 且已过期才返回 410。串单 409、金额/商户不符 409。

实现要点(src/pay/):

  • X402 L2(skill_info/pay_type=SKILL_PAY/pay_mode=AUTH_AND_PAY/pay_items/expires_at,标准 Base64);L1 签名串严格为 POST\n/palmpayminiapp/clawagentpay/preorder\n{timestamp}\n{nonce}\n{payment_required}\n,RSA SHA256 PKCS#1 v1.5,SkillHub 开发者私钥。
  • 微信支付 V3 请求签名(商户私钥)与响应验签(平台公钥 + Wechatpay-Serial 与配置平台证书序列号比对)均为 Node crypto 真实实现;三类密钥严格区分;错误统一脱敏,不输出密钥细节。
  • 文件订单存储(单实例):目录 0700、文件 0600、原子写、每订单排他锁;只持久化订单元数据、payload SHA256、支付凭证(用于幂等恢复)及固化结果,不保存原始 profile、mealText、私钥。历史订单按保留期清理并有文件数上限。多实例/多机生产部署必须替换为数据库事务实现。
  • notify_url 目前仅作为微信下单必填配置,仓库尚未实现支付回调解密/处理,履约依赖重试时主动查单;生产上线建议(微信侧也要求)补回调作为到账确认通道。
  • 来源认证:APP_AI_TOKEN 不用作公开 Pay Skill 凭证;后端默认要求独立 CHICHULAIDE_PAY_SOURCE_TOKEN,仅在明确接受公开调用风险时才允许 CHICHULAIDE_PAY_ALLOW_UNAUTHENTICATED_SOURCE=true。SkillHub 官方签名方案明确后应替换当前 token 门禁。当前边界为 64KB body 限制 + 每来源限流(30 次/分钟)+ 订单 15 分钟过期 + 查单后履约。应用默认不信任客户端可伪造的 X-Forwarded-For;反向代理部署需用 CHICHULAIDE_PAY_TRUSTED_PROXY_IPS 明确列出 TCP 对端代理 IP,并保证代理覆盖或追加真实来源地址,同时在代理层独立限流。

配置见 .env.example(CHICHULAIDE_PAY_*,全部使用占位符,仓库不含真实密钥);未启用时该入口返回 503,其余接口不受影响。付费 Skill 侧部署说明见 workbuddy/skills/chichulaide-meal-review-pay/references/setup.md——未配置真实 HTTPS URL 不可提交审核。

Hermes MCP 适配

src/mcp/server.mjs 是零新增依赖的 stdio MCP 服务,Hermes 可直接启动并发现以下工具:

  • chichulaide_capabilities:版本、能力、支付配置和安全边界。
  • chichulaide_daily_targets:本地确定性每日营养目标。
  • chichulaide_meal_review:本地确定性中文餐食复盘。
  • chichulaide_paid_invoke:转发到 CHICHULAIDE_PAY_API_URL,首次调用需提供并复用 idempotencyKey,保留首次 402 的 paymentCode / outTradeNo,并支持支付后原 body 重试。该工具不会在本地绕过支付。

本地启动与协议测试:

cd ai_backend
npm run mcp:start

注册到 Hermes(--args 必须放在最后):

hermes mcp add chichulaide \
  --command "$(command -v node)" \
  --args "$(pwd)/src/mcp/server.mjs"
hermes mcp test chichulaide

若需要付费工具,在 --args 之前增加:

--env CHICHULAIDE_PAY_API_URL=https://你的域名/v1/workbuddy/pay/invoke \
--env CHICHULAIDE_PAY_SOURCE_TOKEN=与后端相同的独立来源令牌

MCP stdout 只输出 JSON-RPC,诊断信息不得写入 stdout。Hermes 中首次可调用 chichulaide_capabilities 验证;本地免费工具不记录 profile/mealText,付费工具会把业务请求发送到所配置的 HTTPS 后端。

WorkBuddy 开放平台 Connector(未来版本,首发不启用)

远程 chichulaide-history Connector 位于 src/mcp/remote-server.mjs,使用 HTTPS streamableHttp 暴露 save_confirmed_meal、get_recent_meals、build_7day_report 和 delete_my_data 四个工具。它只接受当前 Token 对应的匿名主体,不接受 user_id;图片、原始聊天和未经确认的候选不会进入 Connector。首发专家不声明此依赖,也不启动该服务。

本地部署:

cd ai_backend
cp .env.example .env
# 设置 DATABASE_URL、CHICHULAIDE_SAFETY_RECEIPT_SECRET、HISTORY_PUBLIC_BASE_URL
npm run history:migrate
npm run history:provision-token -- tester
npm run mcp:remote

save_confirmed_meal 要求平台可信 safetyReceipt、domainVersion 和确认动作幂等键;没有可信安全凭证时默认返回 SAFETY_CHECK_UNAVAILABLE,不计算也不保存。公开发布前仍需 WorkBuddy 书面确认 OAuth/PKCE 或等效保护、原始消息安全事件来源、HTTPS、健康类目和回滚流程。