DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

SBOMs are essential to circumventing software supply chain attacks, and they provide visibility into various software components.

Related

  • Google Calendar Integration with Ruby on Rails Development
  • The Evolution of Software Integration: How MCP Is Reshaping AI Development Beyond Traditional APIs
  • Synergy of Event-Driven Architectures With the Model Context Protocol
  • Designing Scalable Multi-Agent AI Systems: Leveraging Domain-Driven Design and Event Storming

Trending

  • Stop Prompt Hacking: How I Connected My AI Agent to Any API With MCP
  • Top Load Balancing Algorithms: Choosing the Right Strategy
  • The Shift to Open Industrial IoT Architectures With Data Streaming
  • How to Build Your First Generative AI App With Langflow: A Step-by-Step Guide
  1. DZone
  2. Software Design and Architecture
  3. Integration
  4. [Part-2] Text to Action: Words to Calendar Events

[Part-2] Text to Action: Words to Calendar Events

Turn your words into calendar events effortlessly! This AI-powered assistant understands your text, extracts key details, and schedules events for you.

By 
Vivek Vellaiyappan Surulimuthu user avatar
Vivek Vellaiyappan Surulimuthu
·
Mar. 21, 25 · Tutorial
Likes (2)
Comment
Save
Tweet
Share
3.2K Views

Join the DZone community and get the full member experience.

Join For Free

Welcome back to the “Text to Action” series, where we build intelligent systems that transform natural language into real-world actionable outcomes using AI.

In Part 1, we established our foundation by creating an Express.js backend that connects to Google Calendar’s API. This gave us the ability to programmatically create calendar events through an exposed API endpoint.

Today, we’re adding the AI magic — enabling users to simply type natural language descriptions like “Schedule a team meeting tomorrow at 3 pm” and have our system intelligently transform such words into adding an actual calendar event action.

What We’re Building

We’re bridging the gap between natural human language and structured machine data. This ability to parse and transform natural language is at the heart of modern AI assistants and automation tools.

The end goal remains the same: create a system where users can type or say “create a party event at 5 pm on March 20” and instantly see it appear in their Google Calendar.

This tutorial will show you how to:

  1. Set up a local language model using Ollama
  2. Design an effective prompt for text-to-json conversion
  3. Build a natural language API endpoint
  4. Create a user-friendly interface for text input
  5. Handle date, time, and timezone complexities

The complete code is available on GitHub.


Prerequisites

Before starting, please make sure you have:

  • Completed Part 1 setup
  • Node.js and npm installed
  • Ollama installed locally
  • The llama3.2:latest model pulled via Ollama
Plain Text
 
# Install Ollama from https://ollama.com/
# Then pull the model:
ollama pull llama3.2:latest


Architecture Overview

Here’s how our complete system works:

  1. User enters natural language text through the UI or API call.
  2. System sends text to Ollama with a carefully designed prompt.
  3. Ollama extracts structured data (event details, time, date, etc.).
  4. System passes the structured data to Google Calendar API.
  5. Google Calendar creates the event.
  6. User receives confirmation with event details.

The magic happens in the middle steps, where we convert unstructured text to structured data that APIs can understand.

Step 1: Creating the NLP Service

First, let’s install the axios package for making HTTP requests to our local Ollama instance:

Plain Text
 
npm install axios


Now, create a new file nlpService.js to handle the natural language processing. Here are the key parts (full code available on GitHub):

JavaScript
 
