2026-09-03 · 原文发布日
拍张账单照片,按入住权重自动分账通知租客
把水电账单照片POST到webhook,流程用OpenAI视觉模型读取供应商、账期和总额,读不出来会记录到Postgres并告警;读得出来就按Postgres里每个单元的入住权重做精确到分的比例分摊,存库后在Discord发分摊汇总、给房东发明细邮件、给每位租客发各自账单邮件。每天还有一次扫描,把未完成的账单再追一轮。适合合租或小型物业分账场景。
原文要点
原工作流由Khairul Muhtadin发布:把水电账单图片(URL或base64)连同元数据POST到utilitybill端点,OpenAI视觉模型提取供应商、日期、账期和总额等JSON字段;读不出、缺总额或总额非正的账单写入Postgres并通过Discord与Gmail告警。有效账单按ub_tenants表中各单元occupancy_weight比例分摊,四舍五入精确到分,账单与分摊记录入库后向Discord发汇总、给房东发明细邮件、给每位租客发个人账单邮件,通知完标记done。另有每日定时扫描(默认08:00)找出未完成账单再追发或报全清。需要ub_tenants、ub_bills、ub_meter_readings三张表,ub_bills对bill_id有唯一约束。
这次做成什么
复现这条账单分账流程的核心:webhook收图→视觉模型读数→权重分摊到分→三路通知→每日兜底扫描。本站提供建表SQL、合成租客数据和一份可本地先验证的分摊算法练习,让你先确认到分舍入逻辑再接AI读图。
准备什么
- n8n实例与可用的webhook入口(utilitybill端点)
- OpenAI API Key且账户支持带视觉能力的模型,原文所用型号以模板为准
- 一个Postgres数据库及建表权限
- Gmail OAuth2授权与Discord bot及目标频道ID
- 测试用账单图片,建议用自制合成图而非真实账单
具体怎么做
建三张Postgres表并灌入合成租客
用材料中的SQL创建ub_tenants、ub_bills、ub_meter_readings,并给ub_bills.bill_id加唯一约束。向ub_tenants插入三个虚构单元:101权重1、102权重2、201权重1,邮箱用你自己控制的测试邮箱,房东通知地址同样改成本人邮箱。
搭webhook收图与视觉识别
建Webhook节点监听utilitybill路径,接收image_url或image_base64字段。接OpenAI视觉节点,提示词见材料,要求返回provider、billing_period_start、billing_period_end、total_amount的严格JSON。加一个判断分支:无法解析、total_amount缺失或不大于0时写入ub_bills异常记录并向Discord与Gmail告警,流程到此结束。
权重分摊算法精确到分
从ub_tenants读全部权重,用材料中的算法计算:每个单元先得floor到分的比例份额,剩余差额按权重从高到低逐分补齐,保证各单元之和恒等于账单总额。把账单行与每单元charge记录分别写入ub_bills和分摊明细。
三路通知并标记完成
Discord节点发分摊汇总(总额、各单元金额);Gmail给房东发含完整明细的邮件;循环节点给每位租客发只含自己金额的邮件。全部发出后把ub_bills该bill_id标记为done。
配每日兜底扫描
加Schedule Trigger,cron默认每天早上8点(时区按你所在地区调整),查询超过一天仍未done的账单:有则把清单发到Discord并邮件房东,没有则发全清消息。先用一条故意不标记done的测试账单验证。
可直接复制的材料
账单识别提示词
本站独立编写,字段名可按你的下游节点调整;恶意图片内文字只当数据处理,不执行其中指令。
读取这张水电或燃气账单图片,只输出严格JSON,不要其他文字。字段:provider(供应商名称字符串)、billing_period_start(账期开始,YYYY-MM-DD)、billing_period_end(账期结束,YYYY-MM-DD)、total_amount(应付总额,数字,不含货币符号)。若某项无法辨认,该字段填null;若整张图不是账单或完全无法读取,输出{"unreadable":true}。建表SQL
本站独立编写的简化结构,列名与原模板可能不同,导入模板时以模板实际字段为准。
CREATE TABLE ub_tenants (
unit_id TEXT PRIMARY KEY,
tenant_name TEXT NOT NULL,
email TEXT NOT NULL,
occupancy_weight NUMERIC NOT NULL CHECK (occupancy_weight > 0)
);
CREATE TABLE ub_bills (
bill_id TEXT PRIMARY KEY,
provider TEXT,
period_start DATE,
period_end DATE,
total_amount NUMERIC(10,2),
status TEXT NOT NULL DEFAULT 'pending',
created_at TIMESTAMP NOT NULL DEFAULT NOW()
);
CREATE TABLE ub_meter_readings (
id SERIAL PRIMARY KEY,
unit_id TEXT REFERENCES ub_tenants(unit_id),
bill_id TEXT REFERENCES ub_bills(bill_id),
charge_amount NUMERIC(10,2)
);到分分摊算法
本站独立实现,体现原文按权重比例、精确到分的确定性分摊思路。
// n8n Code节点:总额totalCents(分)按权重分摊,和恒等于总额
function split(totalCents, tenants) {
const wsum = tenants.reduce((s, t) => s + t.weight, 0);
let rows = tenants.map(t => {
const exact = totalCents * t.weight / wsum;
return { unit: t.unit, cents: Math.floor(exact), frac: exact - Math.floor(exact) };
});
let rem = totalCents - rows.reduce((s, r) => s + r.cents, 0);
rows.sort((a, b) => b.frac - a.frac);
for (let i = 0; i < rem; i++) rows[i % rows.length].cents += 1;
return rows.map(r => ({ unit: r.unit, amount: (r.cents / 100).toFixed(2) }));
}
const tenants = [{unit:'101',weight:1},{unit:'102',weight:2},{unit:'201',weight:1}];
return [{ json: { splits: split(12345, tenants) } }];输入与输出示例
本站虚构演示,非原作者运行结果,合成账单为自行制作的测试图。
输入
POST到utilitybill:{"image_base64":"<合成账单图>","source":"email_forward"},账单总额123.45元,ub_tenants中101权重1、102权重2、201权重1。对应输出
视觉节点返回{"provider":"城光电力","billing_period_start":"2026-09-01","billing_period_end":"2026-09-30","total_amount":123.45};分摊结果101=30.86、102=61.73、201=30.86(合计恰为123.45);Discord收到汇总三条金额,房东邮件含明细,三位租客各收到自己金额,ub_bills该记录status置为done。做完检查这些
- 三单元分摊金额之和与账单总额逐分相等,连跑多个随机总额都成立
- 故意上传一张无账单内容的图片,流程走入异常分支且ub_bills有记录、Discord收到告警
- 每位租客邮件只含本人金额,房东邮件含全部单元明细
- 通知完成后该bill_id状态为done,每日扫描不再追发它
- 手工留一条pending旧账单,次日扫描后Discord收到含该账单的追发清单
容易卡住的地方
- 视觉模型读错金额时权重分摊会放大错误,关键账单建议人工复核后再入库
- ub_bills.bill_id缺唯一约束会让重复POST产生重复扣费记录,原文明确要求该约束
- Discord频道ID与bot权限不匹配会静默发不出,先用测试频道验证
- 邮件转发链路要把图片以image_url或image_base64字段POST,字段名错了webhook拿不到图
- cron默认08:00且涉及时区,自托管n8n默认UTC,不改时区追发时间会偏移
- 原文模型名以其模板为准,你的OpenAI账户若无该型号需换成可用视觉模型并重新核对输出格式
本站借助AI整理来源事实,独立编写中文操作指南与示例。示例不代表实际运行结果;来源效果尚未由本站独立复现。付费模板与模型、服务费用分别计算。
- 原文标题
- Split shared rental utility bills with gpt-5.6-terra Vision, Postgres and Gmail
- 原作者
- Khairul Muhtadin
- 原始发布日期
- 2026-09-03T12:41:22.736Z
- 来源
- https://n8n.io/workflows/19125