这是对Hacktoberfest 周末挑战赛:为朋友而构建 的提交

我构建了什么

上个月 Ma 转发给我一条 WhatsApp 消息,说她的 SBI 账户会被冻结,除非她更新 KYC。她没有点击链接。她打了那个号码。

我妈妈能读孟加拉语。我的祖父母也是。但支配他们生活的大部分纸张却读不了:电费单、银行信件、血压药板上的说明条,以及每个印度父母手机里不断收到的"尊敬的客户,您的账户今天将被冻结"的消息。

所以这些东西最后都变成一张照片发给我,附上一句"এটা কী?"(这是什么?)。如果我在开会,它就得等着。如果那条消息是诈骗,等待才是最危险的部分。

চিঠি (Chithi)在孟加拉语里是"信"的意思。它只做一件事。你把手机对准任何一张纸或任何截图,它就用你的语言大声说出来:

  1. 这是什么。"这是你的 CESC 电费单。"
  2. 你需要做什么。"在 12-10-2026 之前支付 ₹1,182.00。"
  3. 它是不是陷阱。一个红色的প্রতারণা!(诈骗!)印章,上面写着"什么都别做。不要点链接,不要打消息里的号码,不要分享 OTP",还有一个大按钮可以直接打给我。

它最初是给我家人用的孟加拉语应用。后来我意识到同样的问题存在于每一种印度语言中,所以现在它支持印度第八附表里的全部 22 种语言,外加英语。

One fake SBI KYC message read in six languages

演示

试试看:chithi-teal.vercel.app。选一种语言,然后点击其中一张示例照片(一条诈骗短信、一张账单、一条药板),或者上传你自己的。

Chithi demo: choose a language, read a scam SMS, a bill, then the same scam in Hindi and Tamil

选择一种语言 孟加拉语主页 一条诈骗信息 一张账单
Language picker Home screen in Bengali Scam result in Bengali Bill result in Bengali

公开演示在云端运行 Gemma,这样你不用安装任何东西就能试用,页面上也说明了这一点。在家里它运行在我们自己的笔记本电脑上。关于为什么这个区别很重要,下面会详细说。

代码

GitHub logo codeswithroh/chithi

把手机对准任何账单、信件或 WhatsApp 转发消息。用你的语言听它。知道它是不是诈骗。开源权重 Gemma,22 种印度语言。

চিঠি (Chithi)

Chithi

在线演示:https://chithi-teal.vercel.app。选一种语言,然后点击一张示例照片 为以下活动而构建DEV Hacktoberfest 周末挑战赛:为朋友而构建。MIT 许可。

给我妈妈和祖父母的口袋阅读器,他们能读孟加拉语,但读不了英语。

把手机对准任何账单、银行信件、药板或 WhatsApp 转发消息。Chithi 会读取它,使用Gemma(一个在家庭笔记本电脑上运行的开源权重模型),然后用你的语言大声说出:

  1. 它是什么,
  2. 你需要做什么(金额、截止日期),
  3. 是否是诈骗,并配有一个大按钮可以打给我。

照片从不离开家里。没有云端 API,没有账户,也没有月费。

工作原理

