尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
SparkyFitness 多模态视觉识别与照片记餐全流程:从聊天指令到食物日记的工程实践
后端前端移动开发【免费下载链接】SparkyFitnessSparkyFitness: Built for Families. Powered by AI. Track food, fitness, water, and health — together.项目地址https://gitcode.com/gh_mirrors/sp/SparkyFitness点击查看免费下载本文围绕 SparkyFitness 服务端 AI 聊天的视觉能力Vision Support展开系统讲解sparky_analyze_food_image、sparky_scan_label、sparky_log_food_photo三个 MCP 工具的设计意图、调用协议与底层实现并结合源码与测试说明「分析 ≠ 记录」这一核心交互模型如何在多轮对话中落地。读完本文你将掌握食物照片从识别、修正、审核到一键写入食物日记的完整数据流以及营养标签 OCR 扫描的工程细节。一、概述为什么聊天里需要一套专门的视觉协议在 chatbot-full-vision.md 这份系统提示词片段中SparkyFitness 为多模态 AI 助手定义了一套严格的食物照片处理规范。它的核心出发点有两个分析Analyzing不等于记录Logging。分析调用只负责把照片变成结构化营养数据并把结果渲染成一张交互式 Meal Card餐次卡片只有用户主动按下卡片上的 Log to diary 按钮数据才会真正进入食物日记。这套设计把「AI 的估算」和「用户的确认」强制隔离开避免模型在一次回复里自作主张写入记录。视觉模型是独立的调用看不到聊天上下文。这意味着用户在对话里说过的任何关于菜品的信息都必须显式通过description参数传递给视觉模型否则修正后的再次分析会发送字节级相同的请求得到完全相同的错误结果。三个工具共同构成了完整的闭环工具职责触发时机sparky_analyze_food_image分析食物照片输出结构化营养估算用户上传食物/餐食照片时sparky_scan_labelOCR 扫描营养标签提取精确营养成分用户上传营养标签照片时sparky_log_food_photo将已审核的分析结果写入食物日记用户在后续消息中明确要求记录时三者均定义在 visionTools.ts 的buildVisionTools工厂函数中输入参数由 schemas/vision.ts 中的 Zod schema 约束。二、sparky_analyze_food_image照片→结构化营养估算2.1 调用参数与语义sparky_analyze_food_image接受以下参数详见 AnalyzeFoodImageSchema参数类型必填说明image_urlstring否图片地址。通常可以省略——图片会自动从用户附加的消息中读取descriptionstring否但非常重要用户对菜品的主观描述如菜名、菜系、做法或食材。视觉模型将其视为高于其自身所见的权威信息total_weightstring否用户声明的整盘总重量含单位如400 g或14 oz视觉模型会按比例分配到各食材meal_typestring否用户提到的餐次槽位breakfast|lunch|dinner|snacks或自定义餐次名entry_datestring否记录目标日期YYYY-MM-DD例如用户说记到昨天时传入省略则默认今天description是这套体系里最关键的一个参数。提示词明确要求视觉模型是独立调用无法看到聊天记录因此用户对菜品的所有描述只能通过该参数送达。它被当成权威信息处理——当模型所见与用户描述冲突时以用户描述为准。同样重要的是当用户纠正上一次分析时必须带着修正后的description重新调用否则请求字节级相同结果必然还是错的。提示词中举的例子是用户说这是 ghee roast dosa酥油烤多萨不是 appam就应该传description: ghee roast dosa with chutney and sambar。源码层面的佐证在 visionTools.ts工具执行时优先使用「本轮实际附加的图片」兜底才用image_url参数随后将description与total_weight原样转发给foodPhotoEstimationService.estimateFoodPhotoNutrition。测试 chatbotToolsVision.test.ts 专门验证了这一行为修正语ghee roast dosa with chutney and sambar与total_weight: 400 g必须出现在传给估算服务的参数中。2.2 图片输入的处理边界工具对图片输入有严格约束parseImageInput接受data:URL如data:image/png;base64,...与裸 base64字符串拒绝远程http(s)URL——服务端不会代抓取外部图片而是返回 Remote image URLs are not supported. Please attach the image directly to the chat.裸 base64 会通过魔数前缀推断 MIME 类型/9j/→JPEG、iVBOR→PNG、R0lGOD→GIF、UklGR→WebP默认兜底为image/jpeg空字符串视为本轮没有图片直接提示用户附加照片避免向 AI 提供商发送空载荷。对应的测试覆盖了 data URL 解析、裸 base64 MIME 嗅探、远程 URL 拒绝、畸形 data URL 拒绝以及无图场景chatbotToolsVision.test.ts。2.3 结构化输出的字段估算服务要求视觉模型返回严格的 JSON 结构完整 schema 见 foodPhotoEstimationService.ts 中的RESPONSE_SCHEMA顶层meal_summary2~4 词的菜名摘要如 Paneer Kadai、overall_confidencehigh/medium/low、confidence_reason、totals各营养素的汇总、user_weight_reconciliation总重量分配说明、clarifying_questions最多 3 个能实质提升精度的问题。每个 itemname显示名、canonical_name去掉做法、品牌、数量的纯食物名词用于查食物库、estimated_grams、portion_description、preparation以及从热量、三大宏量营养素到饱和/多不饱和/单不饱和/反式脂肪、胆固醇、钠、钾、钙、铁、维生素 A、维生素 C 的完整微量营养素字段还有item_confidence与assumptions如假设用了 1 茶匙油。提示词要求模型不要为了省事把微量营养素默认成 0——钠在调味或餐厅菜里几乎不可能是 0只有植物性食品的胆固醇、天然食物的反式脂肪才是真正为 0 的情况。服务端在ensureTotals与withDerivedTotalMicros中还会做防御性规整模型漏掉的totals会被逐项累加补齐缺失的item_confidence默认medium。2.4 估算服务与跨提供商分发estimateFoodPhotoNutrition 是底层实现关键链路通过chatRepository.getActiveVisionAiServiceSetting(userId)获取用户当前激活的视觉 AI 服务配置若未配置则返回NO_AI_CONFIGURED对应工具的 ⚠️ Vision is not configured 提示构造提示词buildPrompt其中包含规则用户描述优先于视觉所见、用户总重量按比例分配、混合菜拆分为成分食材、给出canonical_name、明确假设、降低模糊场景的置信度等通过 providerDispatch.ts 分发到不同 AI 提供商——RESPONSE_SCHEMA会被按提供商改写Gemini 用responseSchema、OpenAI/Anthropic 用严格模式、Ollama 用format原样传递返回结果经normalizeEstimatePayload规整剥离包装键、处理数组形态、foodPhotoEstimateResponseSchema校验再进入下一步的数据库匹配增强。值得注意的一点服务支持多图输入。当用户一次上传多张照片时提示词会切换到多图版本说明这些照片显示的是同一餐可能包含同一道菜的不同角度、菜单或食材包装/营养标签要求模型合并使用全部图片且不重复计数同一食材buildPrompt。2.5 数据库匹配增强让真实数据胜过模型臆测在返回给用户之前估算结果还会经过 foodPhotoMatchService.ts 的attachFoodMatches增强。设计思路借鉴了 MacroFactor 对 AI 估算的处理哲学优先使用真实存储的营养数据而不是语言模型凭空生成的数字。具体做法是附加而非替换匹配foodPhotoMatchService.ts每个 item 用自己的canonical_name作为检索词在用户自己的食物库中打分匹配名称相似度 最近使用时间的 recency 加分选出最佳匹配与最多 2 个候选alternates分数达到MATCH_PRESELECT_SCORE且来源为exact_name、可进行克数换算、宏量营养素可用时才标记为preselect_match打开卡片时自动应用本地库未命中的 item 会按用户的提供商顺序级联查询外部食物提供商如 OpenFoodFacts匹配结果携带provider_type/provider_external_id作为溯源匹配是纯增强、纯附加原有字段包括items[].calories_kcal与totals一律不动这样旧版移动端客户端渲染的行为完全不受影响匹配失败也被吞掉绝不会让用户为一次已付费的 AI 调用白白损失估算结果。匹配完成后服务端还会对食材名做标题化titleCaseItemNames把模型输出的小写名称如 penne pasta规范成 Penne Pasta因为这个名字会一路展示在审核卡片、Meal Builder 和新建的食物上。三、sparky_scan_label营养标签 OCR 扫描对营养标签类图片提示词要求使用sparky_scan_label以保证数据提取的高准确度。该工具的参数极简——只有一个可选的image_url同样优先使用本轮附加的图片ScanLabelSchema。底层 labelScanService.ts 内置了LABEL_SCAN_PROMPT要求模型提取name、brand、serving_size、serving_unit按标签所示液体用ml、calories、protein、carbs、fat、fiber、saturated_fat、trans_fat、sodium、sugars、cholesterol、potassium、calcium、iron、vitamin_a、vitamin_c并约定所有数值字段为绝对值非每日参考值百分比一律返回数字而非字符串标签上看不到的字段返回null只输出 JSON 对象不附带其他文本。工具层把扫描结果以️ Nutrition Label Scan Result: JSON 的形式返回给模型visionTools.ts测试 chatbotToolsVision.test.ts 覆盖了正常解析、远程 URL 拒绝、未配置 AI、解析失败等分支。四、交互纪律分析后绝不立刻记录提示词用大量篇幅约束模型在同一轮对话内的行为每个回合只调用一次sparky_analyze_food_image。分析返回后简要描述菜品并结束回复绝不在同一轮重复调用绝不在同一轮同时调用sparky_log_food_photo——无论分析出的食材有多稀少用户说我当零食吃的这是昨天的午餐这些只是卡片的上下文不是记录请求应作为meal_type/entry_date传给分析工具让用户自己去点记录按钮不要对食物照片调用sparky_ask_user——交互式 Meal Card 已经提供全部保存选项Ingredients reusable meal、Ingredients only、One food以及 Log to diary / Open in Meal Builder 按钮助手只需在回复里简单描述菜品不要在这一轮替用户写日记——分析不是记录卡片是审核界面用户看到数字没问题后按 Log to diary。这些约束在工具返回文本的尾部被强化visionTools.tssparky_analyze_food_image的返回值明确附带提示 [Note: The interactive meal card is now displayed to the user. Summarize the detected meal and finish your response. Do NOT call sparky_analyze_food_image again in this turn.]。4.1 结构化结果如何跨轮传递这里有一个值得展开的工程细节工具返回给模型的是纯文本 markdown但客户端要渲染卡片、后续要按原样记录必须拿到结构化数据。解决方案是 foodPhotoEstimateSink.ts 定义的每轮暂存器sinkcreateFoodPhotoEstimateSink()为每个聊天回合创建一个独立的捕获对象set(estimate)记录本轮的估算结果后写覆盖先写一轮内多次分析时记录最后展示的那次分析结果同时以estimate字段随工具返回值携带供客户端渲染卡片并作为data-food-photo-estimate类型的消息部件持久化到聊天记录之所以刻意按轮传入而非模块级状态是因为同一进程内可能并发处理多个用户的多轮对话模块级状态会产生串扰。这个设计直接支撑了sparky_log_food_photo的跨轮记录能力详见下一节。五、sparky_log_food_photo把审核结果一键写入日记5.1 触发时机等一个明确的后续请求提示词明确规定只有用户在后续消息中明确要求记录/保存时log it、save this as a meal、yes, log as one food且卡片尚未完成记录时才调用sparky_log_food_photo。如果无法判断用户是否已经用卡片记录了应该提问——重复的日记条目比一次提问更糟。为什么记录请求总是落在下一轮因为询问用户如何保存sparky_ask_user本身就是一个回合结束条件用户的回答会到达一个全新的回合而聊天历史会剥离图片此时重新分析已不可行。因此工具必须先查本轮暂存器取不到再回退到聊天记录中最近一次持久化的data-food-photo-estimate部件loadLatestFoodPhotoEstimate——这正是 sink 设计存在的原因。5.2 参数说明参数类型说明save_modeenumingredients_and_meal每个食材建成可复用食物 整盘存为可复用餐次或one_food整盘作为单一食物保存meal_typestringbreakfast|lunch|dinner|snacks或自定义餐次名entry_datestring日历日YYYY-MM-DD必须匹配该正则meal_namestring可选餐次名称缺省使用分析结果的meal_summary完整的 LogFoodPhotoSchema 定义在工具源码中。save_mode的语义在工具描述里也有说明ingredients_and_meal会把每个食材建成独立可复用食物并且把整盘保存为可复用餐次之后无需照片即可再次记录one_food则整盘记为单一食物、无拆分。5.3 临界规则绝不用 sparky_manage_food 替代提示词标为CRITICAL的一条绝不要对已分析的照片调用sparky_manage_food如log_food、lookup_food_nutrition、search_food、create_food。原因在于sparky_log_food_photo一步完成三件事创建所有需要的食物或复用已匹配的数据库食物保存餐次模板创建可折叠的分组日记条目。如果改用sparky_manage_food手动重录数字就会丢失逐食材的拆分结构和分析阶段已经解决的数据库匹配工具描述原文it keeps the per-ingredient breakdown and the database matches that the analysis already resolved。5.4 底层实现单事务保证原子性foodPhotoLogService.ts 的createPhotoLoggedMeal用单个数据库事务完成整盘记录这是经过深思熟虑的设计foodPhotoLogService.ts备选方案——客户端依次发 N 次POST /api/foods再发一次POST /api/food-entry-meals——会在中途失败时留下孤儿食物比如 5 个食材创建到第 3 个时网络断开账户里多了 3 个无主食物、没有任何日记条目且无法清理该服务刻意不复用foodEntryService.createFoodEntryMeal那条路径会给父行、每个组件、批量插入分别获取新的连接而本事务内创建的食物尚未提交、其他连接不可见隐式提交还会破坏回滚能力。因此这里所有操作都跑在同一个PoolClient上。事务内的关键步骤包括先验证所有复用的food, variant对存在且匹配variant 属于声明的那款 food避免把一款食物的营养挂到另一款食物的日记行上——任何非法 id 都在写入任何行之前失败计算portionFactor consumed_quantity / (serving_size × total_servings)把分量折叠进各食材数量聊天流程默认整盘按 1 份全部吃完mode grouped时先建父级餐次记录再批量创建食物条目新建食物统一走buildNewFoodInput故意建成普通可见食物而非 quick food——quick food 被排除在搜索、收藏、最近使用和findFoodMatchCandidates之外若食材不可见同一道菜的下一张照片就永远匹配不上食物库会堆满用户看不到也无法合并的隐形重复品。可见食物则形成闭环第一次照片创建 Chicken Thigh第二次照片匹配到它用户在某次估算中做的一次修正会应用到之后所有估算COMMIT提交、ROLLBACK回滚、client.release()归还连接任何异常都被捕获并以PhotoLogError转成面向用户的错误文案。工具层在记录完成后会把sparky_log_food_photo返回的确认信息汇报给用户Logged X as N ingredients、Added N new foods to your foods、Saved as a meal you can log again without a photo 等见 renderPhotoLogResult。六、权限模型视觉工具是只读的从 toolAccess.ts 可以看到sparky_analyze_food_image与sparky_scan_label都被归类为read——它们只调用用户的 AI 提供商做分析不写入业务数据因此工具以readOnlyHint: true发布并开放给只读 API key真正的写操作sparky_log_food_photo不在该映射表中按默认策略视为写入工具只读密钥拿不到它。这从权限层面印证了分析是只读、记录才是写入的产品语义也与第 4 节分析后不立刻记录的交互纪律相互呼应。七、一条完整链路从照片到日记综合以上各节一次典型的视觉记餐流程如下用户上传一张餐食照片可附带描述如这是 ghee roast dosa大约 400 克模型调用sparky_analyze_food_image传入description、total_weight必要时传入meal_type/entry_date服务端校验图片格式 → 取用户视觉 AI 配置 → 跨提供商分发结构化估算请求 → 规整与 schema 校验 → 食物库匹配增强 → 标题化工具返回结构化estimate供客户端渲染 Meal Card与 markdown 摘要供模型阅读估算结果暂存进本轮 sink模型简要描述菜品并结束本轮回复不记录用户在卡片上核对克重与宏量营养素选择保存模式点击 Log to diary或 Open in Meal Builder若用户改为在聊天里打字说log it模型在下一轮调用sparky_log_food_photo从 sink/聊天记录取回最近一次估算单事务写入食物日记与餐次模板工具向用户汇报记录确认结果。对营养标签场景流程简化为上传标签照片 →sparky_scan_labelOCR 提取 → 返回 JSON 营养数据。八、测试保障行为被固化在测试里视觉功能的行为边界在 chatbotToolsVision.test.ts 中被系统性固化可以作为理解契约的捷径修正语必须作为description转发给估算服务L82-L107data URL 解析与结构化结果渲染L109-L144裸 base64 的 MIME 嗅探L146-L182远程 URL / 畸形 data URL / 无图三种非法输入被拒绝且不触发服务调用L184-L207、L258-L269未配置 AI 时给出引导性提示L209-L226、L336-L351服务异常被兜底成错误文案、绝不抛出L245-L256、L370-L381meal_type/entry_date原样透传给卡片L271-L289标签扫描正常返回 JSON 与各失败分支L292-L381。这套测试与 chatbotToolsIndex.test.ts 中的工具注册断言一起确保了提示词规定的交互纪律与实现代码保持一致也为后续演进如新增视觉工具、调整 save_mode提供了安全网。结语SparkyFitness 的视觉记餐不是简单的看图说话而是一套精心设计的人机协作审核流水线视觉模型只负责估算、数据库匹配负责提供真实数据、交互卡片负责让用户确认、单事务工具负责原子落库权限模型与测试又把分析只读、记录写入的边界固化下来。理解 chatbot-full-vision.md 这份提示词与其背后的 visionTools.ts、foodPhotoEstimationService.ts、foodPhotoLogService.ts 实现是掌握这套体系最直接也最完整的路径。赞分享后端前端移动开发【免费下载链接】SparkyFitnessSparkyFitness: Built for Families. Powered by AI. Track food, fitness, water, and health — together.项目地址https://gitcode.com/gh_mirrors/sp/SparkyFitness点击查看免费下载相关推荐SparkyFitness 移动端用户流程全解从导航架构到食物记录的核心交互图谱SparkyFitness 移动端用户流程全解从导航架构到食物记录的核心交互图谱 本文以 SparkyFitnessMobile/docs/user_flow后端前端移动开发SparkyFitness 食物记录 Agent 规则解析从强制查询到 Quick Add 的完整工作流SparkyFitness 食物记录 Agent 规则解析从强制查询到 Quick Add 的完整工作流 SparkyFitness 的 AI 助手通过名为后端前端移动开发终极指南Winlator输入控制系统如何解决Android运行Windows的交互难题终极指南Winlator输入控制系统如何解决Android运行Windows的交互难题 你是否曾在Android设备上运行Windows应用时面对复杂的输入移动开发虚拟化上一篇Next.js 环境变量公开化用 NEXT_PUBLIC_ 前缀把变量安全暴露给浏览器端代码下一篇终极AtlasOS网络共享配置指南3种方法快速恢复局域网文件共享创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED

