Welcome back.
So with our API key safely incorporated
into our script, we're almost ready to make our first call to the ChatGPT API
from Python.
So what's with the almost?
Well, let's take a closer look at this code that the OpenAI platform auto
-generated for us to find out.
Now, first, you can see that the code
calls the client .chat .completions .create method from the OpenAI library,
which basically helps us construct our request.
Now, this method obviously takes a series
of named arguments, most of which, like model, temperature, and so on, pertain to
those various knobs we can use to fine -tune the response from the API.
But what I want you to focus on now is the messages argument.
Here we have a list containing a set of dictionaries, and it looks like the first
two dictionaries correspond to the two parts of our prompt, the system prompt
and the user prompt.
So far, so good.
But now, if you look carefully, you'll see the API's response, that passive
-aggressive message it wrote for us, included in this third dictionary.
So clearly, by default, the OpenAI platform assumed we'd want to send our
prompts and the API's initial response back to the API.
But why?
So the thing about the ChatGPT -powered
API, just like ChatGPT itself, is that it is first and foremost designed to be a
chatbot, hence the name, which is capable of carrying on an extended conversation
with an end user.
So while we can engage in a simple one
-question -one -answer exchange with the API, it's designed to handle much longer,
more complex conversations.
But to do this, it needs context, that is
to say, the entire history of the conversation prior to the current response.
Now, when we use the ChatGPT website, that isn't a problem.
The software takes care of that piece for us.
I can say, for example, what college
basketball team won the national championship in 2012, then follow that up
with a related question that only makes sense in the context of this
conversation, but would not make sense in isolation.
Let's say, ChatGPT just confirmed for us
that the University of Kentucky Wildcats won the college basketball national
championship in 2012, so if I then ask who was that team's head coach, we get
the correct answer of John Calipari.
But if I had simply asked the question
who was that team's head coach without the context of the prior question,
ChatGPT wouldn't have had any idea which team we were talking about.
But when we include that as a follow -up question in an existing chat, ChatGPT is
able to answer the question, since it remembers what was said previously in the conversation.
The API, so to speak, does not work the same way.
The API doesn't remember the context of any given message we send it.
Each API call is effectively processed in isolation.
So that begs the question, how do we then
have these kinds of conversations with the ChatGBT API?
Well, the answer is simple.
By sending it the entire history of our
conversation, including both our prompts and its responses, every time we call the API.
Now, we'll get into the mechanics of how we can do all that a bit later on, but
suffice it to say, that's why the auto -generated code the OpenAI platform
generated for us assumed that we would want to include the API's responses.
But our use case here is pretty simple.
We're just looking for a simple response
to a single prompt for now, so let's remove that last dictionary from our
messages list.
Then, down below, I'll add a print
statement to see what we get in this response variable that should contain the
response from the API, and then I'll add another print statement to see the data
type of that response.
So now, running our code, what we get
back here is an OpenAI chat completion object, which we can interact with, much
like with any other object, using dot notation.
Now, digging through this chat completion
object that was returned to us in the response variable, we can see that there
is a lot of stuff going on here, mostly metadata about our request and the
response, but if we scroll over a bit and zoom in on the choices property of that
object, we see a list containing a single object, and that object contains a
property called message, and that message property is set to a
chatCompletionMessage object, which, in turn, features a content property.
And sure enough, all those layers deep, there is our API response.
So, to get to that, we'll just navigate through this object the same way we would
navigate through any deeply nested data structure, one layer at a time.
So, to get to the actual message that we're fetching out of that response from
the chatGBT API, and for the first layer to peel out of that response, I'll just
grab this choices list that is a property of the overall chat completion object
that was returned to us by the API.
And of course, I can do that with bracket
notation, just like with any other list.
Next up, using dot notation, I'll grab
the message property of that object, which is set to a chatCompletionMessage object.
So, I'll just say .message, and finally, I'll just grab the content property of
that chatCompletionMessage object, again, using dot notation.
That was a lot of digging to get what we wanted, but
at this point, I think we should be good to go.
So, let's print this content value, and then comment out our other print
statements, and then I'll make one last tweak before we hit the magic run code button.
I know, I know, we've already waited long enough.
So, I think I'd like our grumpy email to
be a bit longer than I originally specified.
So, let's go up to our user prompt and
change that request to specify that the message should be at least four
paragraphs in length.
At least almost everything.
You see, it looks like the response just cut off at the end.
So, did the API just get tired and decided it didn't feel like finishing the
message, or what?
Not exactly.
In other words, to turn one of those knobs on the proverbial API machine to
fine -tune its output.
We'll explore how to do that in the next video.
See you then.