构建 AI 驱动的账单分摊工具:OCR、LLMs 与实时状态

发布: (2026年1月18日 GMT+8 19:35)
8 min read
原文: Dev.to

Source: Dev.to

Doru Prodan

1. OCR 管道:从像素到原始文本

构建像 Hackbill 这样的工具的首要挑战是将可能模糊、光线不足的手机照片转换为机器可读的文本。传统的光学字符识别(OCR)技术已经取得了长足进展,但收据具有独特的难点:字体多变、纸张皱折以及复杂的布局(数量、名称和价格的列)。

预处理步骤

在送入 OCR 引擎之前,通常需要通过一系列处理来提升准确率:

  • 灰度转换: 去除颜色噪声。
  • 透视校正: 使用边缘检测(例如 Canny)找到收据的四个角点,并执行四点透视变换。
  • 自适应阈值化: 处理纸张上不均匀的光照。

选择引擎

  • Tesseract: 开源标准。
  • 基于云的解决方案(AWS Textract、Google Cloud Vision): 对多列布局提供更好的结果,因为它们返回“块”和“表单”,而不仅仅是原始字符串。

2. 使用 LLM 进行结构化数据提取

原始 OCR 输出往往是一堆无结构的字符串。例如,一行可能显示为 1 BU RGER $15 .00。基于正则表达式的传统解析非常脆弱,因为每个 POS 系统的收据格式都不相同。

这正是大型语言模型(LLM),如 GPT‑4oClaude 3.5 Sonnet 发挥作用的地方。与其编写上百行正则表达式,不如将原始 OCR 文本传给 LLM,并使用系统提示让其返回符合 JSON 架构的结果。

示例实现(Node.js)

const extractReceiptItems = async (rawText) => {
  const prompt = `
    Extract the items, quantities, and prices from this receipt text.
    Return ONLY a JSON array of objects with keys: name, quantity, price.
    Text: "${rawText}"
  `;

  const response = await openai.chat.completions.create({
    model: "gpt-4o",
    messages: [{ role: "user", content: prompt }],
    response_format: { type: "json_object" },
  });

  return JSON.parse(response.choices[0].message.content);
};

通过使用 AI 驱动的扫描,Hackbill 能够智能地识别哪些行是商品条目,哪些是元数据(例如日期或服务员姓名),从而显著减少用户的“审查”阶段。

3. 实时协作与状态管理

一旦收据被扫描并提取出商品,接下来的技术难点就是“共享与认领”阶段。从开发者的视角来看,这是一道分布式状态问题。如果三个人同时查看同一张账单,我们必须确保不会出现两个人同时认领同一瓶啤酒的情况。

实时同步的技术栈

要实现 Hackbill 工作流中提到的“实时查看谁在认领什么”功能,通常有三种选择:

  • WebSockets (Socket.io): 适用于低延迟、双向通信。
  • Server‑Sent Events (SSE): 适合单向更新(服务器 → 客户端)。
  • 实时数据库 (Supabase/Firebase): 对于快速开发最为高效,因为它们已经内置了发布/订阅逻辑。

冲突处理

当用户点击 “Claim” 时,客户端应在后台验证请求的同时,对 UI 进行乐观更新。如果数据库中该商品已经被另一个 user_id 认领,后端会拒绝该事务,UI 随即回滚。

4. 公平小费分配的数学

Hackbill 哲学中最具创新性的功能之一是 Fair Tip Distribution(公平小费分配)。大多数人只是把小费平均分配,但这在技术上并不公平。如果我点了一份 5 美元的沙拉,而你点了一份 50 美元的牛排,那么把 10 美元的小费平均分配就意味着我相对于我的消费支付了过多。

算法

Hackbill 确保只有声明了项目的人才支付他们应付的小费份额。其数学计算方式为加权百分比:

  1. 计算小计: 所有已声明项目的总和。

  2. 计算用户小计: 用户 A 所声明项目的总和。

  3. 计算比例:

    User A Proportion = User A Subtotal / Total Subtotal
  4. 应用小费/税费:

    User A Total = User A Subtotal
                 + (Total Tip * User A Proportion)
                 + (Total Tax * User A Proportion)

在后端实现此逻辑可确保最终的“Claim”(声明)金额在数学上是合理的,并且在社交上也没有摩擦。

5. 安全性与隐私考虑

作为开发者,我们必须考虑收据数据的敏感性。收据通常包含信用卡的后四位数字、商家的地址以及用餐习惯。

  • 数据最小化: 仅存储商品名称和价格。成功解析后丢弃原始图像。
  • 短期会话: 使用基于 UUID 的唯一 URL 分享账单,并在设定时间后失效。
  • 加密: 确保所有传输中的数据通过 HTTPS 处理,且个人可识别信息(PII)在静止时加密。

结论:用代码解决社交摩擦

构建像 Hackbill 这样的工具是将多种现代技术——计算机视觉、自然语言处理和实时网络系统——相结合,以解决日常人类问题的典范。

对于想要构建类似应用的开发者,关键点很明确:

  • 不要用僵硬的正则表达式去对抗现实世界的非结构化特性。 采用大型语言模型进行数据提取,使用实时同步实现协作,并始终确保你的数学处理诸如加权小费分配等边缘情况。

准备好摆脱手动计算了吗? 访问 Hackbill,亲眼见证这些技术原理的实际应用,并简化你下一次的团体聚餐。

开发者关键要点

  • OCR 是起点,而非终点: 使用大语言模型(LLM)来结构化 OCR 产生的混乱数据。
  • 实时性不可妥协: 使用 WebSockets 或 Supabase 实现无缝的“认领”体验。
  • 加权计算 > 简单计算: 始终基于比例小计来计算份额,以确保公平。

祝编码愉快,愿你的下一张午餐账单像这段 Markdown 一样清晰!

Back to Blog

相关文章

阅读更多 »

了解网络设备:初学者指南

基本网络流程 Internet → Modem → Router → Switch → 您的设备 Modem - 它的作用:将来自 ISP 的信号转换为您的设备可以使用的数据。 - Ana...