← Back to list

Book a Google calendar by using Gemini LLM

Hi friends, in this post, I will explain how to build a node application which connects with Gemini LLM and, using a prompt, we book a…

Edison Devadoss in YavarTechWorks · 2025-05-13 11:05 · 50 claps · 5.5 min read
#gemini #googlecalendarbookingai #geiminicalendar #google-api #calendarbookingbygemini
Open on Medium ↗
Wiki topics: LLM · Large Language Models

Book a Google calendar by using Gemini LLM

Hi friends, in this post, I will explain how to build a node application which connects with Gemini LLM and, using a prompt, we book a Google Calendar event.

https://www.photopea.com

https://www.photopea.com

Set up an account in Google APIS.

Click the link and set up a Google account, then access the API services.

Then search in the service bar “calendar” and enable the calendar API. Consider the image below as a reference.

Enable Google Calendar

Enable Google Calendar

After the calendar is enabled, configure the authorised redirect URI for authorisation.

Once authorised with our Google account, it will redirect to the configured URL and give an access code. We need this access code for Google Calendar booking.

authorization URIs configuration

authorization URIs configuration

Define the Auth callback

import Fastify from 'fastify';

const fastify = Fastify({
  logger: true
});

// Declare a route
fastify.get('/auth', async function handler(request, reply) {
  console.log('request', request);
  return { hello: request.query };
});

try {
  await fastify.listen({ port: 3000 });
} catch (err) {
  fastify.log.error(err);
  process.exit(1);
}

The above code is just a Fastify application setup and configured with one route with the GET method. In request.query We can find the access code.

$ node server.js

Now we can run the application using the above command.

Generate Gemini API

Once the Google API is configured now we can generate the Gemini API key and configuration.

Click this link to generate an API key. After generating of API key, configure it in the .env file.

GEMINI_API_KEY=

Not only the Gemini API key, but we can also configure the following in .env

GOOGLE_CLIENT_ID=''
GOOGLE_CLIENT_SECRET=''
REDIRECT_URI=''

Install the required library in our application.

$ npm install @google/genai dotenv fastify googleapis --save

Run the above command to install all required libraries.

Create aindex.js file where we can write our code for calendar booking.

import { configDotenv } from 'dotenv';
configDotenv();

import { GoogleGenAI, FunctionCallingConfigMode } from '@google/genai';
import { google } from 'googleapis';
import * as readline from 'readline';

const { GEMINI_API_KEY, GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, REDIRECT_URI } =
  process.env;

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
});

const genAI = new GoogleGenAI({ apiKey: GEMINI_API_KEY });
const geminiModel = genAI.models;

const oauth2Client = new google.auth.OAuth2(
  GOOGLE_CLIENT_ID,
  GOOGLE_CLIENT_SECRET,
  REDIRECT_URI
);

In the above, we import the library needed for the application and initialise the GoogleGenAI model and the oauthClient library.

We have used it readline for interaction with the node application via the terminal.


async function authenticate() {
  const authUrl = oauth2Client.generateAuthUrl({
    access_type: 'offline',
    scope: 'https://www.googleapis.com/auth/calendar.events'
  });
  console.log('Authorize this app by visiting this url:', authUrl);
  rl.question('Enter the code from that page here: ', async (code) => {
    try {
      const tokenResponse = await oauth2Client.getToken(code);
      tokens = tokenResponse.tokens;
      oauth2Client.setCredentials(tokens);
      calendar = google.calendar({ version: 'v3', auth: oauth2Client });
      console.log('Authentication successful!');
      queryGemini();
    } catch (err) {
      console.error('Error retrieving access token', err);
      rl.close();
    }
  });
}

The above function is for authentication with the Google API for calendar access.

rl.question It asks for our input via the terminal. Once we are authorised using authUrl, we can enter the code in our terminal or paste it.

This function generates a token for our further access. Then it will call queryGemini() function.

const chatHistory = [];

let isBooked = false;

async function queryGemini() {
  rl.question('Ask Gemini (or say "book calendar"): ', async (query) => {
    try {
      chatHistory.push({
        role: 'user',
        parts: [{ text: query }]
      });

      const result = await geminiModel.generateContent({
        model: 'gemini-2.0-flash-001',
        contents: chatHistory,
        config: {
          systemInstruction: `
You are a smart assistant that helps users with any kind of query.

If the user explicitly says they want to book a calendar, schedule a meeting, or talk to an agent, interpret it as a request to create a calendar event and use the \`create_calendar_event\` function (if enough information is available). Ask only the necessary missing details.

Once the calendar event is successfully created, return to normal assistant behavior. Do not continue suggesting or prompting about calendar bookings unless the user explicitly brings it up again.

For all other types of queries, respond normally as a helpful assistant.
`,
          toolConfig: {
            functionCallingConfig: {
              mode: FunctionCallingConfigMode.AUTO
            }
          },
          tools: tools
        }
      });

      const response = result;

      console.log('Gemini:', response.text);

      if (!isBooked && response.functionCalls?.length > 0) {
        const func = response.functionCalls[0];
        console.log('Function call received:');
        console.log('Function name:', func.name);
        console.log('Arguments:', func.args);
        const args = func.args;

        if (func.name === 'create_calendar_event') {
          await bookAEvent(
            args.title,
            args.date,
            args.time,
            args.email,
            args.timezone
          );
          isBooked = true;
        }
      } else if (response.text) {
        chatHistory.push({
          role: 'model',
          parts: [{ text: result.text }]
        });
      }
    } catch (error) {
      console.error('Error querying Gemini:', error);
    }
    queryGemini(); // Continue the REPL
  });
}

