跳到正文

Fud AI

一个跑在你自己 AI 密钥上的 iOS 与 Android 热量与训练记录应用:拍一张、说一句或打几个字,分析交给十三个 provider 里你挑的那一个——全都不行时,还有设备本地的模型兜底。

Screenshot of Fud AI
编辑截图, 29 Sep 2026Fud AI ↗

这是什么

一个本地优先的饮食、体重与训练记录应用,iOS 用 Swift、Android 用 Kotlin。记一餐可以一次拍最多十张照片、扫条码、说一句、打字,或者用 Siri;分析交给你配置好的那家 AI provider——支持十三家,包括任意 OpenAI 兼容端点——密钥存在系统钥匙串里。核心记录功能不需要账号、也没有分析上报;产品里唯一的一处第一方同步是一个可选的每周挑战,分享的是聚合分数而不是日志。运动示意图是一套 875 个动作的手绘动画库,而只有一份清单随应用一起发布。

谁做的一个人:2,361 次提交里 2,142 次是他写的,并在 2026 年 9 月 9 日把这个项目在印度注册为微型企业,Udyam 编号 UDYAM-DL-06-0225072。其余提交来自一个有自己 GitHub 身份的 agent 账号、一个依赖机器人和大约十几位其他人。应用已上架 App Store 与 Google Play,第一次订阅提交与 7.1.2 版一起发出去。

它是怎么搭起来的

组成 · 6

两个原生客户端架在一套刻意超大的共享素材语料之上,而所有外部智能都藏在一条由用户配置的链后面。塑造整个仓库的那个决定,是插画库放在哪:7,000 帧太大、装不进安装包,于是语料留在仓库里作为正典副本,一份小清单随应用发布,应用再从静态 CDN 拉取并缓存单独的帧——这让两个安装包都待在自己的体积上限内,也把一条美术流水线变成了一个有契约的投递问题。AI 那边是链形而不是适配器形:一次请求先走用户选的 provider,再走用户选的备用项,某些情况下最后走到设备本地的模型,于是一家厂商挂掉时退化的是答案,而不是功能。两件事之外,这个项目把不可撤销的动作当成默认关闭的闸门,把可撤销的本地数据当成常态——没有账号、没有分析上报,唯一一处可选同步传的是聚合分数而不是日志。

ios/calorietracker
464 个文件:一层 @Observable 的档案与 store(食物、体重、饮水、训练、对话),一个 services 层,其中 GeminiService 与 ChatService 各自路由十三个 provider,语音服务把远端转写路由到五家厂商,体重分析服务装着预测算法;密钥走 Keychain;视图从十五步 onboarding 一路到图表和教练页。旁边还有 Watch 应用、两个 widget 扩展、一个分享扩展,以及 47 个测试文件。
android/
一个 Kotlin + Compose 应用,725 个文件,共用同一套语料和同一套路由思路,用 Health Connect 而不是 HealthKit,另有自己的应用内语言选择器。android/release 里放着 42 个打包产物,共 513 MB。
shared/workout-vectors
7,011 个文件、1.21 GB:性别感知动画语料的正典副本、运行时清单,以及那份 README——里面写着命名契约、每帧的动画语义(起始、第一个动作、过渡或最大幅度、镜像或受控回位)、所有序列共用的一套视觉语言,以及一个如实写下的空缺:Other 档案目前用男性素材,直到画出专门的包容性一套。
artifacts/workout-visual-qa
7,835 个文件、1.26 GB 的修复凭据:整段序列的对齐报告(其中一份 8.8 MB)、复核过的前后帧、每帧按哈希命名的记录、已验收修复的清单,以及那份跟踪「哪些已验收、哪些停在版本控制之外、哪些发现仍在阻止验收」的 README。
scripts/ 与 workers/
48 个脚本,管素材流水线、商店操作与发布检查,其中包括后台修复运行器以及它的提升、描边和对齐测试套件;workers/ 里是一批编号的生成运行,每个动作输出四帧男性与四帧女性,外加一份结果文件。
store/、services/ 与 web/
store/ 是那份自带 README 的发布机制:产品与订阅目录、各平台元数据占位,以及那些闸门变量。services/ 里是托管 AI 代理的文档,和一个 Discord 机器人——它的四个注册脚本负责创建 /ask、bug 与 feature 三个命令。web/ 是官网,带自己的工作流和测试;local-models/ 装着目录、一个校验器和本地语音与语言模型的第三方声明。

