Continuing the Conversation0:00
All right, welcome back, everybody. So what you see here is where we left off at the conclusion of our introductory Hello, World! example. But now I want to talk about how we could go about continuing the conversation. And here's what I mean. We started it by saying, well, compose a poem that explains the concept of recursion and programming, right? And it gives us a response. But what if we then want to reply back and say, okay, very good, but now make it much more silly or funny? How do we go about doing that? And actually, as it turns out, the way we go about doing that is by assuming that OpenAI has no short-term memory. And I'll show you what I mean.
And actually, as it turns out, the way we go about doing that is by assuming that OpenAI has no short-term memory. And I'll show you what I mean. Okay, so the first thing I want to do is grab this array of messages, and I'm going to extract it into its own variable. Okay, so we can do that right up here at the top. All right, so now right down here, we fetch our first response, and that happens to be the poem. So here's what I'm going to do. I'm going to push to that messages array, and this will be, well, effectively this. So I can grab that and paste it in. But now the content is going to be equal to the poem itself,
So I can grab that and paste it in. But now the content is going to be equal to the poem itself, and the role is not going to be us, the user. It's going to be OpenAI, and we usually call this assistant. Okay, so now at this point, once we get to this line, our messages array consists of our system message where we set the world. It has our initial message, and then it also has the poem response. Okay, so for example, if I were to die and dump this in the browser, let's have a look. Here we go. So now we have our messages array that contains the system message,
No Short-Term Memory1:51
Here we go. So now we have our messages array that contains the system message, our conversation starter, and then the poem response from our assistant or OpenAI. Okay, so now here's what I mean when I said we should assume that OpenAI has no short-term memory. If I want to continue the conversation, what I really need to do is send this entire array back to OpenAI. So it's almost like every time I want to continue the chat, I have to remind OpenAI of everything that was said leading up to that very moment. All right, so that's why we're now storing it within an array. Okay, so now let's clear that out, and here's what we're going to do.
All right, so that's why we're now storing it within an array. Okay, so now let's clear that out, and here's what we're going to do. We will reply, so I will push a new item to the array, like so. The role is still going to be user because that represents us, and I'll say, good, but can you make it much, much more silly? Okay, so now we can make a brand new request back to OpenAI. All right, and this time we will call it silly poem, and we'll get the response. Okay, so if we want to keep this going, once we have the response, we will once again push to the messages array. And yeah, this is what I mean when I say it can get pretty messy.
we will once again push to the messages array. And yeah, this is what I mean when I say it can get pretty messy if we don't have a little more structure in place. All right, and then finally, let's pass through the silly poem and take a look. All right, come back to the browser. All right, and here we go. So now, presumably, we have a much sillier poem about recursion. In a land where code gets giddy, there dwells a concept oh so silly. It's recursion, a joyous spree, where functions bounce like a kangaroo.
In a land where code gets giddy, there dwells a concept oh so silly. It's recursion, a joyous spree, where functions bounce like a kangaroo. You see, yeah, clearly it's taking that feedback, and it has updated the poem, which is really cool. All right, so now we have the ability to converse with OpenAI, and we didn't know how to do that in the previous episode. All right, that's pretty cool. But yeah, clearly, this just gets messy very, very quickly. So I want to finish up this video by showing you just an initial implementation that you might consider.
Creating a Chat Class3:52
So I want to finish up this video by showing you just an initial implementation that you might consider before we switch over to some dedicated packaging. All right, so here's what I want to do first. In my app directory, I'm going to create a new folder called AI. That's fine. And within here, we'll add a new class called Chat, because really, that's what we're doing here. We're chatting with OpenAI. Now, I'm not sure what we're going to add here,
We're chatting with OpenAI. Now, I'm not sure what we're going to add here, but often, I just start by thinking, if I had a Chat object, what might I want from it? Well, one thing I might want is, give me all of the messages in our conversation, in our Chat. So that's probably a method I should go ahead and implement, messages. And yeah, presumably, that's just a getter that will return a messages array. So let's go ahead and define that now. And initialize it to an empty array.
So let's go ahead and define that now. And initialize it to an empty array. Okay, what else might I want to do with a chat? Well, I might want to send a new message. Or remember, one fun thing about developing little APIs like this is, you can be as creative as you want. So if you want to keep it kind of lifelike, you could create a method called say. All right, now I'm going to say this to OpenAI, if you want. But yeah, for now, I'm just going to keep it with a little more technical.
All right, now I'm going to say this to OpenAI, if you want. But yeah, for now, I'm just going to keep it with a little more technical. I will call it sends. And how would that work? I want to send a new message, tell me a bedtime story, or something, you know, kind of dark like that. So could we make that work? Well, hmm, it sounds like I need a new method here called sends. And this will give us a message. And as we learned, let's open up a split here.
And this will give us a message. And as we learned, let's open up a split here. As we learned, what we really need to do is, excuse me, we need to append to our root messages array. So probably what we would do at this point is say, well, this messages push a new array where the role is user, and the content is whatever that message happens to be. All right, but next, this is just adding a new message. And maybe that can be useful. But the method is called sends.
Implementing Send Requests6:01
And maybe that can be useful. But the method is called sends. So we actually need to perform the API request here, don't we? So what I will do, once again, is return to routes/web.php. And yeah, we're going to grab this chunk here. And I'm going to paste it in. All right, let's import that. Of course, you could grab the underlying, what would it be? Is it a factory? Is it a pending request?
Is it a factory? Is it a pending request? I can't remember. But you could use dependency injection if you want. All right. So HTTP with token, we're going to make a POST request to the completions API. Again, all of this could be configurable. So if you want to use a unique language model for certain messages, then you could make that configurable as well and define it as a property. OK, the messages will reference that property.
then you could make that configurable as well and define it as a property. OK, the messages will reference that property. We get the response. Now we've learned the response should also be appended to the messages array. So once again, I could duplicate this and then say role assistant response. All right. And then finally, I have to decide when I call that send method, what do I want returned? Is void returned? Is the response message itself returned? Is the messages array?
Is the response message itself returned? Is the messages array? I think for now, I'd prefer that the response message is returned. So return the response. All right. So I will let you take a look at what we have so far. And yeah, we're just sort of winging it. We can tweak it if we need to. But I think this will end up being quite a bit more flexible than what we had before. OK, so now let's switch back to my routes file.
But I think this will end up being quite a bit more flexible than what we had before. OK, so now let's switch back to my routes file. And yeah, let's simplify this a little bit so we can start from scratch. Yeah, this is basically what we had. OK. So we're going to create a new chat instance. I will call it chat. I will call it chat. I no longer need this. So I will comment that out.
I no longer need this. So I will comment that out. And then we're going to say chat sends a new message. And the message is right here. So I will pass that through. And now I know what you're thinking. Wait, what about the system message? We'll do that in just a minute. But that allows me to get rid of this section here. This will give us our poem, which allows me to get rid of all of this.
But that allows me to get rid of this section here. This will give us our poem, which allows me to get rid of all of this. I no longer have to manually run this code that's already on the chat instance itself. So now I think that should do the trick. All right, let's check our work. Back to the browser. All right, very good. Now we've reproduced exactly what we had at the conclusion of the first episode. But now, yeah, this just looks much better. And it's easier on the eyes, less duplication, yada, yada, yada.
Adding System Messages8:42
But now, yeah, this just looks much better. And it's easier on the eyes, less duplication, yada, yada, yada. Okay, so now I want to finish up by tackling this system message. How do we go about that? And yeah, as always, this just sort of goes back to basic object design. So grab a sheet of paper. In a perfect world, how would you declare it? One option might be maybe you pass it as the second argument. system message goes here. You could do that.
System message goes here. You could do that. I don't love it, though. What I might like to do is declare it optionally. So maybe, remember, keep in mind, when you interact with OpenAI, it's not mandatory that you declare a system message. Again, that's only if you want to kind of narrow the world in which you want OpenAI to behave. Should it function as a tutor? Should it function as an expert?
Should it function as a tutor? Should it function as an expert? Should it function as a dummy who is sarcastic about everything? All of that could be configured as part of the system message. But yeah, it is optional nonetheless. So with that in mind, what if we just had like a setter? Something like this. Maybe system? Yeah, the problem is system is such a generic word. Maybe in the context of OpenAI, it's very clear.
Yeah, the problem is system is such a generic word. Maybe in the context of OpenAI, it's very clear. But I don't love the double words. But maybe it's better to be just crystal clear. This is for the system message. I don't know. Tell me what you think. So now I can grab this, paste it in here, and this is effectively a setter on the object. All right, so I can get rid of all of this.
and this is effectively a setter on the object. All right, so I can get rid of all of this. Now, a little cleanup. Let's import Chat and simplify that a little bit. And you know what? I could even do something like this. New Chat, or I could even use like a real-time facade if I wanted to. That might be cool. And that would allow me to do things like this. Chat::sendMessage(), which is really cool.
And that would allow me to do things like this. Chat, send a message, which is really cool. But yeah, this is sort of what we end up with. All right, new chat, declare a systemMessage, optionally, and then send this to OpenAI and fetch a response. All right, so now let's implement that method. We could do it right here. systemMessage. You're going to give us a string. So that'll be your message.
You're going to give us a string. So that'll be your message. And yeah, this is effectively what we did down here. But this time, the role will be system. And that will return. Let's make it fluent. Let's return the instance, like so. Yeah, so now notice I can fluently call this method if I want to declare a system message. Or I can skip over it entirely,
if I want to declare a system message. Or I can skip over it entirely, and it won't be included as part of the messages array. Okay, cool. And then if we want, we could do things like this. Actually, you know what? I inlined this, but now I'm going to do the opposite because I still want to interact with it. Sorry about that. Anyways, though, we have our response.
Sorry about that. Anyways, though, we have our response. What if I didn't want to say chat? I could send a new message. But maybe we could also have some aliases. Like, what if it would be nice to call reply? And reply is effectively going to do the same thing as send. So you probably have some opinions on this. Is it okay to have methods that are effectively aliases and only serve the purpose of better readability?
Is it okay to have methods that are effectively aliases and only serve the purpose of better readability? Or do you think that just sort of muddies things up and it's not necessary? Again, this is just sort of a preference personality thing. But I think it's cool if I could call a reply method. Cool. Can you make it much, much sillier? All right, so now we are continuing the conversation. Cool.
Reply Alias and Errors12:21
All right, so now we are continuing the conversation. Cool. So let's go in here, and we're going to add, at least I think it's our alias, reply, string, message. And yeah, I don't see any difference here at all. So that would just defer to this send. All right, and that will return the same response. Okay, now there's a few error-specific things we need to deal with. Like, what if there is no response?
we need to deal with. Like, what if there is no response? What if the OpenAI server is overloaded? In that case, response would be equal to null, and then we're pushing a null content to the messages array. So just keep in mind, we would need to handle some things like, well, if we have a response, or if we don't have a response through an exception or display flash message, provide some feedback, something like that.
or display flash message, provide some feedback, something like that. But for now, we could just say, well, if there's a response, then push to this array and return it. So with that in mind, in its current iteration, it could return a string or null, and that's something we should be clear about. All right, so how are we looking here? When you visit the homepage, we now have a new Chat class
When you visit the homepage, we now have a new Chat class where we can declare a system message and send a message to OpenAI to start a conversation. Then once we have a response, at that point on our chat object, we can keep the conversation going by calling this reply method or send. Same thing. That will give us our silly poem.
Same thing. That will give us our silly poem. And once again, we have now reproduced what we did at the beginning of this video, but now we've wrapped it up within a nice API. All right, let's have a look. Awesome. Okay, no mistakes, exactly the way I like it. And trust me, behind the scenes, there's usually lots and lots of mistakes.
And trust me, behind the scenes, there's usually lots and lots of mistakes. So that's a big win. All right, in a land of loops and curly braces, there lived a concept that wore funny faces. Everything is working. And I think we're in pretty good shape here. Okay, so now beginning in the next episode, in the next chapter, we're just going to start going through example after example.
in the next chapter, we're just going to start going through example after example. Maybe we want to interact with OpenAI through the command line. Maybe we want to transcribe or translate some audio. Maybe we want image generation. I'm just going to show you a huge series of fun examples that I think you will enjoy. All right, as always, I will see you in the next episode.
All right, as always, I will see you in the next episode.
