这是参与Hacktoberfest 开源 AI 挑战赛第 1 周:Touch Grass 的参赛作品
我构建了什么
在哈科特港,停电后大约两秒钟房间就变了样。风扇停了。路由器断了。笔记本电脑切到电池供电。然后有人喊“开发电机!”
以前我就只能干坐着。手机用移动数据,笔记本用电池,等着发电机启动好继续干活。
从 NEPA 断电到有人启动发电机之间的那段空档,是我一天中屏幕已经处于下风的唯一时刻。Light don go会利用它。当我的笔记本电脑切换到电池供电超过 30 秒时,一个全屏页面会覆盖在我正在做的事情之上:

10 月 8 日 12:31 的真实停电。粗线是 Gemma 的。它上面的线是代码。
它给我一个计划、一个 60 秒的伸展计时器(站起来、向上够、转肩、摸脚趾、走到户外),以及一个按钮:“I don stand up. Close am.”计时器结束时,它会说“You self don try.”在下次断电之前,这个页面不会再打开。
天空会跟随情境变化。白天是暖色调,并倒计时到下雨或日落。夜晚是暗的,计划被放在房子附近:

白天和夜晚是模拟运行(ldg simulate)。这些提示是那些运行中真实的 Gemma 输出,取自日志。
这个页面在无网络时也能用,因为路由器早就断了:它不使用网络字体,也不从 CDN 加载任何东西。
它面向任何在停电司空见惯的地方用笔记本电脑工作的人:尼日利亚、南非的轮流停电、印度和巴基斯坦的很多地方。你不需要向他们任何人解释这个问题。
你可能不认识的词(尼日利亚英语和皮钦语):
| 词 | 含义 |
|---|---|
| NEPA | 尼日利亚人至今仍这样称呼电力公司(旧称 National Electric Power Authority)。“NEPA takes light”意思是电网断电。 |
| Light don go | “停电了。” |
| Gen,“on the gen” | 电网故障时大多数家庭手动启动的汽油发电机。“On the gen”意思是启动它。 |
| Hold the gen | 让发电机保持关闭。“₦1,500 saved every hour e rest”意思是它每保持关闭一小时就省下 ₦1,500 的汽油钱。 |
| Abeg · waka · close am · fit | 请 · 走 · 关掉它 · 可能(“rain fit start” = 可能要下雨) |
| You self don try | “你做得很好。” |
| Mineral · kiosk · junction | 软饮 · 路边小店 · 小吃摊聚集的街角 |
| WAT | 西非时间,UTC+1 |
演示
在 YouTube 上观看:https://youtu.be/Zr-YILDu6JI
截至目前真实发生的停电,来自logs/outages.jsonl(2026 年 10 月 8 日和 9 日,WAT):
| 时间 | 事件 | 工具做了什么 |
|---|---|---|
| 12:23 | NEPA 断电 | 下雨路径,室内活动。Gemma超时;显示兜底句子 |
| 12:25 | 123 秒后恢复供电 | 已记录(发电机) |
| 12:31 | NEPA 再次断电 | Gemma:“Abeg 把笔记本关了,走到窗边站着伸展一下背和腿,雨下得正大。”首次通过校验 |
| 12:34 | 225 秒后恢复供电 | 已记录 |
| 12:53 | NEPA 断电 | 首次使用全屏页面的断电。Gemma:“Abeg 把笔记本关了,去小卖部买瓶冷饮,快点回来。”首次通过。事实行:约 15:00 有雨,还剩约 2 小时 |
| 13:34 | NEPA 断电,笔记本进入睡眠 | 超时,已记录兜底。Windows 事件日志显示笔记本处于 Modern Standby:断电时短暂唤醒,通话中途又睡回去,13:56 再次唤醒。模型仍处于加载状态。屏幕前没有人 |
| 10 月 9 日,07:33 | NEPA 断电 | Gemma:“Abeg 把笔记本关了,去小卖部找瓶冷饮,快点回来。”首次通过 |
它让我出门时我做了什么。我合上笔记本,在哈科特港我所在的街区外出散步,去看望了表亲,和他们的孩子一起玩。那是 10 月 9 日 07:33 的断电。大约 12:05 来电。
第一次真实停电就发现了一个 bug。详见下文。
代码
dannwaneri/light-don-go
当 NEPA 断电时,本地 Gemma 会叫你在开动发电机之前先出门。Hacktoberfest 2026 Touch Grass。
Light don go
当 NEPA 断电时,在任何人启动发电机之前,你的笔记本会叫你出门,然后自己让开。
- 检测断电:笔记本切换到电池供电达 30 秒或更久(这栋房子没有逆变器)。
- 路由器断电也能用:预报在有电时已保存;断电后不再有任何东西访问网络。
- 代码做决定,Gemma 组织措辞:规则计算日落(NOAA 公式,离线)、干燥时段和节省的 ₦,并写出事实行。本地开源权重的 Gemma 只负责写提醒语,如果其中出现任何数字、超过 20 个词,或提到灯/发电机,校验器就会拒绝它。重试一次,然后使用固定句子。
你可能不认识的词(尼日利亚英语和皮钦语):
| 单词 | 含义 |
|---|---|
| NEPA | 尼日利亚人至今仍用来称呼电力公司的叫法(即旧时的 National Electric Power Authority)。"NEPA takes light" 意思是电网停电了 |
我是怎么做的
检测。我家里没有逆变器,所以 NEPA 一停,笔记本电脑就真的靠电池供电了。psutil每 5 秒读取一次电源状态。短于 30 秒的断电算作闪断。15 分钟内第二次断电会被记录但不会提醒,这样 NEPA 反复闪灯就不会给你刷屏。
没有网络时的天气。灯一灭,路由器也跟着断。所以在有电的时候,这个工具每 30 分钟保存一次 Open-Meteo 的逐小时预报。断电之后,它只读那个文件。日落时间来自 NOAA 太阳公式,在笔记本上计算。它给出 10 月 7 日哈科特港的日落时间为 18:21;Open-Meteo 说是 18:21,sunrise-sunset.org 说是 18:22。
有一条规则必须为雨季而改。我最初把降雨概率 50% 的小时算作"湿"。10 月的哈科特港,几乎每个小时都超过 50%,于是这个工具把所有人整天都关在室内。现在只有达到 70%,或预计降雨量达到 0.5 mm 的小时才算是湿。
模型:Gemma 4 E2B,跑在我的 CPU 上。 gemma4:e2b-it-qat通过 Ollama。下载大小 4.3 GB。我的笔记本是 i5-1135G7,没有 NVIDIA GPU。实测:冷启动 14 秒,热启动 3.6 到 4.0 秒,大约每秒 15 到 20 个 token。
模型被允许做什么。这是我最在意的部分。
我的第一个版本让 Gemma 根据事实写出整条消息。在 4 次测试运行中,它把每个数字都漏掉了,还有两次把意思弄反了:
"E be like NEPA light doncomePort Harcourt…"
意思是电来了回来。
"Close your laptop now, before the generatordies…"
发电机根本没开。
对数字做检查抓不到这两处错误,因为这两句话里都没有数字。
所以我把工作拆开了:
- 代码写事实行。它说明发生了什么、雨或日落什么时候来、还剩多少分钟、省了多少奈拉。消息里的每个数字都来自代码。
- Gemma 只写提醒语。它看到三样东西:地点、情况("正在下雨"、"干燥的白天"、"天黑之后")以及由规则选出的活动。它完全看不到数字。
- 有一道守卫检查提醒语。如果它包含任何数字、超过 20 个词,或提到 NEPA、light、power 或 generator,它就拒绝这条提示。Gemma 会带着原因重试一次。如果重试也失败,就使用一个固定句子。这最多是两次模型调用,绝不循环。
拆分之后,9 次测试运行中有 9 次首次通过,我没有看到任何语义错误。
这个守卫做不到的事。它检查数字和主题,不检查语义。在一次测试运行中,Gemma 写出了“watch the rain inside the phone”,而它通过了。更大的模型会少写这种句子,但它无法在这台笔记本上运行。我选择了小模型,并接受它有时会写出奇怪的句子。
一次真实断电发现的 bug。12:23 时灯灭了,工具捕捉到了它,而 Gemma 超时了。我在做任何改动之前先做了测量。ollama ps显示模型刚刚被加载,是由那个失败的请求导致的。Ollama 会在模型空闲 5 分钟后将其卸载。我的预热在 11:53 运行过,所以在 12:23 时工具遇到了冷启动,在电池供电下,耗时超过 20 s。修复方法是一个设置:keep_alive: -1,它让 Gemma 常驻内存(占用我 15.7 GB 中的 3.9 GB)。在下一次断电时,即 12:31,Gemma 首次就给出了回答。之后一次断电,在 13:34,也超时了,但原因不同:笔记本处于睡眠状态(Windows Modern Standby)。我在归咎于这个修复之前先检查了事件日志。
所以默认设置违背了这个工具做出的唯一承诺,即在灯灭时能工作。我在模拟中不会发现这一点。
页面。一个 HTML 文件,断电数据以 JSON 形式写入其中。Edge 用--app --start-fullscreen打开它,所以没有地址栏,也没有标签页。模型的句子作为数据传入,绝不会作为 HTML 插入。一个测试向它输入一条包含</script>的提示,并检查页面不会崩溃。
测试。共有 98 个测试,其中包括一个会封锁所有网络套接字、却仍将断电路径运行到最后的测试。我还故意 8 次破坏守卫(放宽容差、移除检查),每次都有一个测试失败。
为什么开放式创新重要?
因为网络会随着灯一起断掉。
当 NEPA 断电时,我的路由器就断了,直到有人启动发电机。云 API 恰好在这个工具需要说话的那一刻无法访问。我笔记本电脑上的模型在无信号的情况下 4 秒内就能回答。另一个理由根本不需要。
它在每次断电时也不产生任何费用,这在每天都停电的情况下很重要。而且因为 Ollama 和模型是开源的,我能看到第一次真实调用失败的原因:空闲模型在 5 分钟后会卸载,而我可以更改这个设置。对于闭源 API,超时就只是超时。
奖项类别
- Gemma 最佳应用。Gemma 4 E2B(QAT)通过 Ollama 在仅用 CPU 的笔记本电脑上本地离线运行。它是系统中唯一负责写文本的部分,而护栏将其限制在小模型擅长的范围内。
这个工具迄今为止最好的结果并不在日志里。那是一个本会用来等发电机的早晨,我却和表亲的孩子们一起度过了。