const axios = require('axios');
// Main function to convert text to calendar event
const textToCalendarEvent = async (text, timezone) => {
  try {
    const ollamaEndpoint = process.env.OLLAMA_ENDPOINT || 'http://localhost:11434/api/generate';
    const ollamaModel = process.env.OLLAMA_MODEL || 'llama3.2:latest';
    
    const { data } = await axios.post(ollamaEndpoint, {
      model: ollamaModel,
      prompt: buildPrompt(text, timezone),
      stream: false
    });
    
    return parseResponse(data.response);
  } catch (error) {
    console.error('Error calling Ollama:', error.message);
    throw new Error('Failed to convert text to calendar event');
  }
};
// The core prompt engineering part
const buildPrompt = (text, timezone) => {
  // Get current date in user's timezone
  const today = new Date();
  const formattedDate = today.toISOString().split('T')[0]; // YYYY-MM-DD
  
  // Calculate tomorrow's date
  const tomorrow = new Date(today.getTime() + 24*60*60*1000);
  const tomorrowFormatted = tomorrow.toISOString().split('T')[0];
  
  // Get timezone information
  const tzString = timezone || Intl.DateTimeFormat().resolvedOptions().timeZone;
  
  return `
You are a system that converts natural language text into JSON for calendar events.
TODAY'S DATE IS: ${formattedDate}
USER'S TIMEZONE IS: ${tzString}
Given a text description of an event, extract the event information and return ONLY a valid JSON object with these fields:
- summary: The event title
- description: A brief description of the event
- startDateTime: ISO 8601 formatted start time
- endDateTime: ISO 8601 formatted end time
Rules:
- TODAY'S DATE IS ${formattedDate} - all relative dates must be calculated from this date
- Use the user's timezone for all datetime calculations
- "Tomorrow" means ${tomorrowFormatted}
- For dates without specified times, assume 9:00 AM
- If duration is not specified, assume 1 hour for meetings/calls and 2 hours for other events
- Include timezone information in the ISO timestamp
Examples:
Input: "Schedule a team meeting tomorrow at 2pm for 45 minutes"
Output:
{"summary":"Team Meeting","description":"Team Meeting","startDateTime":"${tomorrowFormatted}T14:00:00${getTimezoneOffset(tzString)}","endDateTime":"${tomorrowFormatted}T14:45:00${getTimezoneOffset(tzString)}"}
Now convert the following text to a calendar event JSON:
"${text}"
REMEMBER: RESPOND WITH RAW JSON ONLY. NO ADDITIONAL TEXT OR FORMATTING.
`;
};
// Helper functions for timezone handling and response parsing
// ... (See GitHub repository for full implementation)
module.exports = { textToCalendarEvent };


The key innovation here is our prompt design that:

  1. Anchors the model to today’s date
  2. Provides timezone awareness
  3. Gives clear rules for handling ambiguous cases
  4. Shows examples of desired output format

Step 2: Calendar Utility Function

Utility module for calendar operations. Here’s the simplified version (utils/calendarUtils.js):

JavaScript
 
const { google } = require('googleapis');

// Function to create a calendar event using the Google Calendar API
const createCalendarEvent = async ({ 
  auth, 
  calendarId = 'primary', 
  summary, 
  description, 
  startDateTime, 
  endDateTime 
}) => {
  const calendar = google.calendar({ version: 'v3', auth });
  
  const { data } = await calendar.events.insert({
    calendarId,
    resource: {
      summary,
      description: description || summary,
      start: { dateTime: startDateTime },
      end: { dateTime: endDateTime }
    }
  });
  
  return {
    success: true,
    eventId: data.id,
    eventLink: data.htmlLink
  };
};

module.exports = { createCalendarEvent };


Step 3: Updating the Express App

Now, let’s update our app.js file to include the new natural language endpoint:

JavaScript
 
// Import the new modules
const { textToCalendarEvent } = require('./nlpService');
const { createCalendarEvent } = require('./utils/calendarUtils');

// Add this new endpoint after the existing /api/create-event endpoint
app.post('/api/text-to-event', async (req, res) => {
  try {
    const { text } = req.body;
    
    if (!text) {
      return res.status(400).json({
        error: 'Missing required field: text'
      });
    }

    // Get user timezone from request headers or default to system timezone
    const timezone = req.get('X-Timezone') || Intl.DateTimeFormat().resolvedOptions().timeZone;

    // Convert the text to a structured event with timezone awareness
    const eventData = await textToCalendarEvent(text, timezone);
    const { summary, description = summary, startDateTime, endDateTime } = eventData;
    
    // Create the calendar event using the extracted data
    const result = await createCalendarEvent({
      auth: oauth2Client,
      summary,
      description,
      startDateTime,
      endDateTime
    });
    
    // Add the parsed data for reference
    res.status(201).json({
      ...result,
      eventData
    });
  } catch (error) {
    console.error('Error creating event from text:', error);
    res.status(error.code || 500).json({
      error: error.message || 'Failed to create event from text'
    });
  }
});