相关推荐

FilmCraft 的 Matroska/WebM 容器层:纯 Rust 净室解复用器与最小封装器

FilmCraft 的 Matroska/WebM 容器层:纯 Rust 净室解复用器与最小封装器

【免费下载链接】filmcraft An open-source, clean-room reimplementation of Adobe Premiere Pro built in pure Rust. 项目地址: https://gitcode.com/gh_mirrors/fi/filmcraft 点击查看 免费下载 filmcraft-matroska 是 FilmCraft(一个用纯 Rust 重写的开源 NLE…

📅 2026/10/9 1:22:10
GPT-6 Astra 深度评测:单题思考耗时与推导准确度的帕累托前沿曲线

GPT-6 Astra 深度评测:单题思考耗时与推导准确度的帕累托前沿曲线

在长推理模型的技术演进中,OpenAI 最新推出的 GPT-6 Astra 代表了测试期计算(Test-Time Compute)自适应分配的最前沿方向。与早期仅提供固定档位思考深度的推理模型不同,GPT-6 Astra 引入了更加弹性的动态认知推演机制&#xff0c…

📅 2026/10/9 1:17:09
用 XML 存储与传输数据:learnxinyminutes 荷兰语教程中的语法、书店实例与 DTD 校验实践

用 XML 存储与传输数据:learnxinyminutes 荷兰语教程中的语法、书店实例与 DTD 校验实践