取舍,以及它替代了什么

  • 自带密钥,跑在设备上 替代 经开发者服务器转发的第一方代理

    README 把 AI 访问写成免费、由用户自带密钥:密钥存在系统钥匙串里,请求直接发往所选 provider——并且它记下了早先那个第一方托管代理已被停止提供,也就是另一种选择的早期版本。

  • 插画语料不进商店安装包 替代 把 7,000 帧打进应用

    理由是带着算术写出来的:Google Play 把基础模块卡在 200 MB,而 iOS 包会涨大约 1.3 GB。于是只有清单随应用发布,这个目录保持为唯一正典副本,帧在首次使用时从静态 CDN 取回并缓存——CDN 打不开就显示动作图标。

  • 把本地分析放在链的最后一步 替代 在 provider 失败处结束

    在支持的 iPhone 上,文字、语音转写和 Siri 记录的食物描述分析,可以在所配 provider 与备用项都试过之后,落到设备上的 Apple Intelligence;iOS 27 上用户选定的照片同理。这是一项写明前提的能力,而不是一个默认行为。

  • 所有商店动作在运维打开之前都是关的 替代 打一个标签就发布

    发布 README 写明:android-v* 标签只构建并创建 GitHub Release,不发布;正式发布默认关闭;iOS 仍然由 Xcode Cloud 上传。文案、截图与提审都已接好但都在闸门之后,所以默认路径下不会误发出任何东西。

  • 没实现的门就让构建失败 替代 让它静静地未实现

    把 RevenueCat 同步那个变量打开会让工作流失败,因为写入那条路还不存在。README 说这是刻意的:另一种做法是留一个看起来能用、实际什么也不做的开关。

  • 除非用户主动选择,记录功能的任何东西都不同步 替代 一个需要账号、历史在云端的应用

    核心应用不需要账号、不做分析上报、日志留在本地;唯一一处第一方同步是每周挑战,分享的是一个化名和有限的聚合分数,需要参与者凭证,退出即远程删除档案,不活跃档案九十天后自动删除。原始日志与照片从不同步。

依据README.md(32,980 字符,含其中带注释的 iOS 目录树与隐私一节)、shared/workout-vectors/README.md、artifacts/workout-visual-qa/README.md、store/README.md、.github/workflows/quality.yml,以及完整的 16,512 个文件树及其体积。

制作过程

