*This is a submission for the Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady
What I Built
Every class has that WhatsApp group. 300 messages a day, memes, "ok sir", "who has the notes?" and somewhere in the middle, one message with the exam date. I mute the group to stay sane, and then I'm the one who misses the deadline.
NoticeCatcher is my lazy fix. You export the group chat as a .txt file, and it reads the whole thing for you. It pulls out only the notices that matter (exams, deadlines, workshops, cancellations) and writes a calendar file (.ics) you can open on your phone.
On the built-in fake chat from "Demo College" (40 messages), it found 4 events, noticed 1 cancellation, and set 1 vague notice aside for me to check instead of guessing a date.
Demo
There is no live demo link. The page runs on my own computer with python serve.py and only processes the built-in fake sample chat. The screenshots above are from a real run of the real model.
The main way to use it is the command line:
python cli.py samples/sample_android.txt
Real output from my run:
Events: 4, Cancelled: 1, Needs Check: 1
Event: Final Exam for CS301 | Start: 2026-10-28 10:00:00
Event: Submit Assignment 2 | Start: 2026-10-20 23:59:00
Event: Project demo | Start: 2026-10-15 14:00:00
Event: Workshop on Cloud Computing | Start: 2026-10-19 10:00:00
Cancelled: Guest lecture on Robotics
Needs Check: annual sports day | Reason: Unclear date: 'sometime next month'
Seconds taken: 68.52
Code
NoticeCatcher
Extracts notices, deadlines, exam dates, and cancellations from WhatsApp group chat exports into standard iCalendar (.ics) files.
What It Does
NoticeCatcher parses exported WhatsApp group conversations (Android or iPhone format), identifies announcements with dates or deadlines, resolves dates deterministically, and writes valid .ics calendar events.
How It Works
NoticeCatcher uses a hybrid architecture: the model proposes, plain code decides.
-
Parser (
parser.py): Reads raw text exports, handles Android (DD/MM/YYYY, h:mm am/pm - Sender: Text) and iPhone ([DD/MM/YY, h:mm:ss PM] Sender: Text) formats in 12h/24h time, preserves multi-line notices, and filters out system notifications and media lines. -
Model Extraction (
engine.py): Sends chunked messages to an open LLM (Qwen/Qwen3-8B) with strict instructions treating chat text as untrusted data. The model proposes candidates with exact date/time words copied verbatim from the text without attempting date math. -
Deterministic Resolver (
resolver.py)…
MIT licensed. 32 tests pass.
How I Built It
The one rule I followed: the model proposes, plain code decides.
- Parser (plain code). Reads both Android and iPhone export formats (DD/MM dates), joins multi-line messages, and skips system and media lines.
- Model (Qwen3-8B through Tinker). Reads the messages in chunks of about 25 and returns JSON: a title, the date words copied exactly as written (like "next Monday"), and a time. It is told never to turn those words into a real date. The chat text goes into the prompt marked as data, not as instructions.
- Resolver (plain code). This is where dates are decided. "Tomorrow" counts from the date of the message it was written in, not from today. It also checks that the source message really exists. Anything it can't pin down goes to "Needs your check" and is never guessed.
- .ics writer (plain code). Writes the calendar file in the Asia/Kolkata timezone. Cancelled notices never become events.
Why split it like this? A language model is bad at "what date is next Monday?" but good at "is this message an announcement?" So the model only does the second job, and ordinary code does the first.
I checked two dates by hand against the sample chat:
- "Project demo tomorrow" was written on 14 Oct 2026, and it resolved to 15 Oct.
- "Workshop is next Monday" was written the same day (a Wednesday), and it resolved to 19 Oct.
What went wrong: my first prompt told the model to skip vague dates. The result was "Needs Check: 0", which meant the review list could never show anything. I changed the prompt so the model includes vague notices with their original words, and the resolver now refuses to guess them. The annual sports day ("sometime next month") now lands in the check list, which is where it belongs.
Timing: the command-line run took 68.52 s for 40 messages, including model startup. Through the local web page it took 40.43 s. These are single runs, not benchmarks.
What I did not do:
- Calendar events get a default length of 1 hour, so "Submit Assignment 2" ends at 00:59 the next day.
- I only tested on fake chats, never on a real group in this post.
- I did not test whether a chat message containing instructions can trick the model.
- I did not host it. The page is local only.
Why Does Open Innovation Matter?
A class group chat is private: names, plans, half-finished conversations. So it matters to me which model reads it.
With an open-weight model, the model is one line in a settings file (MODEL in .env). I can swap it for another one without rewriting anything, and I could point the same code at a smaller model running on my own machine. Qwen3-8B is the one I used here.
Here is the honest limit: in this version, the chat text is sent to the Tinker API, so it does not stay on my device. My laptop has 4 GB of RAM, so I did not run a local model, and I did not compare against a closed model. What open models gave me in this project is the freedom to switch and to see how the pieces work together, not a privacy guarantee.
My Agent Session
I did not save a DevRelay session for this project. Claude planned the project and drafted the prompts, Antigravity (Gemini) wrote the code, and I ran everything step by step and checked the output myself.
The Lazy Payoff
I haven't had a classmate use it yet, so I won't pretend it saved anyone hours. What I can say honestly: on a 40-message chat it finishes in about a minute, and it did not guess a single date. The one notice it couldn't date came back to me as a question, and that is the kind of laziness I trust.
Top comments (0)