phone (PWA, camera)  ──Wi-Fi──▶  laptop: Bun server  ──▶  Ollama + Gemma (vision)
        ▲                                │
        └── speech in your language      └── scam rule layer (can only raise risk, never lower it)
            (phone's offline voice)
  • server.ts提供……

它刻意做得很小:一个 Bun 服务器、一个不用框架的手机网页应用,以及不到 200 行的共享逻辑,用于提示词、清理和诈骗规则。

我是如何构建它的

Ma's phone (web app, camera)  ── home Wi-Fi ──▶  family laptop: Bun server ──▶ Ollama + Gemma 3 4B (vision)
       ▲                                               │
       └── spoken answer (phone's own offline voice)    └── scam rules (can raise the risk, never lower it)

模型。Gemma 3 4B,一个开源权重视觉模型,运行在Ollama上,装在我 8 GB 的 M3 MacBook 上。手机通过家庭 Wi-Fi 发送照片。Gemma 读取它,并以固定的 JSON 结构作答:原始文本、文档类型、两行说明、该做什么、金额、截止日期,以及风险等级,取值为safe、caution或scam。Ollama 的 JSON-schema 模式意味着回复总能被解析。

语音。手机自带的文本转语音,使用bn-IN(或hi-IN、ta-IN……)。它可以离线工作。没有手机语音的语言会回退到读取相同文字系统的语音,所以迈蒂利语走印地语语音,孔卡尼语走马拉地语语音。

手机应用。一个添加到主屏幕的微型网页应用。巨大的按钮、大字号,无需学习。它有一个按钮打开相机,一个按钮选择截图。

测试教会了我什么

大部分工作不是“调用模型”。而是找出 4B 模型失败的方式,然后确保这些失败不会传到我妈妈那里。

1. 模型识别出了诈骗,然后给出了骗子的号码。我的第一个测试是一条假冒 SBI 的“KYC 更新”短信。Gemma 正确地说出诈骗,然后建议:“拨打消息中的求助热线了解更多。”那个求助热线就是骗子。从那以后,当判定为诈骗时,建议是每种语言由人工编写的固定文本。模型从不撰写它。

2. 小模型不应是唯一的防线。在scam.ts中的确定性规则层会检查转录文本中是否有 OTP 和 PIN 请求、KYC、“账户被封锁”、彩票和中奖措辞、短链接、.apk文件,以及像 AnyDesk 这样的远程访问应用。它可以提高风险等级,但从不降低它。药板上的印刷 MRP 会被记录,但不会升级。

3. 数字太重要了,不能改写。Gemma 曾把 ₹1,182 念成 "one thousand one hundred eighty-eight"。现在解释中完全禁止出现数字。金额和到期日来自单独的字段,按印刷原样复制,应用会把它们显示在各自的框里。

4. 小模型会在不同文字系统之间漂移。孟加拉语回答里混进了韩文字符。马拉雅拉姆语回答里混进了罗马尼亚语和俄语单词。现在,任何不属于读者自身文字系统(或纯英文,用于 SBI 这类品牌名)的字母都会被剔除,严重漂移的回答会重试一次。如果不做剔除,手机的孟加拉语语音会在句子中间被韩文绊住。

5. 一台 8 GB 的笔记本电脑是有规矩的。第一张照片花了将近四分钟,因为模型在加载。然后我的一个修复让情况更糟了:预热请求和真实请求用了不同的上下文大小,于是 Ollama 加载了两次模型并超时。现在服务器在启动时用相同的设置预热模型,并让它保持加载状态。在家里,一张照片要花 25 到 60 秒,对应用来说很慢,对一封信来说还行。

全部 22 种语言

首次启动时,Chithi 会用每种语言各自的文字系统显示所有语言,并优先推荐手机的语言。之后,一切都跟随所选语言:按钮、Gemma 的解释、诈骗警告、语音、字体,以及乌尔都语、克什米尔语和信德语的从右到左布局。

我对质量很诚实。在 4B 笔记本模型上,印地语、孟加拉语、马拉地语、泰卢固语、泰米尔语、古吉拉特语、乌尔都语和卡纳达语表现不错。奥里亚语和马拉雅拉姆语较弱,而 Gemma 3 4B 根本不会写桑塔利语的 Ol Chiki 文字。这些语言带有 "beta" 标签和屏幕警告,提示与家人核对。

公开演示

评委没法来我家,所以演示在 Vercel 上运行同样的代码。唯一的区别是 Gemma 住在哪里:Gemma 4 26B(一个混合专家模型,激活参数 4B)运行在 Google 免费的 Gemini API 层级上。我学到了两件事:

  • Gemma 4 在回答之前会先思考,结果它把空间用完了。第一次部署失败了,因为模型把 1,500 个输出 token 中的 1,497 个花在了思考上,始终没写出 JSON。朗读账单不需要深思熟虑,所以我设置thinkingLevel为minimal. 回复时间从 40 到 55 秒降到了大约5 秒。
  • 更大的模型弥合了语言差距。在 16 种语言的 63 次实机运行中,每一个骗局都被识破,每一笔金额和到期日都准确无误。Malayalam 和 Odia 输出干净,Santali 以正确的 Ol Chiki 文字返回。同一个开源模型家族,更大的规模,无需 beta 标签。

为什么开放创新很重要?

因为那些照片是我妈妈的银行信件和处方。在家里,照片从她的手机传到隔壁房间的笔记本电脑,就停在那里。没有账号,没有 API key,也没有任何公司的服务器。封闭的 API 意味着要把父母的 KYC 信息发给第三方,来保护他们免受那些想拿到他们 KYC 信息的人侵害。

因为一份礼物不该需要订阅。这个应用运行不花一分钱。如果某个定价页面变了,或者某家公司决定 Bengali 不是优先市场,我妈妈的阅读器照样能用。开源权重意味着那台笔记本电脑上的模型是属于我们的。

因为我可以挑选适合这个家的模型。一台 8 GB 的笔记本电脑运行 Gemma 3 4B。有 16 GB 机器的家庭只需改一个环境变量就能改用 Gemma 4。当 4B 模型在 Malayalam 上表现不佳时,答案不是“等供应商”,而是“试试更大的开源模型”。我试了,问题解决了。

因为安全层必须由我掌控。防骗规则、固定建议和脚本清理都是我能读、能改的代码。用开源模型,我能清楚看到它的回答在哪里结束、我的规则从哪里开始。

在家运行输在哪里?速度。托管的 Gemma 5 秒回答,笔记本电脑要 30 秒。对于一封只读一次的信,我宁愿要 30 秒加隐私。

交到她手上

这个周末我把它交给了妈妈:笔记本电脑留在家里开着,应用放在她手机的主屏幕上,我的号码已经设在红色通话按钮后面。

她用了,然后告诉我这是我为她做的最好的东西之一,会帮到她很多。

她为我做的事感到骄傲。说实话,这比任何测试通过都更让我触动。

我的 Agent 会话

我用一个 AI 编程智能体(Claude Code)作为搭档,在一个周末里做出了 Chithi。产品决策由我来定(面向谁、以诈骗优先的流程、"绝不让模型撰写防诈骗建议"这条规则),而智能体和我一起编写并测试了大部分代码。上面那个带着真实失败案例的测试循环,就是那次会话的产物。

奖项类别

  • Gemma 最佳应用奖。Gemma 3 4B 通过 Ollama 在家庭笔记本电脑上本地运行,Gemma 4 26B 则通过 Gemini API 为公开演示提供支持。应用会自动选择可用的最佳 Gemma。

为我的妈妈和祖父母而做。如果你的父母也会收到"尊敬的用户"这类消息,代码采用 MIT 许可。把它指向你家人的笔记本电脑吧。