Step 4: Building the User Interface

We’ll create a dedicated HTML page for natural language input (public/text-to-event.html). Here's a simplified version showing the main components:

HTML
 
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Text to Calendar Event</title>
  <!-- CSS styles omitted for brevity -->
</head>
<body>
  <div class="nav">
    <a href="/">Standard Event Form</a>
    <a href="/text-to-event.html">Natural Language Events</a>
  </div>

  <h1>Text to Calendar Event</h1>
  <p>Simply describe your event in natural language, and we'll create it in your Google Calendar.</p>
  
  <div class="container">
    <h2>Step 1: Authenticate with Google</h2>
    <a href="/auth/google"><button class="auth-btn">Connect to Google Calendar</button></a>
  </div>
  
  <div class="container">
    <h2>Step 2: Describe Your Event</h2>
    
    <div>
      <div>Try these examples:</div>
      <div class="example">Schedule a team meeting tomorrow at 2pm for 45 minutes</div>
      <div class="example">Create a dentist appointment on April 15 from 10am to 11:30am</div>
      <div class="example">Set up a lunch with Sarah next Friday at noon</div>
    </div>
    
    <form id="event-form">
      <label for="text-input">Event Description</label>
      <textarea id="text-input" required placeholder="Schedule a team meeting tomorrow at 2pm for 45 minutes"></textarea>
      
      <button type="submit">Create Event</button>
      <div class="loading" id="loading">Processing your request <span></span></div>
    </form>
    
    <div id="result"></div>
  </div>

  <script>
    // JavaScript code to handle the form submission and examples
    // See GitHub repository for full implementation
  </script>
</body>
</html>


The interface provides clickable examples and a text input area and displays results with a loading indicator.

Step 5: Creating a Testing Script

For easy command-line testing to automatically detect your current timezone, here’s a simplified version of our shell script test-text-to-event.sh:

Shell
 
#!/bin/bash
# Test the text-to-event endpoint with a natural language input
# Usage: ./test-text-to-event.sh "Schedule a meeting tomorrow at 3pm for 1 hour"
TEXT_INPUT=${1:-"Schedule a team meeting tomorrow at 2pm for 45 minutes"}
# Try to detect system timezone
TIMEZONE=$(timedatectl show --property=Timezone 2>/dev/null | cut -d= -f2)
# Fallback to a popular timezone if detection fails
TIMEZONE=${TIMEZONE:-"America/Chicago"}
echo "Sending text input: \"$TEXT_INPUT\""
echo "Using timezone: $TIMEZONE"
echo ""
curl -X POST http://localhost:3000/api/text-to-event \
  -H "Content-Type: application/json" \
  -H "X-Timezone: $TIMEZONE" \
  -d "{\"text\": \"$TEXT_INPUT\"}" | json_pp
echo ""


Don’t forget to make it executable: chmod +x test-text-to-event.sh

If you know your timezone already, you could pass it directly like below

Shell
 
curl -X POST http://localhost:3000/api/text-to-event \
  -H "Content-Type: application/json" \
  -H "X-Timezone: America/New_York" \
  -d '{"text": "Schedule a team meeting tomorrow at 3pm for 1 hour"}'


Step 6: Updating Environment Variables

Create or update your .env file to include the Ollama settings:

Plain Text
 
# Google Calendar API settings (from Part 1)
GOOGLE_CLIENT_ID=your_client_id_here
GOOGLE_CLIENT_SECRET=your_client_secret_here
GOOGLE_REDIRECT_URI=http://localhost:3000/auth/google/callback
PORT=3000

