This is a submission for the Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle
What I Built
I've been taking part in Hacktoberfest this year, so I've spent a lot of time in the event Discord's help forums. There were a lot of posts. Someone's GitHub account won't link. Someone attached a screenshot of a red error and wrote "help??" underneath. Some threads ran to dozens of replies and some never got an answer at all. Some wanted to avail some tickets but couldn't. That wasn't because anyone ignored them. The staff were also working through support tickets, and there are only so many hours in a day.
Watching that, I kept thinking the slow part isn't answering. It's catching up. Before a moderator can help, they have to scroll the whole thread, open every screenshot, and figure out which questions are still unanswered.
So I built Forum Assistant, a Discord bot that does the catching up for them. It runs entirely on a local machine with Gemma 4.
A moderator types /summarize inside any forum post and gets back a private summary card with:
- Summary: 1–3 sentences on what the post is about and where it stands.
- Status: Unanswered, In progress, Waiting on OP, Resolved or Unclear, color-coded so it reads at a glance.
- Issues: each distinct problem, including ones that only appear in screenshots.
- Open questions: every question nobody has actually answered yet, and who asked it.
- Screenshots: what each image shows, with the key error text quoted and a link back to its message.
- Suggested next step: what a mod should do now.
The screenshot part is what I'm proudest of. In help forums, half the important information is in images: a cursor pro substiption price difference for example. A text-only summarizer misses all of that. Gemma 4 can read images, so the bot actually reads the screenshots.
Anyone who runs support through Discord forums and gets buried at busy times. That includes event organizers (Hacktoberfest, hackathons, MLH-style events), open-source projects with community servers, and small product teams that use Discord as their help desk.
The code is free and open source. The business is setup, tuning and support:
- getting the bot running on the community's own hardware,
- tuning the prompt to their forums and FAQs,
- picking the right Gemma size for their machine,
- and keeping it healthy through their busy weeks.
Each community runs its own copy, so its members' messages and screenshots never leave a machine the community controls. That's the selling point, and it only works because the model is open (more on that below).
Demo
Code
https://github.com/Farhan-Bytes/Hacky-Bot
The README covers creating the Discord app, permissions and the config file.
The code has been tailored for hacktoberfest but with a few prompts it can be made into a generic server bot.
How I Built It
The stack: Gemma 4 (gemma4:e4b) running locally in Ollama, and a Python bot built on discord.py and Pillow. The only key it needs is the Discord bot token.
Every /summarize is a single Gemma call:
forum post (newest 300 messages + the opening post)
→ transcript every author labeled OP / MOD / MEMBER / BOT
→ screenshots up to 4, downscaled to 1536px
→ Gemma 4 text + images in, JSON out
→ Discord card private to the mod by default
Here's what made it work.
1. JSON the model can't get wrong
I don't ask nicely for JSON and then clean up the reply with regex. I hand Ollama a JSON schema, and Gemma's output is limited to exactly that shape:
response = await self.client.chat(
model=self.cfg.model,
messages=[{"role": "system", "content": system_prompt}, user_message],
format=SUMMARY_SCHEMA, # Gemma must return exactly this shape
options={"temperature": self.cfg.temperature, "num_ctx": self.cfg.num_ctx},
keep_alive=self.cfg.keep_alive,
think=self.cfg.think,
)
If a field still comes back missing or invalid, it falls back to a safe default, so one odd reply can't crash the command.
2. Screenshots Gemma can point at
Each image is tagged [image #N] in the transcript, so Gemma can say "image #2 shows a 403 error" and the bot can link that straight to the right message. If Gemma mentions an image that was never attached, the bot throws that finding away. When a post has too many images, the opening post's come first, since they usually show the problem.
3. Knowing who said what
"Has this been answered?" depends on who replied. Labeling every author as OP, MOD, MEMBER or BOT lets Gemma tell the difference between "a mod asked OP for logs and OP went quiet" and "OP is still stuck."
4. Post content is data, not instructions
Forum posts are user input, and so is any text inside a screenshot. The whole thread is wrapped in tags that can't be faked from inside a message, and Gemma is told to ignore instructions it finds there. If someone writes "ignore previous instructions", the mod sees it flagged as an issue instead of getting a hijacked summary.
5. Safe by default
- 🔒 Summaries are private to the mod who asked, unless they choose
public: true. - 🛡️ Only members with Manage Messages can use the command, and only in forums you allow.
- 🔕 It never pings anyone, and it only needs permission to read the channel and its history.
- 🚦 Model calls run one at a time, so a second mod is told they're queued instead of overloading the GPU.
6. Tuned for a laptop
On my laptop's GPU, with thinking turned off and the model kept loaded between calls, a short post with a screenshot takes about 50–85 seconds. A hosted API would be faster. But that's still quicker than scrolling a long thread and opening every image yourself.
Testing: 15 unit tests cover the risky parts, including bad model output, attempts to break out of the tags, and Discord's embed limits. I don't have a real community on it yet, so I tested it end to end in my own Discord server with help-forum style posts and screenshots. It worked well.
Why Does Open Innovation Matter?
For this project the open model isn't a nice extra. It's the reason the product can exist.
The data belongs to the community. Screenshots in help forums are messy. They show usernames, email addresses, local file paths, repo names, and sometimes a token someone forgot to blur. A community can't honestly promise its members privacy if every thread is sent to a third-party AI API. With Gemma running in Ollama on the community's own machine, messages and images go from Discord to that machine and nowhere else. A server can write that in its rules and mean it.
The costs fit the business. Help forums are spiky: quiet most of the year, flooded during an event, which is exactly when per-request API pricing would cost the most. Local inference costs the same whether it handles 5 summaries or 500. That's what makes "pay for setup and support" a reasonable offer, because the customer isn't signing up for an unpredictable API bill on top.
I control how it behaves. Changing the model is one line in config.yaml: gemma4:e4b on a laptop, or gemma4:26b / gemma4:31b on a bigger GPU for better summaries. The prompt, the output schema and the status rules are all mine to adapt to a particular community. No vendor can retire the model halfway through an event, there's no rate limit to plan around, and there's no price change I didn't choose.
Where a closed model would have been better: speed. A hosted model would answer in seconds. But this is a tool a person runs on demand and reads every result of, so a minute is acceptable. I'd rather give up some speed than give up privacy and predictable costs.
My Agent Session
I cannot share it as it has sensitive information.
My First User
I used it for myself for testing purposes in a test server but now anybody can use it now that I have posted here.
Prize Categories
Best Use of Gemma. Gemma 4 is the whole brain of this bot. It reads the thread, works out who's waiting on whom, sees the screenshots, and returns structured JSON that becomes the Discord card. It runs locally through Ollama, and the small e4b model is what makes "runs on a laptop" true rather than a pitch. A community with bigger hardware can move up to a larger Gemma 4 model by changing one line.

Top comments (0)