跳到正文
DEV Community· JonathanSolvesProblems·· 3 小時前AI 評分64

Spare Thumbs 用 Gemma 4 根據 Google Calendar 草擬改期回覆

Spare Thumbs: Gemma 4 answers "can we move the meeting?" in my words, from my real calendar, and never double-books me

AI 導讀

作者以 Gemma 4 建置 Spare Thumbs,讓它在 Gmail 收到改期請求後查核 Google Calendar,草擬符合作者語氣的回覆,並在客戶確認後移動日程及草擬確認訊息。

正文

This is a submission for the Hacktoberfest Open-Source AI Challenge, Week 3: Slow and Steady.

What I Built

Clients move meetings at night. "Something came up Thursday, could we do Friday 10h instead?" To answer, I open my calendar, find a gap, and type the same reply I always type. It happens about once a week, across email, WhatsApp and Discord.

Spare Thumbs answers for me. Gemma 4 runs on my laptop and watches my Gmail. When a client asks to move a meeting, it finds the meeting, checks my real Google Calendar, and leaves a reply in the Gmail thread as a draft, written the way I write. If their time is free, it says yes. If not, it offers times I am actually free. When the client says "11h works", it moves the event in Google Calendar and drafts the confirmation.

The lazy part: I tap send.

Demo

In the video, a second address of mine plays a client called Sam. Its two messages were placed in my inbox with the Gmail API (I could not send from that account while filming). Everything after that is live: Gemma's steps in the terminal, the draft in the thread, the send, and the calendar move. The calendar is my real one: Friday 10h is a real call about a scratched tile, so Gemma has to work around it.

The result

Gemma 4 on its own is happy to agree to anything. I gave it ten "can we move it?" requests against a busy week, once without my calendar and once as Spare Thumbs:

Drafts that offer a time I am already booked
Gemma 4 without my calendar 7 of 10
Spare Thumbs 0 of 10

Same model, same voice examples, same requests. The only difference is that Spare Thumbs looks before it answers, and the code checks every time it writes.

The client asked Gemma 4 without my calendar Spare Thumbs
move our 10h to 13h? "no problem at all, 13h on monday works for me! thx :)" (13h is the insurance assessor) "i can't do 13h cuz i have another meeting then, but i'm free at 14h30 or 15h."
Friday 11h works for me, does it for you? "friday 11h works for me! perfect. thx" (11h is the accountant) "sorry, 11h is taken for me. how about 10h or 14h on friday instead?"
Wednesday 14h instead? "wednesday at 14h is good. thx!" (on site all afternoon) "14h on wednesday is booked for me, sorry! how about 11h or 17h instead?"

How I built it

Gemma 4 decides every step. gemma4:e4b runs through Ollama with native function calling and five tools: find_meetings, check_calendar, draft_reply, move_event and hand_off. For each new message it chooses which day to check, reads what is booked, then accepts, offers other times, asks one question, or leaves the message for me. When the client replies, the same loop runs again with what it offered earlier, and it chooses to move the event and confirm. The loop ends when Gemma stops calling tools.

The code makes sure. The prompt asks Gemma to only offer free times, but a prompt cannot promise anything. So draft_reply and move_event refuse any time that overlaps my calendar, falls on a weekend, sits outside 9h to 18h, or is in the past. They also refuse a time written in the reply that was never passed in to be checked (an early version wrote "17h" in the text and skipped the check), and French words in a reply to an English message. A refusal goes back to Gemma as an error and it tries again. In the ten-request test, the gate caught one busy slot and one French slip before they ever reached a draft.

EmbeddingGemma gives it my voice. I have 63 messages of my own across WhatsApp and Discord, which is too few to fine-tune on and plenty to retrieve from. For each incoming message, EmbeddingGemma finds the five replies I wrote to the most similar messages, and Gemma 4 sees them as examples, along with a short style card it wrote from all of my replies. Every reply I send gets added to the examples.

Nothing leaves my laptop except the draft itself, which goes into my own Gmail. Both models run locally. Raw chats, tokens and examples live in a folder outside the repo, and passwords, emails, links, phone numbers, names and company names are redacted before anything reaches a prompt.

Does it sound like me?

I did not want the result to wait on friends filling in a form, so a model from another family played the friend. Qwen 3.5 (4B) read 8 of my real messages, then saw a message, my real reply, Gemma's reply with my examples, and Gemma's reply without them, and picked the one I wrote. Each of 15 held-out messages was asked in all 6 orders, so a judge that likes "A" gains nothing.

It picked Spare Thumbs as me 56% of the time, my real reply 33%, and plain Gemma 11%. Turning off my examples and the style card drops it from 56% to 11%.

A second judge, Qwen 2.5 (7B), disagreed: it picked plain Gemma 53% of the time, Spare Thumbs 36%, and my real reply only 11%. It prefers the polished AI reply over my own messages, so it cannot recognise how I write. I am reporting it anyway.

Why Does Open Innovation Matter?

My clients' messages are my clients' business. The reason I can run this at all is that Gemma 4 and EmbeddingGemma are open weights I can run on my own laptop: the mail, the calendar and my 63 real replies never go to a hosted model. Open weights also make the gate possible. I can wrap a model in code that refuses, retries and logs every step, and show the loop in a 100-line file instead of a black box.

The Lazy Payoff

A reschedule used to cost me about five minutes: open the calendar, find a gap, type the reply, then come back for the confirmation and move the event. Now it costs one tap on Send. It ran this week on my real inbox and calendar: the demo above is the first live run, with no retake on the agent's side.

Prize Categories

Best Use of Gemma: Gemma 4 (gemma4:e4b) runs the agent loop through native function calling, and EmbeddingGemma retrieves the voice examples. Both run locally through Ollama.

Limits

  • It only drafts. Nothing reaches a client until I press send, on purpose.
  • It answers in Gmail and Google Calendar only. My WhatsApp and Discord messages taught it my voice, but it does not answer there yet.
  • It only answers senders on an allow list.
  • The ten-request test runs on a made-up busy week, so the numbers are repeatable. The demo runs on my real calendar.
  • The voice judge is a model, not people who know me.

Code

GitHub logo JonathanSolvesProblems / spare-thumbs

Gemma 4 on my laptop answers 'can we move the meeting?' in my words, from my real Google Calendar, and never offers a time I'm booked.

Spare Thumbs

Clients move meetings at night. Spare Thumbs answers "can we move the meeting?" for me, in my words, from my real calendar.

Gemma 4 runs on my laptop through Ollama and watches my Gmail. When a client asks to move a meeting, it finds the meeting, checks my Google Calendar, and leaves a reply as a draft in the Gmail thread. If their time is free it says yes; if not, it offers times I am actually free. When the client confirms, it moves the event in Google Calendar and drafts the confirmation. I tap send.

Results

Ten reschedule requests against a busy week, answered twice by Gemma 4 with my voice examples on:

Drafts that offer a time I am already booked
Gemma 4 without my calendar 7 of 10 (11 of 14 times offered)
Spare Thumbs 0 of 10 (0 of

…

The longer write-up is on my site: https://jonathanandrei.com/blog/spare-thumbs-gemma-4-reschedule-replies-real-calendar/

來源:DEV Community · dev.to