# Ollama LLM settings
OLLAMA_ENDPOINT=http://localhost:11434/api/generate
OLLAMA_MODEL=llama3.2:latest

# Server configuration
PORT=3000


The Magic of Prompt Engineering

The heart of our system lies in the carefully designed prompt that we send to the language model. Let’s break down why this prompt works so well:

  1. Context setting. We tell the model exactly what we want it to do — convert text to a specific JSON format.
  2. Date anchoring. By providing today’s date, we ground all relative date references.
  3. Timezone awareness. We explicitly tell the model what timezone to use.
  4. Specific format. We clearly define the exact JSON structure we expect back.
  5. Rules for ambiguities. We give explicit instructions for handling edge cases.
  6. Examples. We show the model exactly what good outputs look like.

This structured approach to prompt engineering is what makes our text conversion reliable and accurate.

Testing the Complete System

Now that everything is set up, let’s test our system:

  1. Start the server: npm run start
  2. Make sure Ollama is running with the llama3.2:latest model
  3. Open your browser to http://localhost:3000/text-to-event.html
  4. Authenticate with Google (if you haven’t already)
  5. Enter a natural language description like “Schedule a team meeting tomorrow at 2 pm”
  6. Click “Create Event” and watch as it appears in your calendar!

You can also test from the command line:

Plain Text
 
./test-text-to-event.sh "Set up a project review on Friday at 11am"


To test if your Ollama is running as expected, try this test query:

Shell
 
curl -X POST http://localhost:11434/api/generate \
     -H "Content-Type: application/json" \
     -d '{
       "model": "llama3.2:latest",
       "prompt": "What is the capital of France?",
       "stream": false
     }'


The Complete Pipeline

Let’s review what happens when a user enters text like “Schedule a team meeting tomorrow at 2 pm for 45 minutes”:

  1. The text is sent to our /api/text-to-event endpoint, along with the user's timezone
  2. Our NLP service constructs a prompt that includes:
    • Today’s date (for reference)
    • The user’s timezone
    • Clear instructions and examples
    • The user’s text
  3. Ollama processes this prompt and extracts the structured event data:
    JSON
     
    {
      "summary": "Team Meeting",
      "description": "Team Meeting",
      "startDateTime": "2025-03-09T14:00:00-05:00",
      "endDateTime": "2025-03-09T14:45:00-05:00"
    }
  4. Our app passes this structured data to the Google Calendar API
  5. The Calendar API creates the event and returns a success message with a link
  6. We display the confirmation to the user with all the details

This demonstrates the core concept of our “Text to Action” series: transforming natural language into structured data that can trigger real-world actions.

Conclusion and Next Steps

In this tutorial, we’ve built a powerful natural language interface for calendar event creation. We’ve seen how:

  1. A well-crafted prompt can extract structured data from free-form text
  2. Timezone and date handling requires careful consideration
  3. Modern LLMs like llama3.2 can understand and process natural language reliably

But we’ve only scratched the surface of what’s possible. In future episodes of the “Text to Action” series, we’ll explore:

  1. Adding voice recognition for hands-free event creation
  2. Building agent-based decision-making for more complex tasks
  3. Connecting to multiple services beyond just calendars

The complete code for this project is available on GitHub.

Stay tuned for Part 3, where we’ll add voice recognition to our system and make it even more accessible!

Resources

  • GitHub Repository
  • Part 1: Calendar API Foundation
  • Ollama Documentation
  • Google Calendar API

Let me know in the comments what you’d like to see in the next episode of this series!

AI Google Calendar Event Integration

Published at DZone with permission of Vivek Vellaiyappan Surulimuthu. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Google Calendar Integration with Ruby on Rails Development
  • The Evolution of Software Integration: How MCP Is Reshaping AI Development Beyond Traditional APIs
  • Synergy of Event-Driven Architectures With the Model Context Protocol
  • Designing Scalable Multi-Agent AI Systems: Leveraging Domain-Driven Design and Event Storming

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • [email protected]

Let's be friends: