← 返回信息流

dev.to #ai短讯

Grass Gate:开放权重模型驱动的户外解锁信息流工具

dev.to作者:Rahul Roy开源AI评分:50/100

Grass Gate 是一款参与 Hacktoberfest 开源 AI 挑战的浏览器扩展。它通过限制用户在室内浏览特定网站来对抗无意识刷屏,利用 OpenStreetMap 数据生成附近的户外任务(如拍照),只有用户到达指定地点后才能解锁内容。

这是 Hacktoberfest 开源 AI 挑战赛第 1 周“去草地上走走”的参赛作品。

我做了什么

Grass Gate 是一个只在户外解锁的无限滚动锁。

浏览器扩展程序会屏蔽那些让我浪费数小时时间的网站。当我访问这些网站时,我不会看到令人内疚的倒计时器,而是会接到一个任务。我在手机上打开 Grass Gate,它会从 OpenStreetMap 中为我选择一个附近的真实地点:

💧 鸭湖在南方 330 米处。走过去并拍摄水面。

我把手机放进口袋,然后出发。到达目的地后,手机震动并发出提示音。我拍下照片,运行在手机上的开源视觉模型会检查两件事:我是否真的在户外?这真的是水吗?如果两项都通过,我会获得一个一次性使用的 6 位验证码。我将它输入到被屏蔽的页面中,我的信息流就会开放 30 分钟。之后再次锁定。

屏幕只是锁具。所有重要的体验都在户外发生。

今日任务完成野外日志

这是为那些拇指比大脑先决定打开信息流的人准备的,比如我。以下几点让它不仅仅是一个噱头:

  • 真实的地点,而非“去散散步”。任务来自你附近实际地图上的内容:树木、湖泊、公园、长椅、观景台和公共艺术。每个地点都会显示步行时间和方向。
  • 口袋导航。指南针箭头随手机转动,进度环,以及到达时的震动提示,这样你在路上就不用盯着屏幕看。
  • 野外日志。每个完成的任务都会保存其照片、地点和时间,仅保存在手机上。
  • 连续打卡、行走公里数、户外分钟数,以及 12 枚可收集的印章,每种任务类型一枚。
  • 跟随真实天空的主屏幕。景观随一天中的时间和季节而变化,设备上会计算出类似“剩余 daylight 2 小时 10 分 · 日落下午 6:44”的信息。
  • 被屏蔽的页面会记录尝试次数:“今天尝试 #7”。看到这个数字比我之前看到的任何计时器都更有效。
The browser extension's blocked page:
The browser extension's blocked page:

演示

在你的手机上试用:grassgate.vercel.app

在手机浏览器中打开它,允许访问位置和相机,然后点击“帮我找一个任务”。将其添加到主屏幕以安装应用。第一次拍照检查后,视觉模型会被缓存,即使没有信号也能工作。

该应用独立运行:包含任务、设备端照片检查、日志、连续打卡和印章。浏览器扩展程序负责添加锁定功能,而完成任务获得的 6 位验证码则用于解锁。想在办公桌前试试?在设置中开启演示模式,即可跳过步行距离检查。

代码

Rahul-Roy-Hub / grassgate

Hacktoberfest 开源 AI 挑战赛:第 1 周

你的信息流在你去户外之前将保持锁定状态。

▶ 试用:grassgate.vercel.app(请在手机上打开)

浏览器扩展程序会屏蔽你的无限滚动网站。要重新进入,请在手机上打开 Grass Gate。它会从你附近的真实地点中选择一个任务(例如“麋鹿格伦湖在东南方 430 米,去拍水吧”),然后引导你前往那里。手机上的开源视觉模型会检查照片,你会获得一个一次性使用的 6 位验证码,从而解锁你的网站 30 分钟。

屏幕只是锁具。整个体验都在户外进行。

包含内容

在手机端(PWA)

  • 来自地图的真实任务:基于 OpenStreetMap,提供你附近的树木、湖泊、公园、长椅、观景台和公共艺术,并附带步行时间和方向。
  • 口袋导航:随手机转动的指南针箭头(当手机具备指南针功能时)、进度环、OSM 步行指引,以及到达时的震动提示……

仓库:github.com/Rahul-Roy-Hub/grassgate

整个应用由纯 HTML、CSS 和 JavaScript 构成:一个可安装的 PWA,应用代码约 100 KB,无需打包工具,也无需后端。扩展程序是一个 Chrome Manifest V3 扩展。

我是如何构建它的

笔记本电脑(Chrome 扩展) 手机(PWA) declarativeNetRequest 屏蔽信息流 GPS → OpenStreetMap (Overpass) → 附近特征 “去接触大自然”页面 → 任务:树 / 水 / 公园 / 长椅 / 艺术 / 景观 [可选] 本地 LLM 生成任务文本 共享配对密钥 行走;相机在约 40–150 米范围内解锁 ◀────(仅输入一次,绝不发送至任何地方)───▶ CLIP ViT-B/32 在设备端检查照片 离线检查 6 位代码 ◀── 代码 ── 通过 → 一次性代码(有效期 5–10 分钟)

  1. 基于 transformers.js 的 CLIP ViT-B/32:裁判。开源 CLIP 模型通过 transformers.js 在浏览器中运行(约 155 MB,下载一次并缓存)。零样本分类意味着我没有训练任何东西:分类器的“知识”只是一串英文标签,这与《这甚至是一张有效的卡吗?Lambda 容器中的零样本图像分类模型》一文中描述的伎俩相同。我的版本是在手机上运行,而不是在 Lambda 中。

