Making Meaning of Morning Pages (using LLMs)

For the last 5 years or so I've been following Julia Cameron's suggestion of writing morning pages - "three pages of longhand writing, strictly stream-of-consciousness". First thing in the morning before you do anything else you dump whatever is in your mind onto the page in front of you.

Pages are meant to be, simply, the act of moving the hand across the page and writing down whatever comes to mind. Nothing is too petty, too silly, too stupid, or too weird to be included.

It's been frustrating, boring, delightful, tear-inducing and at times insightful. After about eight weeks of writing morning pages Cameron suggests you go back and read through what you wrote; or not. It's up to you.

I will sometimes go back and read through batches of entries. Just to see how much I've changed or remind myself how I actually felt about a situation at the time and not how I remember it from my current point of view. After accumulating almost 500 morning pages I thought it might be nice to have a summary for each entry and see if there was any insight I might gain from spotting trends across time. In order to do that I required something that could make meaning of my pages and provide some useful tools in summarising that meaning.

Enter ChatGPT. I've been making use of the openai playground for code analysis, knowledge acquisition, etc. But I wanted to dive a little deeper into using the api and see what I could come up with along the way. This is one of a handful of projects I came up with.

OCR

There's also the limitations of optical character recognition. I do all my morning pages on my iPad using an app called Nebo. It provides OCR and converts my hand written notes into ascii text. I'll explain more of that workflow later. The problem is that my handwriting isn't the tidiest and the OCR often confuses a stroke for something other than my intended character or word. I've tried writing neater but when I'm in the flow of releasing my thoughts onto the page the last thing I want to be thinking about is how neat my writing is. A typical example is how I write "th". The bar from the "t" often overlaps the "h" and the OCR thinks I'm writing "H". Autocorrect does go a long way in correcting some of these mistakes but in this case the app assumes I'm typing "His" instead of "this". Or, "Hat", instead of "that". It's a small annoyance but sometimes I read back through the converted text and have no idea what I was trying to say without referring to the original written document.

The Plan

So my theory was, if only a word or two is incorrectly converted, then ChatGPT should be able to infer the meaning of the sentence and replace the word with something more appropriate. "His" would revert to "this".

So I had a couple of goals for each journal entry.

  1. Clean up the existing text so that it makes more sense.
  2. Summarise the text into 3 bullet points.
  3. Add hashtags that reflect the themes of the journal entry.

Prompt Engineering

I found a post on medium that used the following prompt to fix any grammatical errors and summarise the text.

You are a note formatter and summarizer. You format notes as Markdown and fix grammar and spelling. Then you append a 3 bullet summary to the end of the note.

My first couple of tests were promising. It did clean up some basic grammatical errors but didn't always replace words that obviously didn't make sense in the context of the sentence. Also, I'm originally from South Africa and write using British English spelling. The prompt response would change words from "analyse" to "analyze".

There's definitely an art to creating a prompt that is consistent in its output regardless of the input. Adding something like "fix grammar and spelling to match British English" was easy enough to maintain the original spelling. Although, it did replace "mom" with "mum". Getting the response to correctly identify and only replace words that may have been incorrectly interpreted by the OCR was a little more challenging. Some phrases in the prompt would cause the returned sentences to be completely different. The meaning was roughly the same but it no longer read as if I had written it. And sometimes the response would change the meaning in subtle ways that didn't represent how I was feeling or thinking at the time. I appreciate that these systems are probabilistic so it's not about finding a perfect solution but one that works most of the time.

That being said the corrections had some issues. For instance the OCR had produced "My morning lab it slack.". Which would be returned as "My morning labours lack excitement." The original hand written text was, "My morning habit stack". A reference to James Clear's habit stack idea from Atomic Habits. Fair enough. Without sufficient context no one would be able to infer that from the converted text.

In some instances it did a fantastic job. With something like, "Toa's something about Ha current state of affairs that feels stale I guess.", it would return, "There's something about my current state of affairs that feels stale, I guess.". Or, "Feeling a little discombobalaked today. Its been on ongoing ting this week and I Lavant been able to put my finger on it." was corrected to "Feeling a little discombobulated today. It's been an ongoing thing this week and I haven't been able to put my finger on it."

I could probably keep tweaking the prompt but it's good enough for now. I don't want to spend more time on it and I don't want to spend more money on it. Some of these issues only show up when I convert a batch of text documents. Each batch cost started adding up. Not a lot but enough for me to consider my actions.

My final prompt was this,

You are a note formatter and summariser. You format notes as Markdown and fix grammar and spelling to match British English. If a word doesn't make sense in the context of a sentence, replace only that word with another that fits the context of the sentence. Do not change the meaning of the sentence. Then, append a 3 bullet summary to the end of the note and any hashtags that represent themes for the note from the following list: [ hashtags ]

Summaries

