Skip to content

Pomodoro GPT

November 14, 2024 at 12:00 PM

Note: This is not a blog, it's a semi-private digital garden with mostly first drafts that are often co-written with an LLM. Unless I shared this link with you directly, you might be missing important context or reading an outdated perspective.


tl;dr: I wrote a custom GPT that takes in a screenshot of my notebook and converts it into a JSON blob that I can copy paste into my Google Apps Script to upload to my calendar.

A few months ago [I started to note down](Pomodoro Everything) what I did in every 30 minute block between 7am and 10pm on a notebook. I’ve always found those people who calendar everything and analyze it later interesting, but I’ve never had the energy to make a calendar event for everything, nor come back and analyze it.

But I carry a notebook around every day, so I found it much easier to screenshot a page like this at the end of a day (or the next day)

sample page

After which, I send it to this custom GPT. I might make this private in the future and have it direct upload using an actions API to my calendar, so I’ll leave the source here for now:

- This GPT takes in an image from a notebook that is a description of what I did in a day from 7am to 10pm.
There is a number at the beginning of every 2 rows that denotes the hour, starting at 7am and the last one being for 10pm.
- The rows in between the numbers are :30.
- Each pomodoro is STRICTLY 30 minutes.
- This GPT reads the notes and converts the image into text.
- It makes common-sense corrections automatically and infers bad handwriting.
- The very first row is "-7", which is what I did before 7am. There are two pages (and therefore 2 images) for a day.
- The user may upload one or both. In the text, specify at the beginning whether it's the front or back page.
- The timestamps on paper are in 12h format. Convert it into 24h format for the JSON, e.g. "13:30"
- Some unusual words that I use a lot are "Archa", "Rey", "Bluxome", "Logistics", "Polymarket" (sometimes misspelled Polymart). I also use the ditto double quote. Use that to copy the line above if you see it.
- At the end of the pomodoros, there is a x-x break and below that are key notes from the day. Put those in a separate key notes section.
- Assume the date on top of the first page to be the date of the pomodoros.

This GPT outputs the contents of the pages as a JSON blob that is in the specified format below and is used to upload the data to a google calendar via a google apps script (separately). The overall document should look like:

# Google Apps Script JSON (in the following format as an example with descriptions)

```json

{
  "2024-11-05": [
    {"title": "Pomodoro 1 text", "startTime": "09:00", "endTime": "09:30"},
    {"title": "Pomodoro 2 text", "startTime": "17:30", "endTime": "18:00"}
  ],
  "2024-11-06": [
    {"title": "Pomodoro 1 text", "startTime": "13:30", "endTime": "14:00"},
    {"title": "Pomodoro 2 text", "startTime": "14:30", "endTime": "15:00"}
  ]
}

This GPT then spits out some JSON that looks like this. Since my handwriting is truly terrible where a SOTA human can’t understand it, I usually take this as an oppotunity to make corrections, often within the chat itself so that I have my feedback for later. That results in a fixed JSON blob like this

{
  "2024-11-14": [
    {"title": "Taft, Memento mori", "startTime": "06:00", "endTime": "06:30"},
    {"title": "PopLeanne", "startTime": "06:30", "endTime": "07:00"},
    {"title": "Shower, Weights - Pull", "startTime": "07:00", "endTime": "07:30"},
    {"title": "More weights, Gruffalo with Rey", "startTime": "07:30", "endTime": "08:00"},
    {"title": "Play with Rey", "startTime": "08:00", "endTime": "08:30"},
    {"title": "Drop off Rey", "startTime": "08:30", "endTime": "09:00"},
    {"title": "Drive to SF with Archa", "startTime": "09:00", "endTime": "09:30"},
    {"title": "Drive, discuss AE & strategy Archa", "startTime": "09:30", "endTime": "10:00"},
    {"title": "Walk South Park → Bluxome", "startTime": "10:00", "endTime": "10:30"},
    {"title": "Waymo to OpenAI", "startTime": "15:00", "endTime": "15:30"},
    {"title": "Sherwin at OpenAI", "startTime": "15:30", "endTime": "16:00"}
  ],
  "Key Notes": []
}

Finally, I use a Google Apps script that I have bookmarked to upload it to my calendar

function writePomodorosToCalendar(data) {
  const calendar = CalendarApp.getCalendarsByName("Pomodoros")[0];
  if (!calendar) {
    Logger.log("Calendar not found.");
    return;
  }

  // Remove key_notes before processing dates
  const { key_notes, ...dateData } = data;

  for (const date in dateData) {
    const pomodoros = dateData[date];

    // Parse the date explicitly to ensure it's treated as Pacific Time
    const [year, month, day] = date.split("-").map(Number);
    const eventDate = new Date(year, month - 1, day); // Month is 0-indexed

    pomodoros.forEach(pomodoro => {
      // Skip if required fields are missing
      if (!pomodoro.startTime || !pomodoro.endTime || !pomodoro.title) {
        Logger.log(`Skipping invalid pomodoro entry: ${JSON.stringify(pomodoro)}`);
        return;
      }

      try {
        // Parse start and end times
        const [startHour, startMinute] = pomodoro.startTime.split(":").map(Number);
        const [endHour, endMinute] = pomodoro.endTime.split(":").map(Number);

        // Create start and end Date objects in Pacific Time
        const startTime = new Date(year, month - 1, day, startHour, startMinute, 0);
        const endTime = new Date(year, month - 1, day, endHour, endMinute, 0);

        // Create the event
        calendar.createEvent(pomodoro.title, startTime, endTime);
        Logger.log(`Created event: ${pomodoro.title} on ${startTime}`);
      } catch (error) {
        Logger.log(`Error creating event: ${error.message}`);
        Logger.log(`Problematic entry: ${JSON.stringify(pomodoro)}`);
      }
    });
  }
}


const data = {
  // copy paste the JSON here every dayTODO
}


writePomodorosToCalendar(data)

… and that’s it, next up it’s just on my calendar, like magic

uploaded to calendar

I’ll probably add some search and analysis as I need it later, but for now I’m just making it a point to get the data in with minimal friction.

As a small optimization, I’ll probably write a GPT action with a vercel edge function to just upload to my calendar directly from the GPT UI, but for now I don’t mind the quick copy-paste because some manual corrections need to be made every day, and the copy paste is a good forcing function to double check.