# Hammock: my group chat in two lines, read by Gemma inside a browser tab 🦥

> Source: <https://dev.to/aniruddhaadak/hammock-my-group-chat-in-two-lines-read-by-gemma-inside-a-browser-tab-c31>
> Published: 2026-10-22 20:55:11+00:00

*This is a submission for the [Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady](https://dev.to/challenges/hacktoberfest-week3-2026-10-19)*

**Hammock** 🦥 turns a group chat you have been ignoring into two lines:

You export a WhatsApp group (⋮ → More → Export chat → Without media), drop the `.txt` on the page, type your name, and lie back. Everything runs **inside the browser tab**: no server, no account, no API key. After the first visit it opens and runs with the Wi-Fi off.

It is for the person who opens a family or college group after a busy day, sees "312 unread", and closes the app again. You only need to know two things: did anything change, and is anyone waiting on me? Hammock answers those and skips the rest.

The laziest part needs no AI at all. Before a model wakes up, plain code:

Only what survives goes to Gemma.

**Try it:** [https://aniruddhaadak80.github.io/API_projects/hammock/](https://aniruddhaadak80.github.io/API_projects/hammock/)

Use Chrome or Edge on a laptop with WebGPU for the real experience. Two **made-up** sample chats are built in (a family group in the Android export format, a hackathon team in the iOS format), so you can try it without sharing anything. The first run downloads Gemma once (about 0.8 GB) and your browser caches it.

Hammock lives in the [`hammock/` folder](https://github.com/aniruddhaadak80/API_projects/tree/main/hammock) (MIT). No build step: one `index.html`, plain ES modules, a Web Worker for the model, and a small service worker for offline use.

```
src/core.js     parser, noise filter, "since you last spoke" window, mention finder,
                prompts, output cleaners, number check (pure functions, no DOM)
src/worker.js   the only file that touches a model (Transformers.js, WebGPU or WASM)
src/app.js      UI and worker plumbing
test/           14 node --test unit tests for core.js
docs/eval.md    what I measured, including where the small model gets it wrong
```

**Open pieces at the core**

`onnx-community/gemma-3-1b-it-ONNX`) is the default "Nap" model. On WebGPU it uses `q4f16`, or `q4` when the GPU has no fp16 support.
**The design rule: code decides, Gemma writes.**

Small models are good at compressing a messy thread into plain language. They are bad at *who did what* and at digits. So I split the work:

| Job | Who does it | 
|---|---|
| Parse Android / iOS exports, 12h and 24h clocks, day-first and month-first dates | Code | 
| Find your last message, skip the noise, count what was skipped | Code | 
| Decide which messages are aimed at you | Code (word match on your name and nicknames) | 
| Write "what happened" | Gemma | 
| Turn each "needs you" message into a to-do | Gemma, then a cleaner that rejects bad output | 
| Check every number in the summary against the chat | Code, and the UI flags anything Gemma made up | 
| Draft a reply in the tone you tap | Gemma | 

Long chats are split into chunks the 1B model can hold, summarised part by part, then merged.

**What I measured (all on made-up chats, on a 2-vCPU sandbox with no GPU)**

With the 4-bit weights the WebGPU path uses (run in Node with `onnxruntime-node`, greedy decoding, the exact prompts from `src/core.js`):

|  | Gemma 3 1B | Gemma 4 E2B | 
|---|---|---|
| Family group, line one | "The wedding of Rini is moved to December 12th due to a double booking. Train bookings are being finalized for December 11th." (9.9 s) | "Rini's wedding date has changed from 5 Dec to 12 Dec due to a double booking. A gift contribution of 2000 each is due by 1 Dec." (23.6 s) | 
| Hackathon team, line one | Got the gist, but blamed the wrong person for a broken build ❌ | Right people, and it said Meera "fixed" the Safari import when it was her cache (21.9 s) | 
| To-dos | "Book your leave for the wedding", "Call Dida this week", "Start the how-it-works section" (about 2.5 s each) | similar, a bit more specific, about 2x slower | 

That wrong-person mistake is the reason "what needs you" is never decided by the model.

**The honest bit: the CPU fallback.** Without WebGPU, Hammock falls back to WASM. ONNX Runtime Web's WASM backend has no kernel for the `GatherBlockQuantized` op in the 4-bit export (I also tried the 8-bit Gemma 3 270M export, same error), so the CPU path uses the 1 GB 8-bit 1B export. I ran the full app in headless Chromium on that path and it exposed two real bugs: the summary came back **empty**, and one to-do was the prompt's own instruction ("Start with a verb, under 12 words"). Now:

After the fixes the CPU run finished end to end in 132 s for the family sample. The retried summary was fluent but **wrong about who did what**, and I put that exact screenshot in the README rather than hiding it:

Not measured yet: speed on a real laptop GPU, Safari, Firefox, phones. If you try it, I would love a comment with your browser, GPU and how long it took.

Group chats are the most personal text most of us have: family plans, money, health updates, people's phone numbers. A closed API would mean uploading all of that to someone else's server just to be told "the wedding moved".

With open weights running in the tab:

`FileReader`. In the headless runs, every request the page made was a GET for the app's own files, Transformers.js from jsDelivr, or the model weights from Hugging Face. No request carried chat text. You can check yourself in DevTools → Network, or just switch the Wi-Fi off after the first run.
On the made-up family chat: **74 messages** since "Arjun" last spoke. Code skips **64** of them without reading (19 greetings, 16 emoji-only, 13 photos or stickers, 12 one-word reactions, 2 deleted, 2 forwards), Gemma reads the remaining **10**, and you get back two lines plus two to-dos, each with a reply draft one tap away.

I have only measured this on the two sample chats so far, so I am not going to claim minutes saved per day. What I can say: the skip and mention counts are deterministic and pinned by tests, so the "you can ignore these 64" part does not depend on the model being right.

Thanks for reading. Now go lie down. 🦥