In the above code, using geminiModel.generateContent() We can interact with our Gemini LLM.

There are a few more things we configured with the generateContent method.

  1. model — AI model name with version
  2. contents — we are passing chat history — both user input and model response. We store those values chatHistory array.
  3. config — In the config, we set up system instruction, toolConfig, and tools.
  4. systemInstruction — It is a prompt message on how our system should act.

If you look at the system instructions, we mentioned the call create_calander_event function if the user requests a book an event or talk to an agent.

     toolConfig: {
            functionCallingConfig: {
              mode: FunctionCallingConfigMode.AUTO
            }

The above configuration defines the mode of function call, it can be AUTO or ANY.

If we set ANY it will call the time user chats, it AUTO means once matched with the system instruction.

Define the create calendar event function

onst tools = [
  {
    functionDeclarations: [
      {
        name: 'create_calendar_event',
        description: 'Create a calendar event based on user input.',
        parameters: {
          type: 'object',
          properties: {
            title: {
              type: 'string',
              description: 'The title of the event'
            },
            email: {
              type: 'string',
              description: "User's email of the event (e.g., edison@yavar.ai)"
            },
            date: {
              type: 'string',
              description: 'The date of the event (e.g., 2025-05-10)'
            },
            time: {
              type: 'string',
              description: 'The time of the event (e.g., 3:00 PM)'
            },
            timezone: {
              type: 'string',
              description:
                'The timezone of the event (e.g., Asia/Kolkata, America/New_York)'
            }
          },
          required: ['title', 'email', 'date', 'time', 'timezone']
        }
      }
    ]
  }
];

Using the above code, we defined functionDeclarations and set up a function named create_calendar_event and defined what the inputs are that we need to collect from the user for calendar booking.

Once the user enters the required fields for calendar booking, we can find values in response.functionCalls.

 if (response.functionCalls?.length > 0) {
      const func = response.functionCalls[0];
   console.log('func is', func);
   console.log('Function name:', func.name);
   console.log('Arguments:', func.args);
    const args = func.args;


   if (func.name === 'create_calendar_event') {
          await bookAEvent(
            args.title,
            args.date,
            args.time,
            args.email,
            args.timezone
          );
          isBooked = true;
        }
      } 
}

Now you can find values in the logs and call bookAEvent function.

async function bookAEvent(title, date, time, mail, timezone) {
  const startDateTime = new Date(`${date} ${time}`);
  const endDateTime = new Date(startDateTime.getTime() + 60 * 60 * 1000); // +1 hour

  const event = {
    summary: title, 
    start: {
      dateTime: startDateTime.toISOString(), 
      timeZone: timezone
    },
    end: {
      dateTime: endDateTime.toISOString(),
      timeZone: timezone
    },
    attendees: [
      { email: 'edisonj1996@gmail.com' },
      { email: mail }
      // Replace with extracted attendees
    ],
    conferenceData: {
      createRequest: {
        requestId: 'meet-' + Date.now(),
        conferenceSolutionKey: {
          type: 'hangoutsMeet'
        }
      }
    }
  };
  console.log('evet is', event);

  if (calendar) {
    const calendarResponse = await calendar.events.insert({
      calendarId: 'primary', // Use 'primary' for the user's main calendar
      auth: oauth2Client,      resource: event,
      conferenceDataVersion: 1
    });
    // console.log('bookAEvent is', calendarResponse);
  }
}

The above function is for creating an event in the calendar. We need to pass the following details in the resource.

  1. summary — event tittle
  2. start — start time with timezone
  3. end—end time with timezone
  4. attendees — email of all attendees.
  5. confererceData — it is for generating a g-meet link

Now, calling node index.jsWe can run the application and chat with Gemini, and book an event in Google Calendar.

References:

Access full code — https://github.com/EdisonDevadoss/gemini-calendar-booking-node-example/tree/main

Google APIs — https://console.cloud.google.com/apis

Gemini API key — https://aistudio.google.com/apikey

Thank you for reading. Have a nice day!


메타데이터
post_id
e841f2f7607f
slug
book-a-google-calendar-by-using-gemini-llm-e841f2f7607f
url
https://medium.com/yavar/book-a-google-calendar-by-using-gemini-llm-e841f2f7607f
canonical_url
https://medium.com/yavar/book-a-google-calendar-by-using-gemini-llm-e841f2f7607f
author_url
https://medium.com/@edisondevadoss
status
ok
fetched_at
2026-06-09 18:51:35