#2. Analyse a journal entry for unhelpful thinking patterns with ChatGPT's function calling 🤯
A deep dive into using ChatGPT's function calling capability to write prompts to get back data in any format we choose (list, objects, text, numbers etc).
Helloooo AI Alchemists! ✨🤖🧪
Last weekend, I built a program that I’ve personally wished existed for years. It’s solved a real pain point for me, and I’m so grateful it was even possible. Not only was it possible, but it was easy. Crazy easy.
This is it:
This program accepts a journal entry, then highlights all of the unhelpful thinking patterns (cognitive distortions) that are present in it, so that you can focus on reframing them (writing counter affirmations).
The main pain point this solves, is automating the pattern spotting step. Re-reading a past journal entry many times trying to spot patterns can be emotionally exhausting.
Our solution 🧯🥰
Thanks to generative AI, we can totally delegate the energy vampire pattern spotting step 🧛🏻♂️ We no longer have to read a journal entry a gazillion times while painstakingly comparing it to a list of cognitive distortions to see if there are any matches.
Now we can just pass in one of our journal entries, let it immediately spot the patterns for us, and then spend our valuable energy on just the reframing step. THIS IS MAGICAL! 🥹
Try it out for yourself hereee: Thought checker 🥳✨
Let’s dooo it ✨🤖🚀
How is it possible to pull out all of the cognitive distortions present in a journal entry? It’s all thanks to OpenAI’s recent ChatGPT function calling feature, which lets us write a prompt to retrieve specific kind of data in a format of our choosing.
The function calling feature is criminally underrated. Very few people know about it, and it’s such a super power 🦸♀️
For example, if we wanted to retrieve a list of quotes that represent cognitive distortions in our journal entry, we can do that:
Or, if we want to get back a more complex set of data, including the direct quote, the type of cognitive distortion it is, AND an explanation for why the quote represents that cognitive distortion, we can do that too:
With the function calling capability, we are able to perform extraction (quotes), categorisation (cognitive distortion types), explanation and wrangling each output into a specific format in a single step, with very little effort.
It just boggles my mind 🤯🤯🤯🤯
How to use ChatGPT functions to build a cognitive distortion checker (or your own use-case)
To make it as easy as possible for you to follow along and experiment with ChatGPT’s function calling feature, I made a CoLab notebook that you can use to run each example without having to setup your own developer environment.
All you need is an OpenAI API key. Then, open this notebook up in google CoLab, or Jupyter. You’ll be able to click the play button on each code example to run it, without having to write any of it yourself. You’ll also be able to change the prompts and property types to make it work for your own use-cases if you want.
🎁 ChatGPT function calling notebook
The anatomy of an API call to OpenAI that uses ChatGPT functions
To use the function calling capability, we need to use OpenAI’s Chat Completion API. It accepts four parameters: model, messages, functions and function_call. The functions and function_call parameters are optional.
openai.ChatCompletion.create(model, messages, functions, function call)
Model parameter
The model represents the name of the GPT model you want to use in string (text) format, e.g. “gpt-3.5-turbo”. You can see the full model list here.
Messages paramater
The message parameter accepts a list of message objects that represent a simulated conversation with the model. Each message object has two properties:
Role property
Specifies who is “speaking” during a turn in the conversation. It can be set to one of three values:
System: Sets the personality of the system, which describes how the model should behave. You can use the content property to write that description.
User: Represents the query or the prompt that is coming from the user. For example when you type something into the online version of ChatGPT and hit “send”, the role you are playing is the “user”.
Assistant: Is used to remember previous responses. For example, when user asks “who is the President of the United States” and gets a response back, if they then ask “How old are they”, the assistant allows the model to remember the previous message for context. It’s not necessary for single task responses.
Usually, the system role appears once at the start of the conversation, and then the messages alternate between user and assistant.
If you don’t provide the system role, it will be something like “You are a helpful assistant” by default. If you don’t provide any assistant roles, then the conversation history beyond one question will be forgotten. The model will only remember the most recent response to a user message.
Content property
The content property holds the actual text of a message for a given role. For the system role that would be the expected behaviour of the model. For the user that would be the question asked or instructions sent to the model (the prompt). For the assistant that would be the previous response to the user message.
In the messages parameter example above, we have set the system role to be a cooking assistant that can suggest recipes (system role). Then we simulated a conversation where a user explained what ingredients they had and asked what they could make with them. The assistant responded with suggestions given in the style of the system role personality.
Functions paramater
In the context of an OpenAI API call, a “function” refers to a custom function that extends the capabilities of the chat model. These custom functions allow us to define specific tasks or actions that the assistant can perform, in addition to its general conversational abilities.
Name property
The name property is the name of the function. For example, I want to extract all examples of cognitive distortions from a journal entry. So I decided to call my function “get_cognitive_distortions”.
Description property
The description property lets you describe what the function will be doing. The description will be like a mini prompt, so it’s better to spell out the exact behaviour you want from the function.
Parameters property
The parameters property is where the magic happens. It allows you to say “for each cognitive distortion, I want three pieces of information: the quote, the distortion name and an explanation for why the quote is an example of that distortion”.
We’ll do this by writing a JSON schema-like definition of the expected output we want our functions parameter to produce.
The reason this is called the “functions parameter”, is so that you can use the data output directly as arguments in other functions or external APIs.
Function_call parameter
The function call parameter lets you force the model to call a function that you have defined in the functions parameter. Otherwise, the model can decide whether or not to call it.
function_call={"name": name_of_function}
Calling the API
Below, is the bare minimum code you need to call the Chat Completion model using the function calling capability.
api_call = openai.ChatCompletion.create(
model=model_type,
messages=[
{"role": "system", "content": system_behaviour},
{"role": "user", "content": user_submitted_content}
],
functions=[{
"name": name_of_function,
"description": function_description,
"parameters": {
"type": "object",
"properties": properties,
"required": required_properties
}
}],
function_call={"name": name_of_function}
)
I have used variables to represent the parts that you will need to fill in yourself. For example, in order to make a call that extracts the cognitive distortions from a journal entry, we would need to update the variables to hold the following content:
model = "gpt-3.5-turbo"
system_behaviour = "You extract every single example of cognitive distortions present in a journal entry, as direct quotes."
user_submitted_content = "A JOURNAL ENTRY"
name_of_function = "extract_cognitive_distortions"
function_description = "You identify cognitive distortions present in a journal entry."
properties = {
"thinking patterns": {
"type": "array",
"items": {
"type": "object",
"properties": {
"quote": {
"type": "string",
"description": "A direct quote from the journal entry that most represents this thinking pattern"
},
"thinking pattern": {
"type": "string",
"enum": ["Black or white thinking", "Overgeneralisation", "Labelling", "Fortune telling","Mind reading", "Blaming", "Catastrophising","Discounting the positives", "Emotional reasoning"]
},
"explanation": {
"type": "string",
"description": "Explain why this is an example of the thinking pattern."
}
},
"required": ["quote", "thinking pattern", "explanation"]
}
}
},
The properties variable is the most complicated of the bunch. It’s where we define what kind of data we want our output to produce, and in what format. In the example above, I have specified that I want to get a list (array) of thinking patterns, and format each thinking pattern as an object containing the following information (properties).
A quote in string (text) format that represents a cognitive distortion.
A thinking pattern label that describes what kind of cognitive distortion the quote is. The thinking pattern can be one of 11 types, which are specified using the “enum” (predefined list of values).
An explanation in string (text) format that explains why the quote is an example of a cognitive distortion.
Access the data
To access the data produced by the Chat Completion API call, you can write the following:
import json
output = api_call["choices"][0]["message"]
data = json.loads(output["function_call"]["arguments"]) if output.get("function_call") else {}
thinking_patterns = data.get('thinking patterns', [])
print(thinking_patterns)
This will give you back the raw data in the format that you defined in the function call properties property. It will look something like this:
Putting it all together, this is the entire code snippet that will return all cognitive distortions present in a journal entry. All you need to do is enter your API key.
import openai | |
import json | |
openai.api_key = "YOUR API KEY" | |
journal_entry = """ | |
Today was terrible, just like every other day. It started off with me burning my toast—what a perfect example of how I can't do anything right. Clearly, I'm a total failure, not just in toasting bread but in life. I'm so clumsy and useless; it's no wonder people don't want to be around me. | |
I got to work late because of traffic. As I walked in, I caught a glimpse of my boss's face, and I knew he was thinking, "Here's that useless employee who can't even show up on time." Everyone at work must hate me; it's the only explanation. To top it off, a meeting was scheduled for tomorrow, and I'm convinced it's going to be about laying people off. I'm sure I'll be the first one to go. | |
My colleague complimented me on my presentation, but she was just being nice. Any idiot could have done it, and it probably didn't even matter because I stuttered during the Q&A. My whole career is a joke, built on some lucky breaks. | |
I came home, and the house was a mess. I should be better at keeping things clean. Anyone else would be. My partner said it was okay, but he must be so disappointed in me. I'm a disappointment to everyone; I'm sure of it. If I were a better person, I would have a cleaner house, be more punctual, and wouldn't mess up simple things like making toast. I should be more disciplined, more organized, more everything. | |
I got an email from an old friend inviting me to a party, but I already know I won't go. They wouldn't have invited me if they knew how pathetic I am. I'll just mess things up and make it awkward for everyone. It's better that I don't go; I don't want to ruin their good time. I blame myself for not being the person everyone wants me to be. | |
At the same time, if people were more understanding, they'd get why I'm like this. But they won't because people are generally terrible and uncaring. It's their fault I feel so miserable. | |
So, another day ends, and the cycle continues. I'm trapped in this pit of despair because of who I am—a complete and utter failure. There's no way out. | |
""" | |
# Make API call with function calling capability | |
api_call = openai.ChatCompletion.create( | |
model="gpt-3.5-turbo", | |
messages=[ | |
{"role": "system", "content": "You extract every single example of cognitive distortions present in a journal entry, as direct quotes."}, | |
{"role": "user", "content": journal_entry} | |
], | |
functions=[{ | |
"name": "extract_cognitive_distortions", | |
"description": "You identify cognitive distortions present in a journal entry.", | |
"parameters": { | |
"type": "object", | |
"properties": { | |
"thinking patterns": { | |
"type": "array", | |
"items": { | |
"type": "object", | |
"properties": { | |
"quote": { | |
"type": "string", | |
"description": "A direct quote from the journal entry that most represents this thinking pattern" | |
}, | |
"thinking pattern": { | |
"type": "string", | |
"enum": ["Black or white thinking", "Overgeneralisation", "Labelling", "Fortune telling","Mind reading", "Blaming", "Catastrophising","Discounting the positives", "Emotional reasoning"] | |
}, | |
"explanation": { | |
"type": "string", | |
"description": "Explain why this is an example of the thinking pattern." | |
} | |
}, | |
"required": ["quote", "thinking pattern", "explanation"] | |
} | |
} | |
}, | |
"required": ["thinking patterns"] | |
} | |
}], | |
function_call={"name": "extract_cognitive_distortions"} | |
) | |
# Access output | |
output = api_call["choices"][0]["message"] | |
data = json.loads(output["function_call"]["arguments"]) if output.get("function_call") else {} | |
thinking_patterns = data.get('thinking patterns', []) | |
print(len(thinking_patterns)) | |
print(thinking_patterns) |
Wrap up 🌯
Woo hoo, that was fun!
The API call we crafted extracted quotes, categorised them into types of cognitive distortions, and even provided explanations. The best part? It’s all in one single step, absolutely magical! 🪄
I’ve shared a CoLab notebook so you can just open up the notebook, click ‘play’ on the code cells, and let the magic unfold! 🥳
CoLab Notebook 🎁: ChatGPT function calling notebook
You can easily tailor this to meet your own unique needs. The function calling capability is a magical toolbox, just waiting to be unlocked with your creativity 🛠🌈
If you need any help setting this up for your own use-cases, reach out to me on LinkedIn, we can set something up! 😄
Until next time,
Stay sparkly ✨