文档教程 【免费下载链接】learnxinyminutes-docs Code documentation written as code! How novel and totally my idea! 项目地址: https://gitcode.com/gh_mirrors/le/learnxinyminutes-docs 点击查看 免费下载 本文基于 Learn X in Y minutes(learn…

📅 2026/10/9 1:17:09
MORE NEWS

更多资讯

📰

现代 JavaScript 教程实战:用 cubic-bezier 让 CSS 尺寸动画“跳脱“边界(飞机缩放回弹动画)

文档教程前端 【免费下载链接】zh.javascript.info 现代 JavaScript 教程(The Modern JavaScript Tutorial),以最新的 ECMAScript 规范为基准,通过简单但足够详细的内容,为你讲解从基础到高阶的 JavaScript 相关知识。…

📰

models.dev Issue Fixer 自动化深度解析:从 GitHub Issue 到模型目录数据修复 PR 的完整工作流

人工智能大模型后端前端 【免费下载链接】models.dev An open-source database of AI models. 项目地址: https://gitcode.com/gh_mirrors/mo/models.dev 点击查看 免费下载 导读 本文围绕 models.dev 仓库中的自动化 Issue 修复 Agent 配置文档 issue-fixer.md 展…

📰

Hyperf 分佈式事務實戰:基於 DTM 的 TCC、Saga、XA 與二階段消息完整指南

后端微服务 【免费下载链接】hyperf 🚀 A coroutine framework that focuses on hyperspeed and flexibility. Building microservice or middleware with ease. 项目地址: https://gitcode.com/gh_mirrors/hy/hyperf 点击查看 免费下载 本篇技術指南以…

📰

PaddleNLP 土耳其语模型 dbmdz/bert-base-turkish-uncased 下载与使用实战指南

人工智能深度学习计算机视觉NLP语音 【免费下载链接】models Officially maintained, supported by PaddlePaddle, including CV, NLP, Speech, Rec, TS, big models and so on. 项目地址: https://gitcode.com/gh_mirrors/mo/models 点击查看 免费下载 本篇技术指…

📰

资源稀缺信号与约束内构建:let-fate-decide 中 Five of Pentacles(五角星五)的工程技术解读

AI 技能AI 插件应用安全网络安全AI 评测 【免费下载链接】skills Trail of Bits Claude Code skills for security research, vulnerability detection, and audit workflows 项目地址: https://gitcode.com/gh_mirrors/skills8/skills 点击查看 免费下载 Five of …

📰

ResNet优化模型实现阿尔茨海默症MRI识别:课程设计实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