Summaries were interesting. I'd say overall they are accurate and useful. What I found interesting was the voice in which they were written. I think the way the journal entry was written would often determine the way the summaries were written. But sometimes the summary was written as if by someone else entirely. A pretty stock standard summary might look like this:

  • Feeling down and unmotivated due to lack of excitement in current tasks.
  • Looking to shift the culture of the company to improve the way people work.
  • Looking for activities to do today that will excite and motivate.

At times it would even write them in the first person which was fine too.

  • I'm aware of my thoughts and feelings and am taking time to coordinate my day.
  • I'm exploring options for travel and am following my passion.
  • I'm taking time to appreciate the things I have and am looking for ways to improve my connection to myself.

But, sometimes, it felt like a book report.

  • The narrator is struggling to relate to her and is looking for ways to help.
  • The narrator is grateful for the things they have and is enjoying exploring life.

Or,

  • The author considered drinking to cope with the sadness but ultimately chose not to.

At one point it ignored the direction of creating three bullet points and generated this:

Mike is processing his feelings around [redacted] and is exploring his beliefs and patterns that he has been choosing. He is afraid of being true to himself and of losing the people in his life if he changes. He prefers honest, direct, and playful relationships that are respectful and loving. He is afraid to be direct himself, but can still state his preferences without invalidating someone else's choices.

I guess my primary concern with this type of inconsistency is that if I wanted to pull all the summaries and use them for further analysis I'd prefer they were formatted in a similar way. Maybe that's asking too much (or maybe I should say please at the end of the prompt).

IA Writer

One of the reasons I like using an app that can convert handwritten text to ascii text is that I can save and search the content later. Each morning I journal in Nebo which does OCR on the fly. Then, when I'm done journaling for the day I run an apple script that preps the note and sends it to IA Writer using the current date as the name of the file.

In the past I've gone back and read through a month worth of entries and added hashtags that represent any themes that I might want to explore across multiple entries. Every time you add a hashtag, IA Writer shows that tag in a side menu so you can quickly filter all documents by the tag.

I figured why not let ChatGPT create the tags for me. Initially I modified the prompt to include the following, "Then you append a 3 bullet summary to the end of the note and 5 hashtags that represent themes for the note."

This actually worked pretty well but I quickly noticed that there was no consistency in the naming of the hashtags from one entry to the next. One would have #self_development. Another would have #selfdevelopment.

So I went through my existing hashtags and created a list of the ones I'd like to use with ChatGPT. Then I modified the prompt to this, "Then, append a 3 bullet summary to the end of the note and any hashtags that represent themes for the note from the following list: "dating", "depression", "expectations", "gift_giving", "goals", "gym", "habits", "loneliness", "mindfulness", "passion", "play", "relationships", "self_worth", "self_care", "travel", "work", "awareness", "self_development".

That did a much better job of labelling the entries. At least now I have a more consistent list of tags but I feel like I've lost out on discovering emerging trends and tags. Maybe there's a way to create a feedback loop so that after each entry the list of hashtags is compared against and updated.

Next Steps

I've been slowly making my way through some of the summaries and cross-checking the hashtags to make sure the entries were correctly labeled. Five hundred summaries is still a lot to go through and less useful without some higher level overview of them.

I had two ideas that could make these summaries more useful:

  1. I'd love to have the summary for previous years of the current day displayed to me as a notification. Kinda like how Facebook or Apple photos shows you something from the previous year. This could be a good daily check-in and provide fuel for further thought.
  2. If I wanted to get really geeky I'd love to visualise the themes that came up over time. I don't know if the data is structured or accurate enough for that. But, I imagine a chart that shows different colours for relationships, self-development, work, loneliness, etc. I could get a high level overview of the seasonality of my life. Maybe there's even some insight to be had.

Stats

  • 460 journal entries over the last 4 years.
  • Tokens ranged from about 200 to a 1000 per entry. Average seemed to be around 500.
  • Cost to process all entries + test runs = $13.00
  • Time to process. Two or three hours. I'm doing a dumb for loop. Probably more efficient to do some kind of Promise.all() asynchronously.

Final Thoughts

I'm really excited for the possibilities that LLM's can help us make meaning from personal data. I think these are the kind of things that could be built into apps in the future. What I'd like to see is a note taking app that learns my handwriting. Combine OCR with the benefits of a base LLM as well as the ability to fine-tune by selecting a particular written word and labelling it for future transcriptions.

There's also a part of me that feels like this kind of stuff shouldn't be something we pay for. I guess because this is still so new that I'm paying for an api usage I'm aware of the costs. If this were built into an app I'd probably be paying a monthly subscription and not think about the specific cost of the LLM service.

But, when it comes to using this technology for personal and, potentially, private data, where the use case is specific to language and meaning making I feel like this should be possible on device without the need for me to send my data over the internet to a paid service. Things are moving so quickly that this could be possible very soon.

PS

If you'd like to play yourself check out my Github repo. As a side note, a lot of the code was generated using GPT4. I can write python scripts but I couldn't be bothered to write the boilerplate for looping through a folder, getting the name of each file, reading the contents, prepping it for the api call, etc.