6 个阶段
  1. 01

    一个人,两个商店上架

    仓库建于 2026-02-04,到 2026-09-28 有 2,361 次提交,其中光是九月就占 883 次。它带的不是一条发布线而是两条——ios-v* 与 android-v*——最新的分别是 iOS 7.1.2 和 Android 7.1.1,两者相隔几小时发布。应用已在 App Store 和 Google Play 上架,包名 com.apoorvdarshan.calorietracker,两个平台各支持十八种语言,445 个星、91 个 fork,27 个未关闭 issue 里多数是用户按模板写得很规整的功能请求。2026 年 9 月 9 日,作者把它在印度注册为个体经营的微型企业,而 7.1.2 版是和第一次订阅提交一起发出去的。一个个人项目配一个营业执照号,这个组合本档案还没记过。

  2. 02

    仓库里装着两吉字节,以及它为什么不进安装包

    GitHub 报的是 16,512 个文件、2.43 GB,而其中几乎没有源码。最大的两个目录都是生成物:artifacts/workout-visual-qa 1.26 GB,shared/workout-vectors 1.21 GB。后者是这个项目自己的插画语料——875 个动作,每个四帧男性加四帧女性,7,000 张 PNG,每张约 175 KB——它的 README 把这套语料称作性别感知运动动画的唯一正典来源,规定了 <exercise-id>_<gender>_<version>_<frame>.<format> 的命名契约,以及一份作为格式、帧名、帧数与代表帧唯一真相来源的运行时清单。让这个体积成为设计决定而不是意外的,是紧接着的那句话:这套语料从不打包进商店安装包,因为 Google Play 把基础模块卡在 200 MB,而 iOS 包会涨大约 1.3 GB。真正随应用发布的只有 0.75 MB 的清单,帧则由应用首次打开某个动作时从静态 CDN 拉取并缓存——一次不带账号、不带设备标识的普通图片请求——CDN 打不开时就显示该动作的图标。语料旁边还躺着 513 MB 的发布产物和大约 150 MB 的市场素材,后者的目录名里带空格。

  3. 03

    一个根 agent 和三个 worker,在修 7,000 张画

    这次修复单独有一份 README,读起来像一份作业记录。图库被审计过,计划是清理背景并对齐画面——在本地做,分割跑在作者的 Mac 上,没有上传任何运动图片,也没有使用付费图像 API。账目记得很细:875 个动作里 5 个已验收并集成,四十张复核过的 PNG 同时进入两个平台的资源目录,五个复核清单被 accepted-repairs.json 钉住,复制后做了 SHA 校验,并跑完了整套 875/7,000 的同步检查;清理、描边、对齐与提升四套测试里共有 48 个通过的安全测试——同时注明视觉复核仍然不可省。剩下的 6,960 帧被停放在一个刻意 gitignore 的目录里,原则是未完成的候选不许进入应用资源、也不许进入发布;进度记在 run-state 文件里,每帧另有按哈希命名的记录,而 README 提醒要先确认记录里的进程还活着——因为一次停下的运行会留下一条仍写着 running 的状态。工作本身是分开做的:根 agent 之外还有三个 worker agent,一个改进队列调度并复核一个肌群,一个做完深蹲,一个完成恢复后的跪姿批次;根负责对齐弯举,并且只提升被完整验收的整组。可疑帧优先处理但一帧都不丢,未被标记的帧明确不等于已验收,而 README 直说跑完推理并不等于图库修好了:原图裁切、透视、前景保护和帧序复核都还是分开的事,并且不给总时长承诺。

  4. 04

    那个 agent 是一个有自己账号的贡献者

    2,361 次提交里 153 次由 cursoragent 用 cursoragent@cursor.com 提交——一个拥有自己 GitHub 账号的 agent,而不是挂在作者名下,它和十几个人一起出现在贡献者列表上。Cursor 还作为共同作者出现在 182 次提交里,而仓库里出现次数最多的尾注名字是作者自己的,231 次。Claude 系列出现在十次提交里,Copilot 三次。审查同样是混合的:README 上挂着一枚写着由 Qodo、GitHub Copilot 与 Greptile 完成代码审查的徽章,项目还持有 OpenSSF Best Practices 通过徽章和一份 Scorecard。至少十二个人落地过改动,其中几位超过五次。整体画面是:一个个人产品,而它的提交历史是作者、一个商业编程 agent,和一条长尾贡献者之间的协作。

  5. 05

    十三个 provider、一条降级链,以及本地兜底

    AI 这一层是当链条做的,不是当集成做的。在设备上你挑 provider、模型、备用项和语音语言;支持十三家,从 Gemini、OpenAI、Claude、Grok 到 Groq、Hugging Face、Fireworks、DeepInfra、Mistral,以及任意 OpenAI 兼容端点,密钥存在 iOS 钥匙串或 Android 加密偏好里,请求直接发往你所选的那家。遇到 503、529 或 429 时,食物分析和教练对话都会按 1 秒、2 秒、4 秒退避重试,于是短暂的服务抖动不会变成用户可见的失败。而在支持的 iPhone 上,这条链的尽头不是某家厂商:在你自己的密钥与备用项都失败之后,最终的兜底是设备上的 Apple Intelligence;在 iOS 27 上它还能在本地读食物照片,本地语音转写则是六个转写选项之一。README 也记下了被拿掉的东西——早先的第一方托管 AI 代理已停止提供,应用回到免费自带密钥、另有一个可选付费档的模式。

  6. 06

    护栏:不会误触发的商店发布,以及只检出 200 MB 的 CI

    上架是移动项目里最不可撤销的一步,也是这个仓库把闸门设得最紧的一步。打 android-v* 标签不会发布到 Play——它只构建并创建一个 GitHub Release——再往后的每一步都藏在一个默认关闭的变量后面,store/README.md 用一张表列清了商店文案、截图、提审、正式发布与目录同步里哪些已经接好、哪些仍然手动。其中一个变量被明确写成「打开就会让工作流失败」:STORE_SYNC_REVENUECAT=true 是错误,因为写入那条路还没实现——README 明说了这件事,而不是留一个看起来像功能的缺口。iOS 的二进制由 Xcode Cloud 上传,周边一切都由每次打标签时的本地流程准备。持续集成也是同一种性格:workflow 里的 action 全部钉死在提交 SHA 上而不是标签上,凭证不被持久化,每个 job 只检出它需要的那几个目录——这就是为什么一次网页 lint 不会把两吉字节的插画帧一起拉下来——而 Android job 会跑 Gradle 自己的 wrapper 校验,把 wrapper 二进制与官方发布的校验和比对,于是被篡改的 wrapper 会让构建失败。质量检查在每次分支推送、每个 pull request 上跑,并且每天 23:03 再跑一次。

相关档案

全部档案 →