{"slug": "sloth-recap-wake-up-to-2-lines-instead-of-200-group-chat-messages-embeddinggemma", "title": "Sloth Recap: wake up to 2 lines instead of 200 group-chat messages (EmbeddingGemma, 100% in your browser)", "summary": "A developer built Sloth Recap, a browser-only web app that condenses a group-chat export into a two-line recap plus a list of messages that need the user's attention. The app runs Google's open-weight EmbeddingGemma 300M model locally via transformers.js in a Web Worker, using WebGPU when available and WASM CPU otherwise, and falls back to TF-IDF keyword vectors if the model fails to load. On the built-in 38-message sample, the pipeline reduced the chat to two lines plus three flagged messages, and the developer reports the 4-bit model export ran roughly 3x slower than the 8-bit file on WASM.", "body_md": "*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)*\n\n**Sloth Recap** is a small web app for one very lazy moment: waking up and finding 200 new messages in a group chat.\n\nYou drop in the chat export (WhatsApp \"Export chat\" `.txt` or `.zip`, or just paste the text), type your name once, and press **🦥 Catch me up**. You get:\n\nGroup chats never sleep. In the morning you scroll through \"lol\", \"😂\", \"ok\" and three conversations happening at the same time, just to find the one question somebody asked *you*. Sloth Recap does that scrolling for you, so whoever reads the group last in the morning gets to be the lazy one.\n\nOne design rule I care about: **Sloth Recap only quotes real messages.** It picks them, it never writes new text, so it can't invent a plan nobody made. When the recap says \"Technician comes Wednesday between 9 and 12\", someone really wrote that.\n\n👉 **Live demo:** [https://asosa933.github.io/sloth-recap/](https://asosa933.github.io/sloth-recap/)\n\nClick one of the two sample chats (🏠 English flatmates or ⚽ Italian football group), then **Catch me up**. The first AI run downloads the model once (about 175 MB with WebGPU or about 310 MB on CPU) and then the browser keeps it cached. If you don't want the download, untick \"Use local AI\" and you get the simple keyword mode instantly.\n\nThe result for the flatmates chat: 38 new messages became 2 lines, plus the 3 messages that actually need me.\n\nIt also works in Italian (and on mixed-language chats), because the model is multilingual:\n\n**Wake up to 2 lines, not 200 group-chat messages.**\n\nSloth Recap reads a group chat export (WhatsApp `.txt` or `.zip`, or pasted text) and gives you:\n\nEverything runs **in your browser**. The open-weight model [EmbeddingGemma](https://ai.google.dev/gemma/docs/embeddinggemma) runs locally with [transformers.js](https://github.com/huggingface/transformers.js). There is no server, no account and no API key, and your chat is never uploaded.\n\n👉 **Live demo:** [https://asosa933.github.io/sloth-recap/](https://asosa933.github.io/sloth-recap/) (click a sample chat, then \"Catch me up\")\n\nBuilt for the DEV [Hacktoberfest Open-Source AI Challenge, Week 3: \"Slow and Steady\"](https://dev.to/challenges/hacktoberfest-week3-2026-10-19). The project was created during the Week 3 window (October 2026).\n\nOn the built-in \"Flat 3B\" sample, 38 messages arrived…\n\nIt's plain HTML, CSS and JavaScript: no build step, no backend, hosted for free on GitHub Pages. The pipeline looks like this:\n\n```\nchat export → parser → \"messages after my last one\" → drop \"ok/lol/👍\"\n            → EmbeddingGemma vectors (Web Worker) → pick key messages → group the rest\n            → 2 lines + \"needs you\" + topics\n```\n\n**The open-weight model: EmbeddingGemma.** In a Web Worker I load [`onnx-community/embeddinggemma-300m-ONNX`](https://huggingface.co/onnx-community/embeddinggemma-300m-ONNX) with [transformers.js](https://github.com/huggingface/transformers.js). It runs on WebGPU when the browser has it and on the CPU (WASM) otherwise. Every new message becomes a vector, using EmbeddingGemma's `task: sentence similarity` prompt. Then:\n\nThe **🙋 Needs you** list is intentionally *not* AI. It's simple rules: your name as a whole word or `@name`, plus question patterns in English and Italian. For \"did someone ask me something?\" I want rules that are 100% predictable.\n\n**Deterministic fallback.** If the model can't load (or you turn it off), the exact same pipeline runs on TF-IDF keyword vectors. I tested this by blocking Hugging Face in headless Chrome: the app showed \"Local AI: failed to load\" and still produced the recap in simple mode.\n\n**Making it fast on a normal laptop CPU** was the part I learned the most from. On my CPU-only test machine (headless Chrome, 38 messages):\n\nThe 4-bit export is the smaller download, but on WASM it was about 3x slower than the 8-bit file. I don't know exactly which operator is the slow one, but the measurement was clear, so the app uses 8-bit on CPU (and 4-bit only on WebGPU). Multi-threading needs a \"cross-origin isolated\" page, and GitHub Pages can't set those headers. So I added a tiny service worker (`sw.js`, about 20 lines) that adds them to the site's own files. After the first load, the model can use several CPU threads (4 on my test machine).\n\n**Testing.**\n\n`npm test`: 11 unit tests with `node:test` (WhatsApp Android/iPhone formats, US/EU dates, multi-line messages, fillers, \"needs you\", the fallback digest, reading a `.zip`).` eval/eval-model.mjs` runs the real model in Node on 5 small chats I wrote and labelled by hand (the 2 demo chats plus 3 held-out ones, one of them mixed Italian/English):\n|  | EmbeddingGemma | TF-IDF fallback | \n|---|---|---|\n| nearest message is about the same topic | 67/88 (76%) | 64/88 (73%) | \n| real topics covered by the top 3 lines | 14/15 | 14/15 | \n| messages grouped under the right line | 72/81 (89%) | 64/78 (82%) | \n| mixed-language chat, grouped right | 11/13 | 9/13 | \n\nTo be honest: it's a tiny dataset that I wrote myself, so it's a sanity check, not a benchmark. Both modes pick good lines on these chats. The model's advantage shows when it **groups** messages, especially short replies and messages that switch language (\"The heating in my room is not working\" / \"Anche da me il termosifone è freddo\").\n\n**AI disclosure:** I'm a beginner from Italy and I built this with a lot of help from an AI coding assistant (code, tests, debugging, measurements). The idea, the \"never write new text\" rule, the choices about what is AI and what is rules, and the testing are mine. I made sure I understand every file.\n\nFor this project, open weights are the whole point:\n\n`src/model-worker.js`. If a better small open embedding model comes out next month, I can try it in an afternoon, and the TF-IDF fallback means the app never depends on any single model.\nMeasured by the app itself on the built-in flatmates chat:\n\nA busier group means more reading time, but the recap is still 2 lines. 🦥\n\nThanks for reading! If your group chat export breaks the parser (there are *many* date formats out there), please open an issue with a fake example and I'll fix it. 🦥", "url": "https://wpnews.pro/news/sloth-recap-wake-up-to-2-lines-instead-of-200-group-chat-messages-embeddinggemma", "canonical_source": "https://dev.to/asosa933/sloth-recap-wake-up-to-2-lines-instead-of-200-group-chat-messages-embeddinggemma-100-in-your-1kp7", "published_at": "2026-10-20 12:07:25+00:00", "updated_at": "2026-10-20 12:18:39.562647+00:00", "lang": "en", "topics": ["artificial-intelligence", "machine-learning", "large-language-models", "ai-tools", "ai-products"], "entities": ["Sloth Recap", "EmbeddingGemma", "transformers.js", "Google", "Hugging Face", "GitHub Pages", "onnx-community/embeddinggemma-300m-ONNX", "DEV Hacktoberfest"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/sloth-recap-wake-up-to-2-lines-instead-of-200-group-chat-messages-embeddinggemma", "markdown": "https://wpnews.pro/news/sloth-recap-wake-up-to-2-lines-instead-of-200-group-chat-messages-embeddinggemma.md", "text": "https://wpnews.pro/news/sloth-recap-wake-up-to-2-lines-instead-of-200-group-chat-messages-embeddinggemma.txt", "jsonld": "https://wpnews.pro/news/sloth-recap-wake-up-to-2-lines-instead-of-200-group-chat-messages-embeddinggemma.jsonld"}}