ai newsMo., 2. Nov.
EilmeldungMalware „Yoba“ tarnt sich als ChatGPT- und Claude-App

Build a Telegram calendar assistant with n8n and Gemini (text and voice notes)

Adding something to a calendar on a phone is about eight taps: open the app, tap plus, type the title, pick a date, pick a start time, pick an end time, save. Saying "lunch with Priya Friday at 1" into a voice note takes three seconds. This post shows how to build a personal calendar assistant in n

dev.toMontag 10:00 · 02.11.6 Min. Lesezeit
Bild: dev.to

Adding something to a calendar on a phone is about eight taps: open the app, tap plus, type the title, pick a date, pick a start time, pick an end time, save. Saying "lunch with Priya Friday at 1" into a voice note takes three seconds.

This post shows how to build a personal calendar assistant in n8n that you talk to through Telegram, by text or voice note. A Gemini-powered AI Agent reads and writes your Google Calendar and Google Tasks, transcribes voice notes itself (no separate speech-to-text service), and replies in plain language. Everything runs on built-in n8n nodes and Gemini's free tier.

Telegram Trigger (message) -> Set: settings (allowed user IDs, timezone, default event length) -> IF: is this an allowed user? (no -> silently ignore) -> Switch: voice or text? voice -> Telegram: download file -> Gemini: transcribe audio -> Set request text -> Set request -> AI Agent chat model: Gemini memory: Simple Memory keyed on chat ID (last 10 messages) tools: Get calendar events, Create calendar event, Get open tasks, Create task, Complete task -> Code: format reply (strip markdown, split long messages) -> Telegram: send message Enter fullscreen mode Exit fullscreen mode Step 1: Lock the bot down first A Telegram bot is public: anyone who finds its username can message it. A bot connected to your calendar must only answer you. The settings node holds a comma-separated list of allowed numeric user IDs (get yours from @userinfobot), and an IF node checks every message:

{{ $json. allowed_user_ids. split ( ',' ). map ( s = > s. trim ()). includes ( String ( $json. message. from. id )) }} Enter fullscreen mode Exit fullscreen mode Messages from anyone else go nowhere. Don't reply to them at all: a reply confirms the bot is live.

Telegram voice notes arrive as a file_id. The Telegram node (resource: File) downloads the OGG file as binary, and n8n's Google Gemini node has an Audio → Transcribe operation that takes binary input directly. Gemini handles Telegram's OGG/Opus format fine, so there's no conversion step and no Whisper bill.

voice: {{ $json. message. voice?. file_id || $json. message. audio?. file_id }} exists text: {{ $json. message. text }} exists Enter fullscreen mode Exit fullscreen mode Anything else (stickers, photos) gets a short "send me text or a voice note" reply.

Both branches end in a Set node that outputs the same field, request, so the agent doesn't care which way the message came in.

This is the single most important part of the prompt. LLMs don't know what day it is, and "next Friday" is meaningless without that. The system message injects the current time in your timezone on every run:

You are a concise personal assistant that manages the user's Google Calendar and Google Tasks through Telegram. Now: {{ $now.setZone(timezone).toFormat("cccc d LLLL yyyy, HH:mm") }} ({{ timezone }}). Resolve "today", "tomorrow", "next Friday" etc. against this.

Use ISO 8601 date-times with the correct UTC offset in every tool call. Rules: - Use the tools for every calendar or task question; never guess what is in the calendar. - New events default to {{ default_event_minutes }} minutes when no end time is given. Repeat back the title, day, start and end after creating one. - A task with a deadline gets a due date; a request with a fixed time ("dentist at 3pm Tuesday") is an event. - A weekday name ("Friday") means the next one after today; if today is that weekday, ask whether they mean today or next week. - If the request is ambiguous (missing day or time), ask one short question instead of guessing. - Reply in plain text, max 8 short lines, times in 24-hour format, no markdown tables.

Enter fullscreen mode Exit fullscreen mode Notice "with the correct UTC offset". Without it, the model sends 2026-11-06T13:00:00 with no offset, Google Calendar interprets it in UTC, and your 1pm lunch lands at 1pm UTC. Including the day name ( cccc ) also helps the model with weekday arithmetic.

"Repeat back the title, day, start and end" is your safety net: you see immediately if it misheard something.

n8n's tool nodes (Google Calendar Tool, Google Tasks Tool) let the agent fill parameters using $fromAI(). Each call names the parameter and describes it for the model:

Create calendar event calendar: primary start: {{ $fromAI('start', 'Event start, ISO 8601 with offset', 'string') }} end: {{ $fromAI('end', 'Event end, ISO 8601 with offset', 'string') }} summary: {{ $fromAI('title', 'Short event title', 'string') }} location: {{ $fromAI('location', 'Location, or empty string', 'string') }} Get calendar events timeMin: {{ $fromAI('after', 'Start of the time range, ISO 8601 with offset', 'string') }} timeMax: {{ $fromAI('before', 'End of the time range, ISO 8601 with offset', 'string') }} options: singleEvents = true, orderBy = startTime, limit 25 Enter fullscreen mode Exit fullscreen mode Two settings on Get events save a lot of confusion:

For tasks, "Complete task" needs a task ID, and the description says where to get it ("ID of the task to complete, from Get open tasks"). The agent learns to call Get open tasks first, find the match, then complete it.

Set the agent's max iterations to around 8. That allows "check calendar, then create event, then confirm" without letting a confused model loop.

Simple Memory keyed on the Telegram chat ID with a 10-message window makes follow-ups work ("move it to 4pm" knows what "it" is).

A final Code node cleans the reply for Telegram:

const req = $ ( ' Calendar and tasks assistant ' ). first (). json; let text = String ( req. output || '' ). replace ( / \*\*(.+?)\*\* /g, ' $1 ' ). replace ( /^#+ \s */gm, '' ). trim (); if (! text ) text = " Sorry, I couldn't do that just now. Please try again in a minute. "; const heard = $ ( ' Use transcript as request ' ). isExecuted? `🎙 " ${ $ ( ' Use transcript as request ' ). first (). json. request } "\n\n`: ''; text = heard + text; const parts = []; for ( let i = 0; i < text. length; i += 3900 ) parts. push ( text. slice ( i, i + 3900 )); const chatId = $ ( ' Set assistant settings ' ). first (). json. message. chat. id; return parts. map ( t => ({ json: { chat_id: chatId, text: t } })); Enter fullscreen mode Exit fullscreen mode For voice notes it echoes what it heard first, so a transcription mistake is obvious.

It also splits anything over Telegram's 4,096-character message limit.

Once it's in daily use, the requests change from "add this" to "what's my day look like?" and "remind me before it starts". So I built a Pro version: safe move and cancel (the agent states which event it means and only deletes after you say yes), free/busy answers ("when am I free Thursday afternoon?"), a 7:30 morning briefing with today's events, due tasks and the weather, reminders before every meeting with the location or video link (checked every 10 minutes, never sent twice), and error alerts. It's $24 on Payhip: Telegram calendar assistant Pro. More templates are on the store and my n8n creator profile. There's also a free one on n8n.io that sends a daily Telegram digest of new YouTube videos with AI summaries, if you like the Telegram-as-interface idea.

What would you add as the next tool? Gmail and Notion are the two I get asked about most.

The free workflow JSON for this and 24 other n8n templates is on GitHub: n8n-ai-workflow-templates.

Quelle: dev.to (dev.to). Original öffnen