每张照片都会经过两项检查:

  • 是在户外吗?“户外 / 自然 / 街道”与“室内 / 房间 / 屏幕”相对比。我在样本照片上对此进行了调整:户外照片得分在 0.56–0.86 之间,室内照片在 0.20–0.29 之间,因此阈值为 0.5。它还能拒绝拍摄显示器上树木的照片。
  • 是目标物体吗?这是我第一次出错的地方。

我的第一个版本是将所有同义词的分数相加:水 + 河流 + 池塘 + 湖泊 + 喷泉。在使用模拟相机的端到端测试中,一张沙滩巾和沙地上书本的照片以 41% 的通过率通过了“水”的任务。照片中没有任何水是物体。由于十三个标签中有五个与水相关,在模型查看任何内容之前,目标类别就已经收集了约 38% 的概率。我的阈值设定为 35%。

修复方案利用了 softmax 保持对数几率差的事实,即 ln(p_a / p_b) = logit_a − logit_b:

// 最佳目标标签必须排名前 3,并且要比中位干扰项高出约 2.7 倍。
const logit = Object.fromEntries(target.map((r) => [r.label, Math.log(r.score)]));
const best = Math.max(...quest.labels.map((l) => logit[l]));
const decoyLogits = decoys.map((l) => logit[l]).sort((a, b) => a - b);
const margin = best - decoyLogits[Math.floor(decoyLogits.length / 2)];
const rank = target.findIndex((r) => quest.labels.includes(r.label)) + 1;
const targetOk = margin >= 1.0 && rank <= 3;

使用 18 个干扰项(“沙子”、“路面”、“动物”、“书”……),我所有的样本照片现在都能正确识别。那条沙滩巾会被判定为:“没看到水。看起来更像是一本书。”而花上的蝴蝶和草地上的狗则能通过。七张照片的样本量很小,因此随着我在户外进行更多测试,这些阈值会不断调整。因为它们只是我自己代码中的普通数字,所以我可以随时修改它们。

应用也会显示其工作原理。在每个结果下方,“设备端模型看到了什么”列出了实际分数。在这里,“动物”是 CLIP 的首选猜测,但草仍然排在第二位,并轻松超过了阈值:

The 'What the on-device model saw' panel: Outdoors 58%, Match for grass 92%, and CLIP's top guesses: an animal 25%, gra…
The 'What the on-device model saw' panel: Outdoors 58%, Match for grass 92%, and CLIP's top guesses: an animal 25%, gra…
  1. 基于 Overpass API 的 OpenStreetMap:任务发布者。单个 Overpass 查询会在你选择的半径内提取树木、水体、公园、树林、长椅、游乐场、观景点和公共艺术。任务地点至少距离 120 米,以确保你真的需要步行,且最后一张地图已缓存,以便在无信号时也能正常工作。如果附近没有映射数据,或者你处于离线状态,你会收到“任意地点”任务:天空、树叶、花朵、草地。
  1. 可选的本地 LLM(通过 WebLLM):叙述者。借助 WebGPU,一个在浏览器中运行的开源模型(Gemma 2 2B、Qwen2.5 0.5B 或 Llama 3.2 1B,可在设置中替换)会将每个任务重写,使其读起来像是一位朋友在催促你出门。LLM 从不决定任何关键事项。任务类型、CLIP 标签和地理围栏都是确定性的。该模型仅获取我已有的事实(地名、距离、方向、季节)并撰写文字。使用较小或替换后的模型可能会使文本质量下降,但它无法将你引导至不存在的地点。
  1. 完全无需服务器。手机和扩展程序通过链接或输入 16 位代码共享一次密钥。解锁代码是该密钥与 5 分钟时间窗口的 HMAC-SHA256 哈希值,采用与 TOTP 相同的理念,并在两端离线验证。每个任务仅生成一个代码:扩展程序拒绝重复使用并对错误猜测进行速率限制。

为什么开放创新很重要?

因为这款应用的核心是我居住和行走地点的每日带地理标签的照片。Grass Gate 不是我会通过封闭视觉 API 发布的东西。

Grass Gate(开源,设备端)封闭 API 上的相同思路
你的照片永远不离开手机你所在街区的每日照片轨迹存储在别人的服务器上
信号下载一个模型后即可在轨迹上工作每次检查都需要连接
成本每次检查 0 美元,无需密钥,无速率限制按图像付费,外加用于隐藏密钥的后端
服务器无需要用于状态管理和 API 密钥
控制权我读取模型的评分,调整阈值,并在一个下午修复了毛巾 bug来自我无法校准的黑盒的是/否判断

最后一行是开放获胜最艰难的地方。海滩毛巾 bug 之所以能修复,是因为我能看到完整的概率分布并反向推导到 logits。一个封闭的“这张照片是否包含水?”端点会给出肯定的回答,而我却没有任何方法知道原因。

存在诚实的权衡。首次 CLIP 下载约为 155 MB,ViT-B/32 也不是目前可用的最锐利的模型。但它足够小,可以在手机上运行,并且足以区分湖泊和毛巾。

奖项类别

  • Gemma 最佳应用:Gemma 2 2B 通过 WebLLM 在浏览器中完全运行,作为任务编写器,因此没有任何任务文本或位置上下文离开手机。

译文已达到本站中文翻译的字数上限,剩余内容请查看原文。

阅读原文