"WEBVTTKind: captionsLanguage: enIn this project-based course, you will learn how to build AI-powered appswith the chat GPT, DALL-E, and GPT-4 APIs.Tom Chant developed this course.Tom is a front-end developer and course creator with Scrimba.Hey there free code campers and welcome to this interactive coursewhere you are going to build mind-blowing AI-powered applicationswith features that didn't seem possible even just a few months ago.We'll be starting with the very basics so you don't needany previous knowledge of the OpenAI API.In fact, the only prerequisites for this courseare basic vanilla JavaScript and some curiosity.Now the special thing about this course is that it's project-basedand it comes with a ton of challenges and that meansyou're going to have your hands on the keyboard, writing code,and tackling challenges throughout.And if you're wondering how you can get your hands on the project code,don't worry, we've got you covered.In the interactive version of this course over on Scrimba,you can pause the video, edit the code, and run the projectsright there in your browser.Or if you prefer, you can download the code from those scrimsand run the projects locally.The link is right down there in the description.Oh, one last thing before we start.If you enjoyed this course, please hit that thumbs upright here on YouTube.That will be much appreciated.And if you'd like to get in touch, reach out to me on Twitter.I am @tpchant.OK, let's get started.Welcome to building AI apps with chat GPT, DALL-E, and GPT-4.I am super excited to bring you this courseon the technology everybody is talking about.We are going to study how to use the OpenAI API.We'll be using various OpenAI models,including the latest GPT-4 model.We'll be looking at prompt engineering.We'll be building chat bots.And we'll be fine tuning a model on our own data.And along the way, of course, there will be lots moreand plenty of challenges.Now, I need to say a quick word about GPT-4.We'll be using the GPT-4 API in the second project in this course.Now, at present, there is a waiting listto get your hands on the API.No doubt in the near future, the waitlist will goand the API will be available to everybody.But for now, while the waitlist exists,why not click on this screenshot, which will take you through to the signup pageand you can join the waiting list there if it still exists.OK, so what are we going to build?We'll start off by exploiting the power of OpenAIto be creative and generate human-standard words and imagesto build this cool movie pitch app,which turns a one-sentence idea into a full movie outline.Then we'll use the GPT-4 model to create an Ask Me Anything chat botcalled Know It All.And we'll use a Google Firebase databaseso the user can persist the conversation they have with the chat botand pick it up at a later date after refreshing the browser.Lastly, we're going to stay with the chat bot concept.But under the hood, everything will be different.We will enter the world of fine-tuning.This is where we upload our own datasetand we create a chat bot that can answer specific questionsfrom our own data.This skill is really essentialif you want to use a chat bot for a specific purpose,such as to handle customer service issues with your company.And with this project, we'll also learn a really neat skillfor whenever you're working with APIs with secret keys.We'll look at deploying the site with Netlify with the API key hiddenso you can share your project without fear of the API key being compromised.This solves the really big problem that we havewhen we're using APIs with secret keys in front-end projects.Now, there are not too many prerequisites for this course.We're going to be working in vanilla JavaScriptand I'll assume you have a reasonable knowledge of it.Now, the JavaScript in this isn't very complicated for the most part.As long as you understand the basics of a fetch request,you'll be absolutely fine.And if you're rusty on fetch requests, don't worry at all.We'll actually go through it all step by stepand I don't think you'll have a problem.Apart from that, we'll be focusing fully on the AIand working through it stage by stage.Who am I?My name is Tom Chant and I'll be your tutor for this course.You can find me on Twitter.My handle is at tpchantand it's always good to hear how you got on with the course.Now, before you get started,why don't you head over to Scrimba's Discord serverand go to the Today I Will channeland let the community know that you're starting this course.Studying is more fun and more productive when it's done together.So, why not interact with fellow students on the Discord community,encourage each other and help each other along.And then, without further ado, let's jump straight in to the first project.In 2006, Terry Rocio and Bill Marcillesold the rights to the Denzel Washington film Deja Vufor a record-breaking $5 millionand it went on to gross more than $180 million worldwide.Have you ever dreamed of making it big in the movies,coming up with that one idea that will make you richbeyond your wildest dreams?Well, the most important thing is to be awareof your wildest dreams.Well, the most successful projects start with one single idea,but once you've had that idea, you need to work with it,brainstorm around it, spend hour upon hour working late into the nightto forge it into something marketable.Or do you?What if you could take one simple idea, just a single sentence,and let the power of OpenAI's large language modeldo the rest of the work for you?What used to be science fiction is now science fact.This is movie pitch, and on the outside, it is so simple.We put a one-sentence idea for a movie in here,we click send, and that is all we have to do.We sit back and we wait for maybe 10 seconds or 15 seconds,and then what we get back when OpenAI has done its thingis the makings of a great movie.We get some artwork for the cover, a great title,and a list of stars, and most importantly of all,we get the synopsis that brings the idea to life,and all of this is brought to us by the power of OpenAI.Now, to get this app working, we have got some work to do.So what will we be studying?Well, we will be using the OpenAI API.We'll be working with models and understanding what tokens are.We'll learn about crafting prompts and how to tweak those promptsto get results and how we can use examples to train the model.We'll be looking at extracting information from textsand also generating images just with words,and by the end of all that, we'll have a great foundationin how to use OpenAI in front-end projects.Now, I want to give you a warning.As we build this project, the API key for OpenAIwill be sat there on the front end, and that means it's visible.Anybody could go in through DevTools to the Network taband they could steal your API key.Now, while you're developing locally, that is fine,but don't share your project with an API keyor publish it to GitHub without ignoring the API keybecause that will compromise the API key.Now, later in this course, but not in this project,we're going to look at how we can deploy our appswith the API key safely stored on a serverwhere no one else can see it.But in the meantime, just be mindful of what you're doingwith your API key.OK, so when you're ready, let's jump into the codeand check out the HTML and CSS that I've got waiting for you.So let's have a look at the code that we've already got,and then we'll get straight on to the AI.So here in index.html, there's nothing particularly strangeor unusual going on.I've bought in a couple of Google fonts.We've got Playfair and Poppins.And then down in the body, we've got a header sectionwhich has just got the movie pitch logothat you can see right here.And then underneath that, we've got a main,and that is divided up into two sections.This first section here is all about the setup,and that is everything that you can see right here.So this is where we collect the user's ideawith this text area, and we interact with the movie boss.And you can see that we've got his speech bubble right herewith this rather braggadocious statementthat we've actually got hard coded right here in the HTML.Now, the second section that we've got down here,this is dedicated to the output.This is where we'll actually display the finished productthat the AI creates for us.Now, we can't see that section in the mini browser at the moment,because if we have a look at the CSS,it's actually set to display none.So we'll bring that into view when we're ready for it.Now, sticking with the CSS, we've got a bunch of styles in here.It's really unlikely that there's anything particularly new or strange,but by all means, feel free to pause and familiarize yourself with it.To be honest, we won't be referring to it that much as the course goes on.We'll just touch on it now and again as we need to.Now, over in index.js, we have already got a little bit of JavaScript.I've taken control of the three elementsthat we're actually working with already.So we've got the text area, which we've already seen down here.The setup input container, that is the container for the text area and the button.And then we've also taken control of the movie boss text,and that is what you can see right here inside this speech bubble.Now, we've got an event listener and it's listening out for clicks on this button.And when it detects a click, it does a couple of things.Firstly, it checks if there's anything inside the text area right here.If there isn't, it does nothing.If there is, it will replace this text area and this button with a loading GIF.And we're just bringing that in right here from the images folder.And also, it will update the speech bubble with some new text.This is actually hard coded into the JavaScript.And that is actually the last bit of human written textthat you're going to see for a while.From this point onwards, we'll mostly be working with AI generated text.Let's just put something in that text area and check it's working.So there's my one sentence idea for a movie.An evil genius wants to take over the world with AI,and only one brave mouse can stop him.Let's hit send.And as soon as we do that, we get this loading SVGjust to communicate to the user that something is happening.And we've updated the speech bubble.Just wait a second while my digital brain digests that.Okay, so everything is working as we want it to.And the next thing we need to do is start applying some AI to this.We want to actually get an AI generated response to our idea.But before we take the first step into this mystical and magical world of AI,we need to talk about some more mundane matters,like how we can actually access the open AI API from within our app.That's how we'll get our hands on these powers.So let's come on to that next.Next, let's get our hands on an open AI API key.And that means signing up.So why don't you head over to the open AI homepage?And this slide is actually a clickable link.So if you just click on this screenshot, it will take you straight there.Now, when you're there, just pause for a momentto check out some of these really beautiful imagesthat they've created with their Dali image generation model.And we will be looking at image generation later in this course.Now, once you've feasted your eyes on the pictures,head over to where it says API.And from there, you'll need to go to sign up.And then you can choose your sign up method,and you'll need to confirm with a phone number.Now, once you're in from the dashboard,you can click your avatar up here and select View API Keys.Now, they only show you the API key once when it's first generated.After that, it will be obscured like this.So be sure to copy and paste it somewhere safe as soon as you get it.But if you lose it, don't worry.From here, you can actually delete it and get a new one.And like all API keys, be sure to keep it secret.In this project we're building, you will see my API key.But rest assured that by the time this recording goes public,I will have deleted it.OK, so that's the API key.Now, while we're here, let's just say a quick word about credit.If we click on Usage here, it will take us through to a pagewhere we can see how much credit we've got remaining.Now, at the time of recording, when you sign up,you get some free credit to play with.I got $18 of credit, which was valid for three months.And it actually looks like I'm nearly through that.But I have been a heavy user.So you'll probably find that the free credit you getwill get you a very long way.Now, when that credit has expired or been used up,it is a pay as you go model.Check the website for the latest info on that.OK, now let's take our API key and build our first request.When you're ready for that, let's move on.Now we've got our API key, we can start using the API.But before we can make our first fetch request,we need an API endpoint.Let's head back to the OpenAI websiteand click through to the docs.And this slide is a clickable link, of course,and it will take you straight there.Now, the OpenAI docs are pretty comprehensive.And right here on the first page,it tells us that the completions endpointis at the center of our API.OK, that sounds interesting, the completions endpoint.We're going to check it out.But before we do that, you might wellbe asking, what is a completion?And completion is a word used a lot in OpenAI.So let's say you want some information,like you want to know who the first person to walkon the moon was.Let's send that question to OpenAI via the API,and it will think about it and send back a completion.And that completion is, of course, Neil Armstrong.So in the world of OpenAI, a completionis a response from the API that fulfills your request.OK, let's click through to the completions endpoint sectionin the docs.And here we get a ton of info and some code examples.And each example is given in node.js, PHP, and curl.But what I want to focus on is this.We have the completions API endpoint right here,and it tells us we can use the POST method.So now we've got that info.Let's come back to index.js, and I'mgoing to save it in a const called URL.And in the next scrim, let's start writing a fetch request.Let's start this API call by laying outthe bare bones of the fetch request.So we need fetch, and then we open up the brackets,and we pass in the completions endpoint,and we've got that saved here as URL.Now we need an object, and inside this object,we're going to need method, headers, and body.And if we check back with the docs,we know that the method is POST.It tells us that right here next to the endpoint.Now the docs don't actually give us an example fetch requestin JavaScript, but they do give us this curl example,and we can adapt it.So let's take a closer look.Our headers are going to need a content type of applicationJSON, and we'll also need an authorization of bearerwith our API key.So let's go ahead and put those in.OK.Now we need a body, and this is wherewe get into open AI specifics.The body for an open AI request needs a model and a prompt.So I'll come down here and add the body,and then I'm going to say JSON.stringify,and I'll pass in an object with model and prompt.Now if we look back at this screenshot,it actually gives us a model right here, text-davinci-003.So let's break the golden rule of codingand just copy a line of code that we don't actuallyunderstand.We haven't discussed what open AI models actually areor what options we have available to us yet,but what I want to do is get this example working,get the first API request actually into our app,and then we'll rewind and talk about models in more detail.For now, just know that open AI has got various modelsthat we can use, and today we're goingto use this one called text-davinci-003.OK.So I'll put that in a string right here.OK.So we've got the model, and now we need the prompt,and we're going to talk about prompts a lot in this course.But for now, what we need to know is this.In this example that we saw in the previous scrim,we asked a question.Who was the first person to walk on the moon?And we got the completion, Neil Armstrong.Well, the prompt is this part.Who was the first person to walk on the moon?The prompt is whatever we ask the open AI API for.Now, sometimes prompts are really, really simple justlike this, and sometimes they're really very complex,as you'll see a bit later in this course.Now, they've given us an example prompt in the docs.Say this is a test, which, to be honest, is not very creative.So instead of using that, I'm goingto ask an easy but real world question for this prompt.I'm just going to say, what is the capital of Spain?And that is all we need to do for a simple prompt.We just put it in a string.OK.Now we need to change some thens.So we'll take the response, and we'll call Jason on it.And then we'll take the data from that responseand log it out.OK, let's open up the console, and I'll hit Save.And we've run into an error.It's a pretty silly one.It's just a typo on my part.But why don't you just pause now and see if you can debug that?And I'll give you a bit of a clue.Have a quick look at this slide.OK, did you spot it?I've actually put bearer colon and then the API key.I think that is causing the problem.Let's try it one more time.And there we are.We're getting a response.So I'm just going to copy this from the consoleand paste it in the editor, just so wecan see it a little bit more easily.And as we can see, this is an object.It's got loads of data in it.And we'll be talking more about some of the propertiesin this object as we go along.But for now, we just need to focus on one word, Madrid.Because that shows us it works.OpenAI is speaking to us, and it knows all about Spain.Now, OK, knowing facts is great.But we're actually interested in emotion and creativity.So I'm actually just going to change things a little bit.Let's delete this.And I'm going to change my promptto say something more emotional.I've said sound sympathetic in five words or less.Let's hit Save.And again, I'll just paste the response right here.And look what we've got.I'm here for you.It's giving us sympathy.And what's really cool about thatis that now the AI is speaking to us as if it were human.It's speaking with heartfelt, or at least CPU felt, emotion.And that is what we're looking for.OK, let's take what we've got hereand apply it to our project.And I haven't forgotten this modelthat we've got here, text da Vinci 003.It's still shrouded in mystery.But I want you to get your hands on the keyboard,start getting practice, start building muscle memorybefore I do any more talking.So let's move on to a challenge with this next.OK, so back in our app, we've got an event listener righthere.And it's listening out for clicks on this button.And what it does is it checks to see if the user has given usany input.It displays a loading message and updates the textthat we see in the speech bubble right here.Now, we're not ready to work with any user inputted text yet.So I'm actually just going to comment out this if.And if I save that now, this codeshould run as soon as we click this button.And there we are.We get our loader.And we've updated the text that we've got in the speech bubble.So let's go ahead and make an API callto get an enthusiastic response that we can pass to our user.And of course, later, we'll refactor thisso the AI is actually responding to the specific ideathat the user gave us.But for now, the response we get back from the AIis just going to be generic.So I'm going to call a function in here called fetch bot reply.And then I'll come down here and I'lldo the donkey work of setting up the skeleton of this function.And now it's over to you.Here's a challenge to finish off this function.And I'm just going to paste it right here inside the functionbody because that is where I want you to write code.So your challenge is this.I want you to make a fetch request to the OpenAI API.And I've put all of the details that you need up here.So you'll have to put your own API key in here.And this is the URL to the endpoint.Now the prompt should request an enthusiastic responsein no more than five words.And you know how to do that because in the previous scrimwe did exactly the same thing to get a sympathetic response.For now, you can just log out the completionto check it's working.Now before you start, there are two things I want to say.The first is, if what you get from the completionisn't quite what you wanted or what you expected,don't worry.We're going to talk a lot more about using promptsand troubleshooting the issues that you can have.The purpose of this challenge is just to get the syntax rightso we are actually getting a completion back from OpenAI.Secondly, by all means, go back to the previous scrimsjust to have a look at the syntax that we need.But don't copy and paste.You're going to do yourself a lot of favorsby writing this out by hand.All of that practice just builds muscle memoryand builds up your fluency.OK, pause now, get this challenge sorted,and I'll see you back here in just a minute.OK, so hopefully you managed to do that just fine.So what we need to do then is come in hereand set up a fetch request.And we'll pass in the URL that we've got stored right here.And then we'll open up the object.And we know that the method is post.And then we need the headers.And that will be an object with two key value pairs.The first is the content type, which will be application Jason.And the second will be authorization.And that will be a string with the word bearer and our APIkey.Then we need the body.And the body is going to need a model and a prompt.So firstly, we say Jason.stringify.And then we pass in an object with model text DaVinci003.And prompt.And for my prompt, I'm going to say sound enthusiastic in fivewords or less.Because that is what we want the movie boss to do.We want him to sound enthusiastic.OK, let's change some VENs so we can deal with the response.So we call Jason on the response.And then we'll take the data from that responseand log it out.OK, let's hit Save.And to fire up this function, all we need to dois hit the Send button.And we've got the loading SVG.And if I open up the console, there we are.It looks like we've got our completion.Let's just copy and paste that into the editor.And we can see we've got these two words righthere excitedly enthusiastic.So it's taken our prompt very, very literally.Now the next thing that I want to dois actually get this completion to appearinside the speech bubble.So I'm just going to delete this challenge textso we've got a little bit more room to work with.Now we've already taken control of the text in the speechbubble.We've got the elements stored up here in this const movieboss text.So let's come down here, and instead of logging somethingout, I'm going to come onto a new line.And I'll say movie boss dot text dot inner text.And now we need to access our completion.And we've got that right here.So to get that, we need to say data dot choices.And choices holds an array.And we actually want what is in the first element of the arrayat position 0.And then we want to access the text property.OK, let's hit Save.And again, I'm just going to hit this button.And there we are.It says eager and excited in the speech bubble.Now we've got a little bit of a problemin that our design is kind of brokenbecause the CSS can't really cope with such a short sentence.Or that's what it seems at the moment.Now I'm not too worried about thatbecause this sentence is not going to stay short.Soon we're actually going to refactor this function.And what we'll get will be a longer completion, whichis actually going to be relevant to the one line inputthat the user puts right here.But before we come on to that, thereare one or two things that I want to cover.Firstly, these fetch requests are unnecessarily complexand long.So instead of writing out loads of these in our app,we can actually use open AI's dependency.And that is going to save us a lot of workas we move forwards.But before we do that, we need to talk about modelsbecause we have used text DaVinci 003and we haven't really got a handle on what that means yet.So let's come on to that next.So in the last two scrims, we have used text DaVinci 003as our model.So now let's ask the question, what is an AI model?Well, loosely speaking, an AI modelis an algorithm that uses training data to recognizepatterns and make predictions or decisions.Now, open AI has got various modelsgeared towards different tasks.And some models are newer and therefore better than others.At the moment, there are two main categories of modelsthat you might come across.There's the GPT-3, GPT-3.5, and GPT-4 models.And GPT-4 is actually just coming out right now.It's currently in beta.And these models are all about understanding and generatingnatural language.And they can also generate computer languages as well.Now, there's also the Codex models.These models are specifically designedto generate computer code, includingtranslating natural language to computer code and vice versa.And you've probably seen examples of that online,even if you haven't tried it yet yourself.Open AI also has a model that filters contentto remove or flag unsafe or sensitive text.In this project, we'll be using the text DaVinci 003 model,which is a GPT-3.5 model.Now, this is one of the newest models.It can provide long text output.And it's great of following instructions.There's GPT-4, which is fresh out.And we will be coming to that later in this course.There's the text Curie 001 model.And this is a very capable model.It's actually faster than text DaVinci 003.But it's not as good overall in termsof the language it creates.There's text Babbage 001, which is great for straightforwardtasks and is also very, very fast.And then there's text Ada 001.And that is fine for basic tasks.And it's fast and cheap.Now, these models are in age order.So text DaVinci 003 is the newest on this list.Text Ada 001 is the oldest.And the older the models get, the less complex they are.So they run faster.And generally speaking, they're cheaper.But you should check the open AI docs for the latest prices.Now, the Curie, Babbage, and Ada modelsall provide shorter outputs than text DaVinci 003.But they might well still be capable of some or evenall of the tasks you might want to do in a project.It depends what it is you want to achieve.But just remember, with the older models being cheaper,that means you can scale apps without incurring toomany costs.And because they're faster, you'llexperience less of the horrible laggy UX.You can sometimes get when you're working with any API,but particularly with artificial intelligence,as it obviously has to do so much computation.Now, so far, our app hasn't been too laggy.We've just been generating quite short, quick completions.But as our requests get more complex,we will see lag times increase.And now, you might well be asking, what modelshould I use in my project?Well, open AI's advice is this.Start with the best available modeland downgrade to save time and costs where possible.So basically, get your app workingso you're happy with its performance,and then experiment with cheaper modelsto see if you can get the same level of results.Now, as new models come out, prices will change.And probably, performance will increase on those new models,so you will have to do some experimentation.Now, to help you with that, in the next grim,I want to introduce you to a couple of really useful tools.And one of those tools will help you select the best modelwhen you come to build your own projects.Let's move on to that next.I want to show you a couple of really useful tools thatcan help us work with open AI.The first one is particularly useful for model selection.This screenshot is from gpttools.com,and this is their prompt compare tool.And of course, this slide is a clickable link, whichwill take you through to their site.Now, to use this tool, you put your API key in right here,and then it allows you to set up two APIcalls side by side using different models.So let's just ask OpenAI for a description of Pablo Picasso'sartistic style.And there we are.I've put the same prompt on each side.Now, for the first one, I'll use the model, or engine,as they call it here, of text DaVinci003,which is the same as we're using in our app.And for the second one, I'll use text Curie001,which is one of the older models.Now, down here underneath, we've got plenty of other settings,but I'm going to leave them all at their defaults.It will be the same on both sides.So now we can submit and see the results.The first one to come back is the Curie,which figures the older, simpler models are faster.Then we get back DaVinci.The big thing that we notice is that the texts are vastlydiffering in length.The newer model, the DaVinci, gives us way more words,though it was slower.And we can actually see the speed difference right here.This one took 5.8 seconds, and this one took just 1.1 seconds.Now, in our project, we are prioritizing language creationability over speed and cost.So we're going to stick with text DaVinci003,but it's good to know for future referencethat you can do some experimentation with this toolwhen selecting a model to use.Although this answer is short, the language it providesis actually perfect human standard English.So remember, those older models are not just there for legacy.They are actually really useful.Now, the second tool I want to show youis back on OpenAI's website, and it is the OpenAI Playground.And again, this slide is a clickable link.Now, the Playground is a really, really cool tool.You can select from some pre-written examples,or you can just come in here and write your own prompts.Let's ask about Picasso again.And when we click Submit, we can actuallysee the results we get highlighted in green.And this will allow you to practicewith different models.Again, you can change it right here,but of course, you won't be seeing the results side by side.It also does allow you to play with the various othersettings, some of which we'll be lookingat later in this course.But what I think is the most useful thing hereis that any time you can come up hereto where it says View Code and get a code snippet,including the prompt you're generating right now,it will actually give you that prompt in either Node.js,Python, or curl.Now, I've selected the Node.js snippet right here.If we look carefully, we can see that it's not quite the sameas the fetch request that we've already written.If we look at this first line, it'susing the require keyword to work with a dependency.So at the moment, we couldn't just cut and paste this codeas it is, but we could use lots of it in our JS.We've got, for example, the prompt right here.But look, the neatness and compactnessof the API call being made here is definitelymaking me think that it's time to move awayfrom the standard fetch request we've already writtenand move towards using the OpenAI dependency.In the long run, this is going to save us timeand allow us to do less work.In the next grim, let's go back to the appand refactor our fetch request to use the OpenAI dependency.When you're ready for that, I'll see you there.So far, we've been using a fetch request to make API calls.But now, we're going to neaten things up a bitby switching to the OpenAI dependency.And this is actually going to save us timeand allow us to write less code as the project progresses.Now, if we look back at the docs,we saw this code snippet for Node.js.And we can actually get a broad idea from thisas to what we want to achieve.Let's just zoom in a little bit.OK, so we're going to need to get our handson the configuration and OpenAI API constructorsfrom the OpenAI dependency.And we'll actually be using the import keyword,not requiring them, because obviously, we're notworking in Node.js.Also, like they're doing here, weare going to store our API key in a separate file.And we'll talk about that more in a moment.And then we'll use the two constructorsthat we're bringing in from the OpenAI dependency.And then we can update and simplify our fetch request.So firstly, let's come over here.And I'm going to set up a new file called mv.js.Now, you can't actually see me do this.But when you hover your cursor here, three dots appear.When you click on them, you get a menu.And you can select New File.I'm going to call this file mv.js.And there we are.You can see that file has now appeared.Now remember, because we're working on the front end,this file is totally visible.If you were taking this to production,this file would need to be server-side.And of course, you would also make sure you were ignoring itwhen pushing it to GitHub.But what we're doing today is purely on the front end.And this is absolutely fine while we're developing and runningthings locally.And as I said, towards the end of the course,we will look at how you can deploy your projectswith your API key safely hidden.And then you'll be able to share your workand use it in your portfolios.OK, so in this mv file, I'm going to export a const.And this const will be process.And process is going to hold an object.And inside that object, we're goingto have a key value pair where the key is nv.And the value will be an object with another key value pair.This time, the key will be openAI API key.And I've put that in uppercase letters with underscoresseparating each word.Now, the value in that key value pair will be our API key.So let's just copy and paste that from index.js.Now, we've done it like this with this environment variableto more closely mimic what we wouldbe doing if this were a production app and this filewere being stored on the server.And now that we've got the API key in one place,when you come to doing the challengesand we've got various API calls happening in the app,you'll only have to paste your API key in one place.Right, let's go back to index.js.And we're going to import that environment variable.So I'll come right up to the top.And I'll say import.And then in curly braces, we need process.And then we need from.And now we just need the path to our environment variable,which is just going to be slash nv.And this should work because in index.js,if we scroll down to the bottom, we've alreadygot this piece of code right here, type equals module.So the browser knows to expect modular JavaScript.Now, let's check it's working.So what I'm going to do is comment out this API key.And I'll set up a new const called API key.And I'll have that store, the API keythat we're importing with process.So it will be process.And then we're going to need.env and then.openai-api-key.Let's hit Save and see if it works.So I'll come in here, click the button.And there we are, enthusiastic and excited.OK, so we've got our API key where I want it.Next, let's install the openai-dependency.And we'll come on to that in the next scrim.OK, let's install the openai-dependency.And in scrimba, that's dead easy.Over here on the left-hand side, then,I'll come to the three-dot menu.And I've got the option to add dependency.And again, that is not recorded, but a dialog box appears.And I just need to enter the dependency I want.And in this case, that is just goingto be openai, all as one word, and lowercase.I hit Add.And there we are.The dependency has appeared on the left-hand side.So scrimba has done all of the hard workfor me in the background.Now, if you're working outside of the scrimba environment,perhaps you're following this on YouTubeor creating your own project in VS Code or any other editor,we will talk about how you can work with the openai-dependencyin just a couple of scrims' time.Now that we've got the dependency installed,we need to import two constructorsfrom that dependency.Let's just check this code.So we're going to need configuration and the openai API.And they both have uppercase-first letters.Now, they use require here.We are using import.So let's just come up here and say import.And we need configuration and openai API.And just note that AI here has got uppercase lettersthat caught me out the first time.Now we're importing them from openai.And let's just sort out my typos.And the first thing that we're going to dois set up a new instance of this configuration constructor.So down here, I'm going to say const configurationwith a lowercase c.And I'll set that equals to a new instance of configuration.And as we can see here, we'll needto pass in our API key inside an object.And we've actually got the code we need for that right here.Now, we need to use this second constructor, the openai API.So I'll come down here.And I'll set up a const openai.And this will store a new instance of the openai API.And we just need to pass in the new instance of configurationthat we just created.Oh, and I've just noticed that I've made a mistake right here.The AI is uppercase, but API is actually camel case.So we need to change that here and here.Glad I saw that before we got a strange error.OK, now we can delete a load of code.So we're not going to need this URL anymore.We're not going to need the API key saved in here.We actually only used it here for a test.So let's delete all of that.And now in the next grim, we're goingto come down here to this fetch bot reply function.And we're going to make a lot of changes to all of this coderight here.When you're ready for that, I'll see you there.So we're going to tidy up this function a lot.All we actually want to keep is the model and the prompt.So I'm just going to delete everything else.Now, I am going to keep this line right herewhere we update the speech bubble.But I'm just going to comment it out for now.And we'll need to make a few changes to it in a moment.Now, I'm going to come in here and set up a const response.And now, as per the code we've got in here,we can await our new instance of the OpenAI API.So remember, we've got that stored as a const right here.Next, we need to tell it to use the create completionendpoint.And then, just like they've done here,we're going to pass in an object with our model and prompt.So let's just cut and paste that right in here.Now, let's log out the response.So I'm going to hit Save.And it looks like we're getting an error.It says syntax error, unexpected reserved word.So here's a quick debug challenge for you.Can you figure out what's going wrong here?Just pause now and take a second to look at that.OK, so hopefully you figured out that because we'reusing the await keyword right here,we actually need this function to be async.OK, let's try that again.And we're not getting any errors.So I'll press the button.And there we are.We're getting our response.And if we look down in the console,we're getting the completion, excited, passionate, eager.OK, so to get this rendered, this line of codeneeds to change just a little bit.Let's just bring it up here and uncomment it.So all we need to do here is take this from response.So it's response.data.choices.And then we'll take text from whateveris at the zero index of the choices array.Let's give it a go.And there we are.It is working, excited, enthusiastic, driven.Now, I'm just going to delete this console.log.And you might well notice that we'vegot a lot of white space up here.And actually, if I just copy and paste somethingfrom the console, you can see that the completionstarts with white space.So here's a quick JavaScript revision challenge for you.How do you remove the white spacefrom the beginning and the end of a string?Just pause now and do that.OK, so hopefully you remembered that wecan do that with the trim method.So I'll chain that on the end.Let's hit Save.And I'll press the button one last time.And there we are.Now it is at least equally spaced out.And as I said before, the CSS wasn't reallydesigned to cope with such a short completion.But soon, the text that we generateis going to be much longer.OK, we have seen various enthusiastic responsesfrom OpenAI.But the next thing that I want to look atis making that response actually tailoredto whatever the user puts inside this text area.So I want to get OpenAI responding to our user's inputin a human manner.But before we do that, I did promisethat we'd quickly look at running our code outsideof the Scrimba environment.So the next grim is optional.If you're working on this in Scrimba,or if you've already set this up locally,you can actually skip the next grim and move straight ahead.When you're ready, let's move on.Let's see how we can get this project up and runningicon on the right-hand corner.in VS Code with the OpenAI dependency.Let's see how we can get this project up and runningin VS Code with the OpenAI dependency.So the first thing to do is to come on to this or any otherSo the first thing to do is to come on to this or any otherScrim, and you don't need to have a Scrimba account to do this.You can just click this cog icon down in the bottom right handScrim, and you don't need to have a Scrimba account to dothis.You can just click this cog icon down in the bottom right handcorner.That's going to bring up a menu.Select Download as Zip.corner.That's going to bring up a menu.You need to unzip that package on your PCSelect Download as Zip.and then click on theYou need to unzip that package on your PCand then open the folder in VS Code.So it's just File and Open Folder.And often, the folder has actuallygot this really convoluted, randomly generated name.And of course, you can change that to whatever you want.Now, inside this folder, we've got several files.This one here is called Read Me for a Reason.Let's open it and see what it says.And basically, it's telling us that weneed to run npm install and npm start.So what we need to do then is open up the terminal.And when we do that, we will get a new instance of the terminaldown here.And this is where we can write npm install.And I've just put it a little bit bigger there,just so you can read it.When you do that, npm install is going to do its thing.Once it's done down here, you can run npm start.And again, there it is, a little bit bigger.And that will do its thing.And eventually, down in the terminal,in the terminal, you will see this.And so to run the project locally now, all we need to dois go to this link.And the link is made of your local IP address and this port.So the port, in this case, is 5173.Now, you could replace your local IP address with localhostand then have the colon and then the port.That will also work just fine.The quickest way to click on this linkis in Mac to hold down Command, in Windowsto hold down Control, and then that link becomes clickable.And it should take you through to your browserwith the project running.And you can see here, I'm accessing this on localhost,but the IP address would work there just fine.Before we get to work on our response from the AI,I want to make a slight change.When we have just one word in these keys,we don't need them to be wrapped in inverted commas.Now, it's a totally personal thing,but I prefer it without where possible.So let me just tidy this up a little bit.OK, I feel strangely better for doing that, even though itdoesn't matter at all.Let's get to work with personalizing the response weget back from the AI.So at the moment, we've given it this rather basic prompt.And you only get back as much as you put in,so it's giving us this very boring, generic reply.And if we hit Send, we'll see an example of that.Excited and eager.OK, so thanks for that.But to be honest, we could have hardcoded it ourselves.What I want to do is uncomment this code here.So what's happening now is when a user clicks the Send button,the If clause here is going to checkthat there is actually some text in the text area.If there is, it's going to render the loading SVGand update the speech bubble to our first generic message.At that point, I also want it to call FetchBot.Now, if we're going to get a personalized response,then our prompt needs to have accessto whatever the user entered into the text area.So let's take whatever that is and save itas a const user input.And we'll pass in user input when we call FetchBotReply.And let's bring it into FetchBotReplyas the parameter outline, because it'sgoing to be a one sentence outline of a movie.Now, the last change I'm going to make hereis I just want to log out the response.OK, and now it's time for a challenge for you.And I'm just going to come in here,and I'm going to paste it right inside this object,because it's this prompt here that I'mgoing to ask you to refactor.So I want you to refactor this prompt so the AI givesan enthusiastic, personalized response to the user's inputand says it needs a few moments to think about it.Now, a couple of things for you to think about.We can use the parameter outline in the promptby converting that prompt to a template literal with backticks.And you might want to put the outline in inverted commasor speech marks to signal to open AIthat this is a chunk of text that you're referringto with the rest of the prompt.And of course, you can experiment with the wording,but don't be afraid to just ask for what you want.There's not one correct way of writing this prompt.And afterwards, I'll show you my way.Now, just before you do that, I'm going to do you a favor.I'm actually going to break the rules againand add a line of code here that we haven't talked about yet.Now, I want to do that because I'maware that we've looked at loads of theoryand we've laid loads of foundations,but there hasn't been too much time for youto get your hands on the keyboard yet.So I just want to pop this line of code in here,because without it, this challengewould be ridiculously frustrating.And then we will talk about it afterwards.So all I'm going to do is add a property to this object, maxtokens 60.OK, so pause now.Don't worry about this mysterious new property at all.Get this challenge sorted, and we'll have a look togetherin just a minute.OK, so hopefully you managed to do that just fine.So I'm going to come in here, and I'mgoing to completely replace this prompt.And what I'm going to say is this.Generate a short message to enthusiastically say,outline sounds interesting, and that you need some minutesto think about it.Mention one aspect of the sentence.So you'll have noticed that I've put outlinein inverted commas, so the AI understandsthat I want it to deal with that specific line of text.And also, this last instruction will hopefullymake OpenAI personalize the completion.Now, of course, to get access to outline,we need to swap these four backticks.OK, let's hit Save, and I'm just goingto put a one-line idea in here.And I'm just going to say, a spy deep behind enemy linesfalls in love with an enemy agent.Let's press Send.And look at that.We're getting a really long completion.And if you just read through that,you can see that it's actually like we'reinteracting with a human.It's being conversational.It's referring to our idea, and thatis exactly what we want.Now, down in the console, we've got the response.And just bear with me while I copy and pastesomething from there.Now, before I explain why I've done that,I'm just going to actually use the same idea again.But this time, I'm going to remove this line of codethat I added just before you did the challenge.So I said, a spy deep behind enemy linesfalls in love with an enemy agent.Let's press Send and see what happens.And there we are.We get our response, but look, it is much shorter.A spy deep behind enemy lines falls in love with an,and then it stops.My answer is cut off.Now, I'm just going to copy and paste the same propertiesfrom the response.And what we can see there is that the first timewith the more successful completion,we had the finished reason of stop.And the second time when the completion was actually notcomplete, where we got cut off, the finished reasonwas length.So generally speaking, a finished reason of lengthis bad news.It means OpenAI has not given us everything it wanted to.Now, also, at the end here, we see completion tokens 59in the first call and completion tokens 16 in the second call.So something we're doing with tokensis affecting the length of the completion we get.Now, as you're a seasoned coder, you'veprobably grasped that we can controlthe length of our completion to some extentwith this max tokens property.But before we start using max tokens all over the place,we should really understand what a token is in OpenAIand what this number 60 really means.So in the next scrim, let's take a peek under the hoodand take a dive into tokens and the max tokens property.When you're ready for that, move on.OK, let's talk about tokens and the max tokens property.So we know that when we add this max tokens of 60to our API request, we get plenty of text back.We also know that if we don't set max tokens,we get much less text back and it's actually not completeand therefore doesn't really make sense.And that's why we're doing this.It's not complete and therefore doesn't really make sense.And that's what we can actually see right here.So what exactly is going on with tokensand what even are tokens?OpenAI breaks down chunks of text for processing.Now, I say text.It depends on which model you're using and what you're doing.It could also be code that gets broken down into chunks.But we're working with text, so weneed to think about tokens in the context of text.I think that each word or each syllable would be a token.But it's actually not as simple as that.Roughly speaking, a token is about 75% of a word.So 100 tokens is about 75 words.So the 60 token limit that we put on this fetch requestwould bring us back a maximum of about 40 words.When we didn't use max tokens at all,this one here actually defaulted to 16, which as we can see hereis way too short for our needs.So that's an important lesson.If you don't allow enough tokens,your completion will be cut short.So you'll actually get less text back from OpenAI.So now you might be thinking, well, OK,a token is a chunk of text.But so what?Why do I need to think about limiting it?And the best way to make sure that your max token settingisn't causing you problems is to check the object youget with your response.If you see the finish reason of length, that is a bad sign.That means the text that you're getting backhas been cut short.And if you see a finish reason of stop, that is a good sign.That means that OpenAI actually got to the end of the processand it's given you all of the textthat it wanted to give you.So you might be thinking, OK, so a token is a chunk of text.But why does that matter?Well, there are some good reasons for knowing about tokensand being able to limit them.Each token incurs a charge and it takes time to process.So that gives you an incentive.If you limit the number of tokens,you can keep costs down and keep performance up.And that's really important, of course,for when you run out of free creditand if you're creating a production app,and that app scales to millions and millions of users.And why shouldn't it?Now, there's something really important about max tokensthat we need to understand.Max tokens does not help us control how concise a text is.As we saw in our app, we get an incomplete responsewhen the token count is low, not a more concise one.So as a tool to control how verboseor how expressive OpenAI is, max tokens is useless.And that begs the question, how should I use it?And the answer is, we should set it high enoughto allow a full response from OpenAI.So you might just have to do a little bit of experimentationwith that each time and just making sure the textthat you get back from the API is not cut short.So how can we control the length of text we get from OpenAI?Well, we do that with prompt design.Good prompt design is everything.And good prompt design is the best wayto ensure that the text we get from OpenAIis the length we want.Now, I actually think that the textthat we got back when we had max tokens set to 60was just a little bit too long.So as we go through this project and we learn moreabout prompt design, we will come backand just do a little bit of refactoring here.But for now, I want to keep up the momentum,keep moving forwards.So let's start tackling our next API call, whichis to generate a full synopsis from our one sentence movieidea.When you're ready for that, let's move on.OK, so we've got the one sentence idea from the user.Now let's make it into a professional synopsisfor our movie.So I'm going to come down here and set up a function calledfetch synopsis.And of course, this will be an async function.Now eventually, when the app's finished,we'll be displaying the synopsis to our userin this container, which will pop upwhen the finished movie pitch is ready to display.And the synopsis will actually be right down hereat the bottom.Now, if we have a look over in the HTML,this is the section here, which is actuallygoing to contain all of the output.And it's this paragraph down here, output text,which will contain the synopsis.So at the moment, this whole container is hidden by default.But if we go over to index.css and we justuncomment that one line there, now that containerhas appeared at the bottom.So in this new function that I've set up, fetch synopsis,what I'm going to do is take control of this paragraphthat we've got right here with the ID of output text.And then we'll be able to display our synopsis rightthere just to check it's working.So inside the fetch synopsis function,we want to say document.getElementByID.And the ID is output-text.And we'll set the inner text to whatever textwe get back from the API.And we can just borrow that line of code right there.Because in every case, the text that we get back from OpenAIcomes in an object.And it is always actually in the same place.Now, I'm going to call fetch synopsis from right hereinside this event listener.And I'll put it right underneath where we get the first replyto our initial idea.And I'll pass in the user input because that will alsobe needed to get the synopsis.And of course, let's take that in as a parameter right here.And again, I'll just call it outline.OK, now it's time for a big challenge for you.And I'm just going to paste it right in here.So I want you to set up an API call with model, prompt,and max tokens properties.The prompt should ask for a synopsis for a movie basedon the outline supplied by the user, which of course,we're bringing in with this parameter outline.And just remember, when writing prompts,try to be specific, descriptive, and as detailed as possibleabout the desired outcome.Try to avoid fluffy and imprecise descriptions.So don't use phrases like sort of or roughly.Now, we said before that we can controlthe length of the output with good prompt design.Now, you could experiment here with askingfor a particular word count.Say, give me a synopsis of 150 words.But I just want to warn you that that'slikely to be quite imprecise.So don't be frustrated if the length of the text you getis not what you want.We will be dealing with that shortly.OK, there is quite a lot to do here,but you've got all of the skills you need to do this.So pause now and get it sorted.OK, so hopefully you managed to get a really good synopsis.Let's have a look together.Inside here, I am going to set up a const called response.And then we'll await an openAI create completion.And we need to pass that an object with our model promptand max tokens.So the model is text da Vinci 003.I'll put my prompt in backticks so we can use the outline.And I'm just going to say, generatean engaging, professional, and marketable movie synopsisbased on the following idea.And lastly, we need max tokens.Because remember, max tokens will actually default to 16.And we don't really need that comment there anymore.So I will say, max tokens.And I'm going to go for something pretty bigbecause I don't want our text to get cut off.So I'll say 700, and we can always reduce that later.OK, let's hit Save and give it a try.So for my idea, I'm going with this.A madman develops a machine to control all humans.And only intelligent animals can save the human race.Although, would they really want to?Anyway, let's give that a try and see what we get.So we're going to get our first message from the API.Again, we've got this pretty long response.And we're waiting now for the synopsis.And I'm just going to scroll downbecause it's just going to appear right hereinside this box.OK, and there we are.We get our synopsis.And the results we get back are fine.Now, I'm just going to copy and paste them because actually,you'll probably find that if you pause,you won't be able to scroll the mini browser.So let me just paste them right here inside this file.Now, the first thing that we can sayis that that is pretty impressive.We've got a long body of text, very much asif it was written by a human.So pretty happy with that.And although it's long, it does finish naturally.I don't think it's actually been cut shortby having too few tokens.I think 700 is plenty.But I do wonder if it's as good as it could be.Now, our prompt instruction that I've written hereis fairly good.But it's actually quite hard to describewhat exactly you want a longer passage of textto be like in detail.And as we've talked about several times,it's also quite hard to control the length.This is arguably quite long.Now, I've just counted the words hereand it comes in at just over 160.That's actually not bad, but we can't really rely on that.Also, I can't help feeling that the story it's laid outis just a little bit woolly.It would be nice if it was just a little bit tighter,a little bit more concise.If we're going to grab the movie studio's attention,we need it to be really sharp.So what I want to look at nextis how we can help OpenAI understand moreabout what we want.So far, we've been giving OpenAIthese simple one-line instructions.What I want to try next is to include one or more examplesactually inside the prompt to give OpenAIa push in the right direction,so it's going to give us more of what we want.So let's take a look at that next.So far, when writing prompts,we've just provided one or more sentencesasking for what we want.You'll often hear this referred to as the zero-shot approach.And what that means is it's just an instruction.Now, the zero-shot approach works really wellfor many simple requests.But when we work with more complex requests,we run a greater risk of getting back resultsthat don't really fulfill our needs.So we might get completions which are off-topicor too long, or perhaps the formatis just not what we want.Now, I've got an example of that happening right here.Let me introduce you to Advertify,which is an app I've made to generate copyfor advertising purposes.It's pretty simple.The user can input a product name,give a description, and a target market.They hit generate copy,and they get a bunch of text they can use in their adverts.And if we just have a quick look at the code,there's nothing unfamiliar going on here.We're bringing in the user inputs right herefrom the inputs and this text area,and then down here, we've got this one-line prompt,and it's a basic instruction,and it's just using the product name,product description, and the product target.So the instruction is just create 50 wordsof advertising copy for this product,which can be described as the product descriptionand aimed at the product target market.And we might just tidy up that last back tickand bring it all onto one line.Let's see this in action, but before we do that,I'm just going to log out the response.Now I'm going to go for the same vegan fish cream examplethat we've got in the placeholder text.And I'll hit generate copy, and let's see what we get.And okay, it's working, but look,it's given me an ordered list.We've got one, two, three, four, five, and six.And it looks a little bit longer than 50 words,but if we open up the console,we can actually see that we've got this,and I'll just paste it in here.It says finish reason of length.And as I'm sure you'll recall,that means that OpenAI has actually cut us short.And if you look, number six is not complete.It just says, grab your vegan dash.And at that point we know that OpenAIwas trying to give us more.Now I've tried this several times before recordingwith various prompts,and OpenAI really doesn't work that well with word counts.The five words or less that we used in a previous challengedoes seem to work okay,but longer word counts often fail.Now, interestingly, OpenAI does know how long a tweet is.If we were to change this prompt and ask for a tweet,it will nearly always deliver something that's tweet lengthand throw in some hashtags as well.Okay, let's try something elseand see if we can make this Advertify appwork a little bit better.We're going to have a look at the few-shot approach.The few-shot approach is where we addone or more examples to our prompt.We do this because it helps the AI understand what we want.This is great for more complex tasks.So let's refactor our prompt.Firstly, I'm going to remove all of the variablesand actually rewrite this instruction.So I've said user product name, a product description,and a target market to create advertising copyfor a product.At the moment, we're not doing anythingwith the user input,so that's just gonna give us something really, really random.But what we're gonna do next is lay out an example.So staying inside the backticks,I'll come down onto a new line and here's my example.So I've got a product name, which is Flask Tie,a product description,a tie with a pouch to hold liquidsand a straw to drink through,and the product target market is Office Workers.Now I've also put some advertising copy right hereand that advertising copy is about 54 words long,which is the kind of length I'm looking for.Now, before this is going to work,we need to do a couple of things.Firstly, we need to bring back our variablesand we're going to lay them outin the same style as our example.So in fact, I'm just going to copy and pasteall of that text.And now let's bring in the user inputs.So Flask Tie, we can replace with product name.Product description, we can replace with product desk.And of course, target market will be product target.Now advertising copy, we are just going to leave that empty.So can you see what we've done here?We've given an exampleand then we've given a partly completed example.And this space right here is an invitation for OpenAIto go and complete.And if you'll remember,we're using the create completion endpoint.So OpenAI is just going to complete this block of text herein the same style as this block of text here.It's going to recognize that we want itto give us something like that,but tailored to the three variablesthat we've got right here.If we tested this right now, it would likely work.But there's one more thing that we can do to help the AIand to make our code more readable.What we're going to do is separateour instructions and context.Now OpenAI docs suggest that you can do thiswith three inverted commas or three hash symbols.I'm just going to go for the hash symbols.And I'm going to put one set right hereafter the instruction.And then I'll put another set down herein between my exampleand where we're asking OpenAI to do its thing.And so all that's doingis breaking up this body of text a little bitso OpenAI can see that it's dealing with different entities,an instruction, an example, and a request to go and complete.Okay, let's hit save and see if it works.So I'm going to put in the same vegan fish creamand I'll hit generate copy.Okay, let's check out the copy we've got.So firstly, we haven't got this ordered list.There's no numbers one to six.What we've got is a body of advertising textand that is what I wanted.Secondly, I've just checked the word count of thisand it's actually coming in as 63 words.Now the example that I put here is actually 54 words.So there's only nine words between the twoand that is pretty good.And if we have a look down in the console,we can see that the finished reason is stop.That makes sense because this is very muchthe end of the sentence and the end of the textso OpenAI has given us everythingthat it wanted to give us.So the example is doing a really good jobof allowing us to show OpenAI what it is we want.Now remember, this is called the few shotand we can add one or more examples.We should remember however, that longer prompts cost moreso you don't wanna go too far.But let's go ahead and add one more exampleand actually this is somethingthat you're going to do as a challenge.So let's get straight onto that in the next script.Okay, so here's your challenge.Add a second example here,be sure to make it similar in design to the first.Now I've put that because we don't want to confuse the AI.The examples that we give should be in a similar formatand they should be consistentelse we're just creating confusion.Now I've also put here, remember to use separators.So that is these three triple hashtagsand you can use them in exactly the same wayto separate out your example from the request to create.Now one thing I want you to remember hereis that the law of diminishing returns applies.Adding more and more exampleswill not guarantee better results.You might see great results or you might not.Also before you do this challenge,I just want to say that I'm awarethat some people following this coursemight be at a disadvantage herebecause English is not their first languageor perhaps language is just something they struggle with.So I've added a file up here called product.mdand that has got an example that you can use.So you can copy the textand just stick to practicing the layoutand the syntax of the prompt.Okay, pause now, get this challenge sortedand I'll see you back here in just a minute.Okay, hopefully you got that working.So I'm just going to come in hereand I'm going to copy all of the textsthat I've got right hereand let's just put our second example underneath the first.First thing that I want to do is separate out the examples.So we'll borrow these hashtags.Now I'm just going to take the product nameand that will be solar swim, product description.It's this crazy swimming costume with solar cellsto charge your phone while you're on the beachor what have you.And we've got the target market,which is of course young adultswho'll spend their money on anything.Finally, we've got the advertising copyand that is approximately the same length and styleas the advertising copy we've got right here.So that should do the trick.Let's just remove that space and we'll hit save.And let's give it a go and I'll hit generate copy.And okay, again, that has been pretty successful.The word count is coming in at just under 50 words.Well, our examples were 54 words and 53 words respectively.So that is pretty good.And also I think we're getting pretty decent copy.Now it can be really, really hard to judgebecause open AI is not going to give youthe same completion for the same prompt each time.So it's really hard to judge when you refactor a promptexactly how much difference is made.But I think two examples is a pretty good amountfor this few shot approach.And it's definitely had a beneficial effect on this app.So what we need to do now is go back to the functionthat generates our synopsisand see if the few shot approach will improve it.When you're ready for that, let's move on.Okay, so we have this synopsis fetch requestand perhaps we can tighten up the synopsis we get backand improve it by adding an example or twowith a few shot approach.Now, when you do this,you're welcome to use your own examples.In fact, I would encourage you to do that.If you're going to be working with open AI,then it's important to practice creating prompts.However, I have put an example synopsis up herein synopsis.md, which you can use if you'd like towhen you complete this challenge.So your challenge is to refactor this promptto use one or more examples,just like we did in the previous script.And remember to separate out the instructionfrom the example with either the triple hashor the triple inverted comma.Check back if you need to remind yourself of the syntaxand I'll see you back here in just a moment.Okay, hopefully you managed to do that just fine.So I'm going to come in hereand we're going to rework this promptand I'm going to replace this with the following.Generate an engaging professionaland marketable movie synopsis based on an outline.Now I'll come down onto a new line.I'm going to add my hashtag separatorand then I'll add my example.And my example needs an outline and a synopsis.And I'm going to use the examples I prepared earlier.This is the outline and then we'll also take the synopsis.And I've made sure that this example synopsisis the kind of thing that I want to get back from OpenAI.Now, underneath that we'll add another separatorand then it's outline.And this is where we need to bring inthe user generated outline.And then the synopsis, which of course we can leave blank.Okay, let's hit save.And I'm just going to pop over to the CSSand I'll just uncomment this one one more time.So we'll see the synopsis appear hereand let's put in a one sentence idea.So I've gone for a madman develops a machineto control all humansand only intelligent animals can save the human race.There we're getting our long initial response.And then down here, let's just wait for the synopsis.And there it is.Okay, the first thing I want to do is check the word count.And the good news is,it's almost exactly the same length as this example.There's less than 10 words in it.Now also, and this is subjective,but if you read through it,I think this is a pretty good synopsis.To me, it seems tight.It tells the whole story.It packs a lot of detail in.There's not too much fluff.So I'm pretty happy with that.And again, as always with OpenAI,it's really hard to make a comparison.But I think adding that example to the prompthas made a big difference.Now, of course, the synopsis makes this prompt quite big.And if we were to add several examples,we could end up burning tokens here unnecessarily.So if we were gonna take this to production,maybe we would run a bunch of tests with multiple synopsesand then reduce the number to the minimum needed.Now, before we move on, I have got one more challenge for you.And I'm just going to come up here and paste it in.Okay, so the initial response that we get backwhen we first put our one line conceptinto the text area is pretty long.It doesn't actually break the layout,but it does just stretch things a bit too much.And I think it's all a bit unnecessary.What I prefer is to see something like this.So we've got a good personalized response,but it's just not that long.There's just enough there to make it clearthat OpenAI has understood our requestand is giving us a conversational responsewhich references the one line input from the user.So here's a challenge for you.I want you to refactor this promptto use examples of an outlineand an enthusiastic response.Be sure to keep the length of your examples reasonably short,say 20 words or so.So we just don't want it to be massive like this one.Now again, it's great if you can work on this on your own,but I have put a file up here called outline.mdand that has got some examples in it that you can use,but do write your own if you're able.Okay, pause now, get this challenge sortedand I'll see you back here in just a minute.Okay, hopefully you got that working just fine.So I'm going to come in hereand I'm just going to change up this initial instruction.I'm saying generate a short messageto enthusiastically say an outline sounds interestingand that you need some minutes to think about it.Now I'm not going to instruct it to mention somethingfrom the outline like we did before,mention one aspect of the sentence.What I want to do insteadis show it how to do that with examples.So let's come in here and put the separator.And now I'm going to go over to outline.mdand I'm going to bring in the examplesthat I've got right here.So I've got three examplesand each one has got an outline and a message.So let's just label them clearly.And I'm going to separate each example with a separator.Okay, now let's come down onto a new line.We'll add another separatorand then we'll say outline and message.And of course message will leave blankbecause that is what OpenAI is going to do for us.And outline will just be the outlinethat we've got coming in here as a parameter.Okay, let's hit saveand I'm going to use the same example as I used before.And let's see what we get.But before we do that,let's actually just get rid of the output boxthat was at the bottom.And also just momentarily,I'm going to comment out this fetch synopsis function.So the app will only go so far as to call this function.I'll need to add my outline again and let's hit go.Okay, there we're getting a much shorter response.Wow, that's incredible.A madman and his machine?I'm feeling inspired already.Let me take a few moments to ponder it.So a much shorter completion, just like our examples,but still clearly referring to the outline I put in.Okay, now the app is working much more smoothly.But before we move on,there's just one little thing I want to tidy up.We've got a global variable up here.And actually we're only using it right here.So my bad for declaring it globally,I'm just going to move it down here inside that function.And I think that is better practice and a little bit neater.Now, next up in our app,we need to create an iconic title for our movie.But I think this would be a good moment for meto say a quick word about the architecture of this app.So let's just take literally a couple of minutesto talk about that.I just wanted to say a wordabout the architecture of this app.As always with code,there are loads of ways you could do this.So I want to say right now that the way I'm doing it hereis definitely not the one best way.And in an app this size,actually it's not going to matter very much at all.But there are some things which we could do herewhich we're not doing and I wanted to give youan explanation as to why.So firstly, on the code reusability front,we are building objects for each of our calls to the API.And as you can see, before this app is finished,we will have done that multiple times.Now, would there be a way to set up one functionto do the fetching and pass it an object with the prompt,max tokens, et cetera, every time we need it?Probably yes.And that would make our code much more reusableand less repetitive.But the reason I'm not doing thatis just to let the AI take center stageand not get bogged down in JavaScript.Once you've got the basics of working with open AI,as you will by the end of this project,that is the time to start looking at ways of saving time,saving work and being more concise with the code.And likewise, normally I like to have my functionsas much as possible just doing one thing.And we're breaking that rule herebecause we've got a function that's doing the fetchingand it's also rendering out to the DOM.Now, we could potentially set up one render functionand then have these fetch functionsjust return the response.And then when all of the API calls have completed,the render function could render out the results.It would be doable.We could store all of our completions in an objectand have a function that checksif all of the fetch requests have responded successfullybefore triggering the render.But again, that would involve a whole lot more JavaScriptwhen in this course, I really want to just focus on the AI.Now, at the end of the course,if you would like to refactor the code,that is not a bad idea at all.In fact, it's a really good idea.But I just wanted to give you a quick explanation nowof why I chose to do it like this.Okay, with that done, let's go ahead and use open AIto generate a movie title that's so iconic,it's going to reverberate down through cinema historyfor the next 500 years.When you're ready for that, let's move on.We need a title for our movie.So let's go ahead and set up a function to do that.Now, I'm going to call this function fetch title.And as you know, by now,that is going to be an async function.Now, if we have a quick look over at index.html,we've got an element here, it's actually an H1.And that is where the title of our movieis going to be rendered.So back inside this function then,let's just deal with that first.Now we're going to generate this title from a synopsis.So we need to take that in as a parameter.I want to call this functionfrom inside this fetch synopsis functions.So as soon as this response comes back with a synopsis,we want to send that synopsis straight back to open AIto get us a title.So I'll call the function right here.Now we need to pass in the synopsisand we've got that right here.But instead of writing out this code several times,why don't we actually set that up as a const called synopsis?And now we can use synopsis hereand we'll also pass it in to the fetch title function.Okay, you should be pretty good at this by now.So I'm going to leave the rest of this function up to you.Just bear with me while I paste in your challenge.So I want you to write a prompt askingfor a title based on a synopsis.If you'd like to, you can specifythat the title should be gripping or alluring.And I say that just to remind youthat being descriptive in prompt writing is a good thing.Secondly, remember that we need to add the model propertyand of course we should give it some max tokens.The default max tokens of 16 might be enough.That really depends on how longyou think a movie title should be.I mean, some movie titles are really, really short.The Stephen King classic is, for example.Some are kind of medium to long, Pirates of the Caribbean,The Curse of the Black Pearl.And then some are quite ridiculous.Night of the Day of the Dawn of the Sonof the Bride of the Return of the Revengeof the Terror of the Attack of the Evil MutantAlien Flesh-Eating Hellbound Zombified Living Dead Part Two.And that film is real by the way, but it is a spoof film.Okay, I'll leave that up to you.Set some max tokens that you think are gonna coverthe kind of title length that you want for your film.When I do this, I'm probably gonna set itto something like 10.Okay, pause now and go ahead and do this.Okay, so hopefully you managed to do that just fine.So I will come in here and set up my response.And then we will await the create completion call.And then inside the object, we need the model.We need the prompt.And my prompt is just going to be,generate a catchy movie title for this synopsis.And as for max tokens, I'm actually going to go for 15,just to give myself plenty of leewayif it does end up generating a really long title.Okay, let's hit save.And then down here, we've still got this display div visible.Remember in index.css, we've just commented outin a display none, so eventually it will be hiddenand then we'll just show it at the endwhen all of the API calls have been completedand the finished product is ready to show.But for now, let's just watchwhen our synopsis and title appear.So I'm going to put in my one sentence movie idea.And this is quite a long one.A time traveler goes back to the 1980sto prevent a catastrophic event,but falls in love with someone from the pastand must choose between saving the worldor staying with them.Let's hit send.There we've got our first bit of feedback.Here comes the synopsis and here is our title.1985 forever, James Mason's time traveling love story.Now I'm a little bit concerned herethat we've got a quotation mark at the beginning,but not at the end.And if we just count up how many words we've got hereand we bear in mind that these are quite long words,I'm just a little bit worriedthat my max tokens of 15 might not be enough.So I'm actually just going to err on the side of cautionand whack that up to about 25.Let's try that again and see what happens.Okay, interesting.This time it's actually given us a much shorter title.So we don't actually know if the max tokenswould have made a difference or not in that first attempt.I should have logged out the response.Then I would have been able to actually seethe reason for finish.Was it stop or was it length?But nevermind, we've got a title and it's a good title.Or is it?That is rather a matter of tasteand to some extent a matter of culture.Consider this.In the English speaking world,this spooky Bruce Willis film is called The Sixth Senseand millions and millions of people have seen it.In China, it's actually called He's a Ghost,which is just a much more direct name.And without wanting to give away spoilers,it's actually a title that gives away key points of the plot.So ideas for titles will vary.Now we know that we can adjust the kind of outcomeswe get from OpenAI with how we phrase our prompts.And we also know that we can give examplesand that will also tweak the kind of responses we get.But now I want to introduce a new property,which is called temperature.And we're just going to add that property right hereto the object that we pass to OpenAI.Before we dive in and start using temperature,let's just have a quick bit of theory about what it does.So we know that OpenAI works by predicting the likelihoodof one language chunk or token following another.So if we had a phrase like the dog,well, OpenAI could complete that as the dog was sleeping,the dog was hungry, the dog bit me.There are millions and millions of possibilities.What temperature does is it controls how often the modeloutputs a less likely token.So what it's doing is giving us some controlover whether our completions are safe and predictableon the one hand or more creative and varied on the other hand.Now temperature is set from zero to one in increments of 0.01,although you are going to find it really hardto see the difference with small changes.Now it defaults to one, so all of the API requestswe've made so far in our app have usedthe default temperature of one.Now lower temperatures, for example, at zero,will use fewer less likely tokens.So the completions will be less creative and more predictable.And this is absolutely great if you're lookingfor factual responses.Now higher temperatures will use more less likely tokens.So in doing that, you're going to get more varietyand more creativity.Now I'm wondering if my titles are a bit too wacky.So I'm going to come in here and I'll actuallyset the temperature to 0.7.And let's save that and give it a try.So I'm using the same outline as before.And here we are.We've got a title back, The Power of Love,Billy Biggs Time Travel Adventure.OK, that is a pretty good title.Now I have to reiterate, it's very, very hardto compare completions because there'sso much variety anyway.I could experiment more.I could take this down to zero.But to be honest, I'm actually happy with whatI've got right here.So I'm going to leave temperature alone.But why don't you have a play around with itand see how you like the results,see if you get a big difference or just a small difference.And remember how we're generating our title.We're actually using the synopsis.And the synopsis was generated with a temperature settingof one by default.So if you lower the temperature here in Fetch Titleand you're still getting somethingwhich is too weird for you, try actuallychanging the temperature property in this functionright here.So there's no right or wrong way to do this.It's just a matter of taste.And of course, it's important to know about the temperatureproperty and how it works.Now we've come a long way.There's only two more things that we need to do with this app.We need to get the cast.And we need to generate an image.So when you're ready for that, let's move on.In our finished product, we're goingto have a star-studded cast so movie industryinsiders can better visualize our story.And this is going to give us a great chanceto look at text extraction using OpenAI.If we have a look at our Fetch Synopsis prompt,in this example, we have actuallygot the actor's names in brackets after each character.But we're not always seeing that in the output.In this screenshot we are, we've got Jeff Bridgesand Emily Blunt.But in this screenshot, we're actually not getting thatat all.We've got the characters, but no names for suggested actors.Now that's probably being a bit inconsistent because we're notspecifically asking for it.Although we've got it in the example,we haven't got it in the instruction.So here's a very quick mini challenge for you.Ask for actors' names in brackets after each character.And I've just put here, you could alsosuggest that OpenAI thinks of actors that would particularlysuit the role.OK, pause now and quickly sort out that challenge.OK, hopefully you got that to work just fine.I'm just going to add a sentence onto the end of the instruction.The synopsis should include actors' names in bracketsafter each character.Choose actors that would be ideal for the role.OK, let's save that and see if it's worked.So I'll put an idea in here and we'll press Send.And there we are.We've got our synopsis.And we can indeed see that we're getting the actors' namesin brackets after each character.Now I've tested this and it is very consistent.OK, the next thing that we need then is a functionso we can extract the stars' names from this textso they can be listed out right here just above our synopsis.You could do that with vanilla JavaScript,but it's actually going to be easier to let OpenAI do thatfor us.So I'm going to come down here then.And after we've generated the synopsis,at the same time as we ask for the title,I'm going to call another function called FetchStars.And of course, we'll pass in the synopsis.Now I'll come down here.And because you've done this lots and lots of times,I'm going to do all of the heavy lifting hereand set up that function minus the prompt.Now we should set some max tokens here.I think we don't need very many.30 will be more than enough.And I'm not actually going to set a temperature here.I've tested this.And it really doesn't make much difference at all.So we might as well leave it at its default.Now we can see on the screenshot that we want the stars right here.Let's just check the HTML.And we've got this H2 element with the ID of output-stars.So that is where we're going to render our stars.And of course, this function needs a parameter.OK, now it's time for a challenge.And I'm going to paste it in right here just above the prompt.I want you to use OpenAI to extract the namesin brackets from our synopsis.Now I've left that challenge wide open because Ithink we've done enough prompt engineeringby now for you to be able to figure out how to do this.If you feel ready for that, pause now.Go ahead, get it sorted.It's always best to try and figure things out on your ownas much as possible.But if you'd like a few more pointers,or if you've tried it and you've got stuck,I have put a hint file up here.It's called hint.md.And it's just got a couple of pointersthat will push you in the right direction.OK, pause now.Get this challenge sorted.Do some experimentation.Take all the time you need.And I'll see you back here when you've got it workingand we'll have a look together.OK, hopefully you got that working just fine.So I'm going to come in here and I'mgoing to start off with a simple instruction.Extract the names in brackets from the synopsis.That should do the trick because OpenAIis more than capable of recognizing names and brackets.But what I do want to do, though, is add an example.So I'm going to come down here onto a new lineand I'll use a divider.So that will be the triple hashtag.And now I'm actually going to take the examplethat we've got up here.It's this Top Gun one.So we can borrow all of that.And I'll just paste it in here.Now we've got all of the names in brackets.So let's just show OpenAI what it is we're looking for.So I'll say names and then a colon.And then I'll just list out all of the names from the brackets.So Tom Cruise, Val Kilmer, and Kelly McGillis.And if we have a look back at the slide,we're actually getting a comma separated list here.And that is actually what we want.So those commas are there for a reason.Now let's come onto a new line again and I'll use a divider.And now let's just put synopsis colon.And this is where we want to pass it,the synopsis that we're bringing in right here.And then underneath that, names.And we'll leave that blankbecause that is where OpenAI is going to do its thing.Okay, let's hit save and we'll see if it's working.I'll paste an idea in and hit send.And let's check out our results.So we've got a title and there we are.We have got our stars, Al Pacino, Kevin Hart,and Dwayne Johnson, what a lineup.That I think will just be a really, really cool film.And we've also got a decent synopsis.Now the final thing that we needto finish this app off is an image.But before we can do that,we need to learn about generating images with OpenAI.That's a little bit differentto everything we've done so far.So let's investigate that next.Okay, let's take a look at generating images with OpenAI.So you've probably seen OpenAI's image generation tool,DALI, and if you haven't,you really should take a moment to go and play with it.This link is of course clickable.It will take you straight there.It really, really is a lot of fun.Now, as well as the DALI playground,we can access the OpenAI image API,which allows us to generate images in our application.And I'm actually building one such application right here.It's a really simple, fun game.All you have to do is describe a famous paintingwithout saying the name of the paintingor the name of the artist.So if I wanted to generate an imageof the most famous painting in the world,I could say something like,a 16th century woman with long brown hairstanding in front of a green vista with cloudy skies.She's looking at the viewer with a faint smile on her lips.Looking at the viewer with a faint smile on her lips.And if I give that description to OpenAI,hopefully it's going to give me a good likenessof the Mona Lisa,which is going to appear right hereinside this picture frame.Now, all of these CSS and HTML for this app is already done.We just need to finish off the JavaScriptand there's nothing unfamiliar happening here.The user is going to input their image descriptionright here, click create.There's an event listener on that buttonand it is going to call generate image,generate image is going to call the OpenAI image API.So let's go ahead and set up a response right here.And up until now,this is where we've been using the create completion endpoint.And now we want to use the create image endpoint.Now, just like with create completion,we need to pass an object with a set of properties,but actually these are not the same propertiesas we've used before with create completion.We actually don't need to specify a model.We don't need to give it max tokensor temperature.Let's just have a quick look at the propertiesthat we do need.So first up, we need a prompt.This will be a description of the imageand we'll go into more detail about prompt writingfor images in just a moment.The second property is N and N just stands for numberand it controls the number of imageswe get back from OpenAI.Now we can pass it an integer between one and 10.So the maximum number of images we can get in one go is 10and it will actually default to one.So strictly speaking, I didn't need to add it here,but it's really, really important that you know it's therebecause in the future you might want to workwith multiple images.Next up, we've got size and size takes in a stringand that string is going to hold the size in pixelsof the image we want.We've actually got three choices here.We can have 256 by 256, 512 by 512 or 1024 by 1024.Now the default here is the big one 1024 by 1024.And remember, bigger images cost more credit.So what you don't want to do is just always leavethat at the default, take the biggest imagesand then resize it to something much smaller with CSS.That's really uneconomical.So just be careful to go for the image size that you want.Today we'll be going for the smaller image.And the last property we've got here is the response formatand that is also a string.And the string can either be URL or B64 underscore JSON.So what this is giving us is the format of the completion.If it gives us a URL, we can just use that URLas a source inside an image element.And actually this will default to URL.And when you're doing the challenges,I recommend that you use URL.But there's a bit more we need to say about response format.Firstly, you need to be aware that OpenAI image URLsonly last for one hour.So if you want to keep an image, you need to download it.As I'm recording thisand my images need to last longer than an hour,I'm actually going to use this B64 underscore JSON method.And this is going to give me an encoded PNG imageso I don't need to rely on OpenAI's URLs.Now, if you've never workedwith a base 64 encoded image before,all it is is a massive chunk of codewhich the browser can interpret as an image.This is one that I've just pasted into VS codeand it is absolutely huge.If you try and log this out in Scrimba,you'll likely actually crash the editor.You can search online for base 64 image to PNG conversionsand you'll find plenty of siteswhere you can just paste in all of this codeand it will just give you an image.But what's also important to knowis that you can add a little bit of codejust before the source in the image tagto tell the browser to expect a base 64 encoded image.And we're going to see that in just a moment.A quick word about prompt design.Prompt writing for images is actually less complexthan the prompt writing we've done for text so far.All we really need to do is describe what we want in detailin a maximum of 1000 characters.Now, the more detailed the description,the more likely you are to get backthe results that you want.So consider this, if you ask for a white dog,that's a bad description.You're not giving any detail at alland you're exerting no controlover what you're going to get back.If on the other hand, you ask for a close-upstudio photographic portrait of an old English sheepdog,well, that is a good descriptionand then you can really start to imaginewhat you're going to get backand you'll actually find with that level of detail,it's quite easy to exert control over the imagesyou get back from OpenAI.Let's get the rest of this coded outand then we can actually see it all in action.So I'm going to come in hereand the first thing that we need is a promptand that prompt is going to bewhatever we've brought in here as a parameterwhich is whatever the user has inputted into the box here.Next, we need N and we only want one image todayso I could leave out N, it does default to onebut as I said, I just want to keep reminding youthat it is there for when you need it.Next, we need size and that one is a stringand I'm going for the smallest optionwhich is 256 by 256and that is just a lowercase X right there in the middle.Now lastly, we want the response formatand again, this is a stringand I'm just going to set it to URL.Now that is the code that it's best for you to usewhen doing these challenges.You're going to get back a URLand I've already set up this image element right here.The source is using the URLand therefore the image is going to appear right here.As I said before, I can't do that.I actually need to use base64jsonso that's B64 underscore JSONand that does mean that I won't be taking the URLbecause actually this is not going to give us a URL.It's actually going to give us this base64 encoded imageso I'm going to change URL to B64 underscore JSON.Now I would log that out to show youso you could see the full responsebut actually the base64 encoded JSON is so bigas I think I said before, it actually crashed the browserso I won't do that but feel free to experiment.Now there's one last thing that I need to doto make this work.You're not going to need to do itif you're using the URL formatbut I'm just going to paste a little bit of coderight in here and what this code doesis it just tells the browser that what's coming upis actually a data version of an image.It's a PNG image and the data type is base64.Without that code right there, this will not work.So let's save it and see if we can describethe most famous picture of all time.So I'm putting in here a 16th century womanwith long brown hair standing in front of a green vistawith cloudy skies.She's looking at the viewer with a faint smile on her lips.I've got the original ready down here for comparison.Let's hit create.And there we are and that is actually not bad at all.In fact, I think it's pretty hard to tellwhich one is the original and which one is my creation.That is a good likeness of the Mona Lisa.Now in a way I've been quite lucky here.You do have to work quite a bit with image promptsif you've got a really exact idea of what you wantand it does all just come down to being descriptiveand being detailed and you'll be really surprisedactually by how much open AI knows about styles.You can talk about impressionismor the style of Matisse or Picasso.You can talk about different lights, shades and hues.You can talk about anime and manga.Just go into as much detail about the image as you want to.Now I'm going to leave you to play with this.Hopefully you can describe a few more famous paintings.You might even do better than I've done.When you're ready, go back to the app.We're going to put these image generating skillsto good use, perhaps not quite in the wayyou'd expect us to actually.All will be revealed in the next scrim.We need an iconic image to complementour synopsis and title.These ones from Jaws and Star Wars are really, really cool.And in an ideal world, we too could have cover artthat featured our star-studded castand had the title of the film right thereblazing across the cover.Now, unfortunately, OpenAI is notgoing to generate recognizable famous faces for us.And also, it can't reliably add text to images.So what we're going to do insteadis focus on illustrating aspects of the plot.We can still create some funky images.And the app is going to end up looking something like that.Now we know how to get images.And what we could do quite easily is just come down hereand add an input field to the appand have our users write an image prompt.But the whole point of AI is that it's labor saving.So what we want to do is actuallyuse the title and synopsis to generate an image promptfor us.And that is a key power of AI.You can use what you've generatedto generate something else.So it's a kind of chain reaction.Now, we're going to use two functions to do this.The first function is going to generate the prompt.And the second function is going to use that promptto generate an image.So I'm going to come down here and set up a new functioncalled fetch image prompt.Now, fetch image prompt should take in both the titleand the synopsis.And I'm going to call this functionfrom the fetch title function that we've got right here.Fetch title takes in the synopsis.And it gets us the title.And so what I think we'll do to keep things a bit tidyis actually set up the title on a const right here,because we're actually going to use the title twice.We'll use it to update the DOM.And now we'll use it when we call the fetch imageprompt function.So we'll pass in title and synopsis.OK, now before we generate any images,we should actually check in the console what prompt we get backto make sure it's good.So for now, I'm just going to log out the promptthat this function generates.And now, of course, we need to build the AI call.And again, I'm going to do most of the heavy liftingbefore I set you the challenge for the prompt writing.So we're using the same model.I've left the prompt blank for now.And I've set max tokens to 100, which should be easily enough.And now let me paste in a challenge.OK, so this is your challenge.I want you to write a prompt thatwill generate an image prompt that wecan use to get the artwork for our movie idea.OpenAI has no knowledge of our characters, of course.So the image prompt needs descriptions, not names.What do I mean by that?Well, if we have a character in the synopsis called Katie,and maybe she's the protagonist, and our image promptsays Katie is standing in front of a burning building, well,of course, the image API has no ideawho Katie is, no idea what she looks like.So what we need is a description of Katie and what she's doing.So maybe how tall she is, what she's wearing.Perhaps she's carrying an axe or some other weaponand is standing in front of a burning building.I've set this as quite an open challenge, and deliberately so.I want you to do some experimentation here.But I will say that you might find it best to use examples.So I have put some examples up here in this examples.md file.But do, of course, feel free to write your own examplesor go online and find some synopses and titlesof your favorite films.And perhaps you can use them as well.OK, pause now, get this challenge sorted,and I'll see you back here in just a moment.OK, hopefully you managed to do that just fine.So let's come in here and start working on the prompt.I'm going to start off with an instruction.I'm going to say, give a short descriptionof an image which could be used to advertise a movie basedon the title and synopsis.Now, I'm going to add to that, the descriptionshould be rich in visual detail, but contain no names.Now, this second sentence may or may not be effective.OpenAI prefers to be told what to do, not told what not to do.But I've had reasonable success with this,so I'm going to phrase it like that.Now, I'm going to add some examples.And I actually put three examples in the examples.md file,but I'm only going to use two.I think two is enough.So first, I'll use the separator,and now I'll paste in my examples.So let's just tidy that up and add any moreseparators that we need.Remember, what we want to do is separate the instructionfrom the examples and actually separate each example as well.And of course, the important partis to include our title, our synopsis,and leave OpenAI a space to create the image prompt.OK, now, just as I was doing that,I realized that up here, I've askedfor a short description of an image whichcould be used to advertise a movie basedon title and synopsis.And then down here, I've used image description as two words.Image description hyphenated and image description hyphenated.Now, OpenAI can probably cope with that kind of typo,but it might be worth just looking outfor that kind of thing and just making sure we are consistent.So I'm just going to change both of those to two words.Now, I'm going to put temperature to 0.8.And I'm doing that because I foundthat some of my image prompts were just a little bit toowacky when it was left at the default one, whichis the most creative setting.Now, it's really hard to tell with temperaturewhether you're making a big difference or not sometimes.It might just have been that the ideas that OpenAI gave meat that time were just particularly strange.Now, it can be really hard to tell sometimesif small temperature changes are making much difference.It could just be that the examples I got beforehappened to be particularly strange.But that said, I've tested this a few times,and 0.8 seems to be about right.OK, so let's hit Save, and we can test itand see what we get.So I'll press Send.And now let's open up the consolebecause that is where our image prompt is going to appear.And there we are, a colorful imageof a raccoon, elephant, alligator, and squirrelstanding in the middle of a city street back to back facingmenacingly towards the viewer.Around them, robotic and alien forcesmarch in the background, weapons drawn.In the sky above, a giant robot claw looms ominously.Now, I think that is a really, really nice image prompt.Now, if you approach this challenge differentlyand you've got different results which you're stillhappy with, that is absolutely fine.There is no one right answer to this.OK, we've got an image prompt.So in the next scrim, let's go ahead and use itto generate an image.When you're ready, let's move on.OK, so it's time to get this image into place.We've generated a good prompt.So now I'm going to set up a new function called fetch image URL.And of course, that needs to be an async function.Now, to fetch the URL, it's going to need a prompt.And we generated the prompt.And we've got it back in this response right here.So it's going to take in a parameter.And I'm just going to call that parameter image prompt.Now, if we have a look at the HTML,we can see that down here inside the output section,we've got this div.And it's got the class of output image containerand the ID of output image container.Well, that is, of course, where we're going to render the image.So let's come back to our function.And I'm just going to add one line of code right here.Now, the source of that image is actuallygoing to be the URL that we get back from this fetch requestto the API.So I'm actually going to leave that empty for now,because that is going to form part of your challenge.But before we get onto that challenge,there's just a couple more bits to do.I want to call this function from inside this fetch imageprompt function.So I'll do that right here.And we need to pass in our image prompt.Well, we've got that right here.So let's just take that and paste it in there.And I'm just going to delete this console.log.Now, the other thing that I'm going to dois just comment this line of code once again.So that is just the display none on the output container.So we'll be able to see the image right there.OK, now bear with me while I paste in your challenge.So this is your challenge.Use the image prompt to generate an image.The image should be 512 by 512 pixels in size.We only want one image, and we want to get a URL backfrom OpenAI.Think about what properties you needto put in the object that you're going to pass to OpenAI.Now, one word of warning.If you find a lot of garbled text in your images,you could specifically request an image with no text.And what I'm talking about is this.Sometimes, OpenAI gives you imageswhich have got this garbled, meaningless text.And this image has also got a really dodgy white border.So there's literally nothing to like about it.So you could just try adding to your prompta sentence which says, I don't want any text in the image.OK, pause now.If you need to flip back to the scrim before lastto refresh your memory, go for it.Get this challenge sorted, and I'll see you back herein just a minute.OK, hopefully you managed to do that just fine.So I'm going to come in here, and I'll set up my response.And we're going to await OpenAI.createImage.And we know we need to pass it an object.And the first thing we'll put in that object is a prompt.And the prompt is going to be this image promptparameter we've got here.But I do want to add a sentence to try and avoidthis garbled text on the image.So I'm actually going to put this in curly braces.We'll have the dollar sign, and we'll wrap it in backticks.And I'm just going to add there should be no text in this image.OK, next I'm going to add an n property.And we don't really need to do that.Again, just a reminder for you, we only want one image.And that is what we'll get by default.Now, for the image size, we wanted 512 by 512.And the response format will default to URL anyway.But let's just write it out.And all we need to do now, then, is deal with what we get back.And we're going to put it right here inside the sourcefor this image.And in fact, I'm just going to delete this challenge text,so we've got a little bit more space.So the image element is already inside backticks.So I can come in here with the dollar sign and the curlybraces.And it will be response.data.data.And I'll just close the mini browser,because this is getting kind of long.And we actually want the element at position zero.And from the object store there, we want the URL.Now, when you tried that, it should have worked perfectly.As I said before, I can't use this format in the Scrimbarecorder, because the image will have disappeared by the time youactually get to watch this.So I'm going to make a couple of changes here.I'm going to change this to B64 underscore Jason.And I'm also going to go for a slightly smaller image,because actually, the encoded images are quite big.It's a little bit overwhelming for the mini browser, whichcan actually crash sometimes if you give it too much data.So I'm just going to go for the 256.A little bit more to do.I just need to tell the browser that this image iscoming in a data format.And I also need to update this.It won't be a URL property.It will be B64 underscore Jason.OK, let's hit Save.And let's put a one sentence outline right here.And it's one we've seen before.It's the time traveler going back to the 80s and fallingin love.Let's hit Send.OK, and we have our image.Now, the first thing to mention isthis is a little bit small, because I'vegone for a smaller image size.So I'm just going to make a little tweak to the CSS.I'm going to come in here where we'vegot the output image container, and we'relooking for an image within that container.And I'm just going to change max width to width.OK, so everything is working.We've got a title.We've got an image.We've got some stars, and we've got a synopsis.So I think what we need to do now is put that to display none.And we just need to make a few little updates to the UX.Now, if you recall, what we want to happen at the endis that we get this view pitch button, which will thendisplay whatever OpenAI has given us.So what I'm going to do is come down here into this function,and we're going to add some more logic right here.And the first bit of logic is justgoing to take this container that we'vegot here, which is currently holding the textarea where we write and then this loading SVG,and it's just going to replace it with this pink button.So let's go ahead and put that right in here.Now, the next thing we need to dois actually wire up this button.So I'm going to set up an event listener right here.And what we'll do then is we'll set the setup containerto display none.So that's the entirety of this section right here.So that is this entire white containeryou see in the mini browser.So let's take control of that container,and then we'll access its style and display,and we'll set that to none.Next, we want to take the output container, whichis this one right here, and that is the one whichis set to display none by default in the CSS.And we want that set to display flex.Now, while we're here, I think weshould actually quickly update the messagethat we get from the movie boss at the very end.He should make some outrageous claim about his own abilityand ask for some money.So we've already selected the movie boss text.So let's set the inner text of that to the following.He's going to say, this idea is so good, I'm jealous.It's going to make you rich for sure.Remember, I want 10%.OK, now for the moment of truth, let'ssee the whole thing in action.I'm going to say a pizza delivery rider infiltratesan organized crime group.Let's hit Save and cross our fingers.So we get the first message.We get the personalized response.Now we've got the View Pitch button,and we're getting an error.I've made a really silly mistake.You can probably see what it is.Just pause now and debug that.OK, so you probably noticed I've actuallyforgotten to put the inverted commas around these two.Let's try that again.There's the first message.And here is the View Pitch button.And there we are.We have got our image.We have got pizza delivery man, the Loire Vitale story.OK, that sounds pretty classy.It's John Travolta and Uma Thurman.That's a pretty good mix if you like Quentin Tarantino films.And let's check out the synopsis.And actually, that synopsis is pretty cool.I would go and see that movie.OK, so everything is working.So let's just take one more scrimto recap what we've done with this projectand where you can go from here.Congratulations on finishing Movie Pitch.Now you've got all of the foundationsyou need to work with the OpenAI API in your apps.Let's just quickly recap what we've studied.So we set up the OpenAI API.And you can see that right here on lines 1 to 11.And we used the text DaVinci 003 modelwith the Create Completions endpoint.And you can see that down here on lines 25 and 26.Now we started off using the zero-shot approach.So we made a simple prompt request to the APIwith just a one-line instruction.We then upgraded that to the few-shot approachwith multiple examples.And we can see that right here, lines 27 down to 39.And we used the few-shot approachto demonstrate to the API what sort of completionwe were looking for.We also used the max tokens property.And you can see that right here.We did that to ensure the model had enough tokensto answer the query successfully.And of course, we also used the temperature setting.And we can see that down here on line 70.And that alters how daring our completions were.Higher temperatures allowed OpenAI's virtual imaginationto go into overdrive.And lower temperatures kept thingssafer and more predictable.Now finally, if we come down here,we can see that we have got a slightly different endpointin use right here.It's the create image endpoint.And we used it to generate images from text prompts.So wow, that was quite a lot.Now it's always a good idea to make a project your own.And there are multiple ways that youcould take this project to the next level.Here are just a few ideas.So in terms of the JavaScript, at the moment,we're making a lot of API calls to the same endpoint.I wonder if you could find a way to think dry,do not repeat yourself, and have one function do the callingso we don't repeat the same line of codelike this one that you see right here multiple times.So that would just involve a bit of neat refactoring.Now in terms of the AI, if you wantto get anywhere in Hollywood or Bollywood,you're going to need a script.And the logical next step of this projectis to have OpenAI create a script for your movie.Now that is a little bit tricky in terms of the amountof tokens you'd have to use.So you would have to break the process up into chunks.But it is doable.And then you could perhaps use the Create Image endpointto create more detailed character sketches.Or you could tailor the app to a more specific genre,so have it create specifically manga or rom-coms.Now if you take these three ideas and sell the script,I want 5%.Now ultimately, the best way to consolidate your learningis to delete all of the code and start again from scratch.You can use it to practice your HTML, CSS, JavaScript,and your knowledge of the OpenAI API.Now of course, you wouldn't need to do it exactly the same way.You would do it as you think bestand just justify the changes you make.So quite a lot of potential work to do there.But with the skills you've got, all of this is possible.Now whatever you do, make sure you take a break nowand consolidate what you've learned before moving onto the next project.It's official.Chatbots are taking over the world.Loads of sites have them.And since the arrival of the more advanced chat GPTmodels, like text DaVinci 003, and now GPT 4,the model we're about to use, chatbotsare going to skyrocket even more.And as they are one of the most common uses for AI in web dev,this course wouldn't be complete without one.So we're going to build a chatbot usingGPT 4, the latest OpenAI model at the time of recording.And it looks like this.Know It All does exactly what it says.It answers your questions and converses with youat a human level.You can ask it anything and it will do its best to answer.Now I need to say a quick word about GPT 4.At the time of recording, you haveto join a waiting list to get your hands on the GPT 4 API.Now I'm sure that will change in time.But if you haven't got GPT 4 API access now,you can click on this slide.It's a link which will take you to the waiting list sign uppage.Now if you don't have access to the GPT 4 API yet, no problem.Everything we do will work with the GPT 3.5 Turbo model.And this is also a very, very capable model.So just take a note of that right nowif you don't have the GPT 4 API yet.And then wherever in the course we use GPT 4,you can use GPT 3.5 Turbo instead.And then when you get the GPT 4 API access,you can just swap out GPT 3.5 Turbo for GPT 4as I'll be using in this project.So what exactly are we going to study?Well, we'll take our knowledge from the previous projectand we're going to add in the chatbot specific syntax usedby GPT 4 and the GPT 3.5 Turbo models.The syntax is exactly the same and it will work with both modelsjust fine.We'll also look at how you can instruct the chatbotto behave in a particular way or have a specific personality.And then we'll look at something called presence penalty, whichcan control how likely the chatbot is to talk about new topics.And we'll also look at something called frequency penalty,which can control how repetitive the chatbot isin its choice of words and phrases.And finally, we'll change directionand look at how we can store our conversation in a databaseso it persists even if a user reloads the pageor closes their browser.Now, I just want to give you a quick warning againthat at the moment our API key is visible on the front end.So be sure to keep it safe, don't share it,and make sure you ignore the end file if you'republishing to a repo.OK, that's enough chat from me.I've already got some HTML and CSS prepared for this project.So let's take a look at that and then get this chatbot working.Let's take a look at the code we've already got.We've got a form component right here and a button,which inside a form component will act as a submit button.Now, this div up here, this is where the conversation unfolds.And in it, we've got this one hard coded message,how can I help you?And that is the message that we can see right here.Now, over in index.js, we've got exactly the same setupas before.These lines of code right here are the open AI setup,just like they were in the previous project.And remember, in terms of the API keythat we're bringing in from this.m file,we will be looking at deploying projects with API keys hiddentowards the end of the course.And always be sure not to expose your API keywhen you're deploying projects, sharing them,or publishing them to public repositories.Now here, we've taken control of the chatbot conversation div.And we can see that right here in the HTML.This is the ID right here.So it's referring to this div.And that is the div where the conversation takes place.Now, we've got that stored in this const.And I've declared that globally, as we'llneed to use it in multiple functions.Now, moving on down, we've got this event listener.And it is listening out for any submit event.And that will be triggered by a user clicking on the buttonor pressing Enter to submit the form.When a submit event is detected, we build a new elementwith create element.We then add the necessary CSS classesand append it to the chatbot conversation div.Then we populate it with whatever the user has inputted.And at that point, we can go ahead and clear the inputfield.Now, this line of code right here just moves the dialoguedown so the latest messages are always in view.Else, as the conversation grows, you'dkeep having to scroll down manually.Now, this is quite a neat way of doing it.But you could also use scroll into view.But I found when you're running a mini browser in a big browser,that can sometimes fail.So I went for this approach.Finally, we have this render typewriter text function.As the name suggests, it will give a typewriter effectto the AI's text as it is rendered.Now, there are loads of ways to do typewriter text.Some you can do just with CSS.But I've gone for a JavaScript approach.And what happens in this function is, again, wecreate a new element.We add the necessary CSS classes.This one includes a blinking cursor class,which would just give a nice blinking cursoreffect to the text as it's rendered.And in fact, you can see the CSS for thatright at the end of the CSS file.We've got the animation right there.The speed at which each individual character is renderedis controlled by this set interval.And at the moment, I've got it set to 50 milliseconds.And you can, of course, change thatif you would prefer a different speed.Now, we won't be working much with the rest of the CSSin this file.But do pause and check it out if you would like to.There's nothing particularly special going on.But we have got a bit of CSS grid up herewhere we deal with the chatbot header.So the CSS grid is just used for this layout up here.OK, so that is what we have so far.Let's move on and take an overview of how the AI isgoing to work in this project.It's a little bit different to what we've done so far.So let's look at that next.OK, let's take an overview of how the GPT-4 model workswith chatbots.So we're going to use one functionto make requests to the API.And in a conversation, we'll use that function multiple times.But we need to think about what we send in the promptbecause there's actually a big problem for chatbotsthat we have to overcome.And I want to illustrate that for you right here.So what I've got here is a simple call to the APIusing the create completion endpoint and the textDaVinci 003 model, which is the model weused in the previous project.And I chose it here because it should look pretty familiarby now.And I can use it to illustrate the pointthat I want to make about chatbotswithout getting caught up in new syntax we haven't studied yet.Now, I'm going to come in here to this prompt.And I'm going to ask a question.Where were the 2001 Wimbledon tennis championships held?OK, let's call that function.And we'll hit Save and open up the console.And we get the answer.The 2001 Wimbledon tennis championshipswere held at the All England Lawn Tennis and CroquetClub in Wimbledon, London, England.OK, so it's a correct answer.Now let's ask it who won that year.And I'll hit Save.And it tells us the Philadelphia 76erswon the 1982 NBA championship.And this is what's called a hallucination.The AI makes up a linguistically plausible answerwhen it doesn't know the right answer.And we'll talk more about hallucinationslater in this course.Now, it figures that it doesn't know the answer.The question who won it that year onlymakes sense in the context of the previous question, whichhad the keywords Wimbledon and 2001.And that exposes a big problem for chatbots,which is that models have no memory of past completions.And that means that all relevant informationmust be sent with each API request.So I need to refactor my second questionto include all of the informationthat the model needs to know, i.e.who won Wimbledon in 2001.Let's run that.And it says Goran Ivanicevic won Wimbledon in 2001.And that is true, with the only problembeing that it's assumed I was talkingabout the men's championships.The women's championships were won by Venus Williamsthat year, and she beat the Belgian Justine Ennanin three sets.So there's just a little example of the biases picked upby AI models as they're fed data from the open internet.OK, so when it comes to chatbots,in order for the model to interact properly sothe conversation flows and remains logical,the model needs to know the context of the conversation.And we achieve that by sending the conversation as it existsso far with each request.So let's look at a diagram of how the main AI business logicis going to work with this chatbot.So the first thing that we'll need to dois store the conversation in an array.And that is what's represented here by this box.And this does have to be an array.The GPT-4 model and the endpoint we're going to be usinghave much stricter rules on syntaxthan the text DaVinci 003 model and the Create Chatcompletion endpoint.Now, once we've set up this array,we'll use some special OpenAI syntaxto instruct the chatbot and tell it how we want it to behave.And then we'll store that instructionin an object at the first index of the array.And I've just put the curly braces either sideof instructions just to make it clearthat that will be an object and that this is an array of objects.So now we've got the instructionsat the first index of the array.We will take some input from the user.And the first thing to do with that inputis to render it to the DOM.Then we'll use some OpenAI syntax to format it.And again, we'll save it in an object in conversation array.Once that's done, we're going to send the entire conversationarray off to the OpenAI API.And what we'll get back, of course, is the response.And what we'll need to do then is render the completionto the DOM and then place the completion in an objectwith the correct syntax that we'll be discussing shortly.And then we'll be adding it to conversation array.So right now, conversation array has got three objects.We've got the instructions, the user's input,and the first response from the API.And then as you can imagine, this process continues.We take the user's reply.We render it to the DOM.We place it in an object.We store that object in conversation array.And then we send it off to the API.We get back our response.And we render it to the DOM, place it in an object,and then store the object in conversation array.And that process continues with the user's response.And we just keep repeating as needed.And this can go on and on until you reach the token limit.But the token limit with the GPT-4 modelis extremely generous.So it would have to be a very, very long conversation,indeed, to reach that limit.OK, that's the overview.Let's get to work.OK, so we need a place to store our conversation.This is going to be the single source of truth, as it were.The place where everything we ask of openAIand everything it replies to us is stored.So I'm going to come in here.And I'm going to set up a const called conversation array.And in fact, I'll abbreviate array to just R.And remember, this is going to store an arraybecause the API needs to have this conversationas an array of objects.So let's look at the first object that we need.It's the object that holds the instruction.This is where we tell the chatbot how we want it to behave.Now, this instruction object consists of two key value pairs.And that will be the same for all of the objects in this array.They're going to follow a similar pattern.The first key will be role.And this should correspond to the value system.This is just telling openAI that what comes nextis the instruction and not part of the conversation.The second key will be content.And this should correspond to a string with an instruction.And this is your chance to influencehow the AI behaves and responds.So I'm going to come in here.And I'll set up the first object in this array.So the first key will be role.And we'll set that to the string system.And the second key will be content.And this will hold our instruction.And for now, I'm going to put something fairly mainstream.I've gone for you are a highly knowledgeable assistant.That is always happy to help.Now, later on in the project, when the chatbotis up and running, we will actuallyrevisit this instruction and have some fun with it.But for now, let's keep things simple.OK, so we've got the conversation arrayand the instruction object set up.Now, let's deal with the user's inputted text,which we'll also be adding to this conversation array.So let's come on to that next.OK, so we have the instructions object in the array.And now we need to add the user's input.So in index.js, we've got this event listener listening outfor a submit.And when it detects the submit, the anonymous functiontakes the user's input and saves it to this const user input.So what we need to do is take that incoming textand put it into an object and push it to conversation array.Now, we've already seen how the chatgpt model wants its objects.And we've got an example of it right here.We've got an object with two key value pairs, role and content.And what we're going to do next is actually very, very similar.The object is going to have two key value pairs.The first key will be role.And this should correspond to the value user.The second key will be content.And this should correspond to a string holding whateverthe user has inputted.So right here inside the event listener's anonymous function,I have written you a challenge.I want you to push an object holding the user's inputto conversation array.And then just log out conversation arrayto check it's worked.Now, I'm going to leave this slide right hereso you know exactly what that object should hold.OK, pause now, get that sorted, and I'll see you back herein just a moment.OK, so hopefully, you managed to do that just fine.So I'm going to come in here, and I'mgoing to say conversation array, and I'll use.push.And we're going to push an object.And we know the first key will be role.And that will have the value of the string user.The second key will be content.And that will hold whatever objectthe user has inputted. OK, now let's log out conversationarray and see if it's worked.So I'll open up the console, and I'll ask a question.And there we are.We are logging out conversation array.And you can see that we've got two objects.The first object has got the role of systemand the content with our instruction.The second object has got the roleof user and the content, what is your name,which is the question that I'm going to use.What is your name, which is the question that I just asked.OK, so that is perfect.We have got the conversation array growing.We've got the instructions object.We've got the user's inputted text.And the next step of the process isto send it all off to the OpenAI API.So in the next screen, let's lookat how we actually use the Create Chat Completionsendpoint, which is just a little bit different to the previousendpoints we've used.OK, so we've got our conversation so far,and it consists of two objects, the instructions objectand the user input object.So let's work on sending them off to the API.So back in index.js then, when the event listener detectsa submit, let's call a function called fetch reply.And I'll come down here and set the function up.And because this function will be called fetch,and because this function will be calling the API,this will be an async function.Next, let's store the response to a constand await the API call.Now, so far at this point, we've beenusing the create completion and create image endpoints.But now, we're going to use something different.Let's head over to the API docs and see what we can find.And this slide is, of course, a link to those docs.What I'm looking at here is the API referencefor create chat completion.And there's a ton of info on this page,and we will be investigating it more soon.But I want to focus in on the code examplethey give us right here, and specifically this.It says openai.createchatcompletion.OK, let's go back to the code, and we'regoing to add create chat completion right here.And just like with the other endpoints,we're going to pass it an object.So in the next grim, let's head back to the docsand investigate what information this endpoint needs from us.OK, so let's complete the object we'regoing to send to the API.If we go back to the docs, we cansee that two properties are required.They are the model and messages.Now, so far for the model, we've been using text da Vinci003, which is a very capable model.But now we're going to use GPT-4.GPT-4 is the newest and most impressive openai model yet.It makes huge improvements on its predecessors,and that is why everyone's been talking about it.Now, if you're looking at these docs and thinking, wait there,it says GPT 3.5 Turbo here.Yes, the GPT-4 model is fresh out at the time of recording,and these docs need updating.So if you click through to these docs,you might find they look a bit different.Now, let's just click through to this endpoint compatibilitytable.We can see that GPT-4 is listed under chat completions.So this is going to work just fine.Now, for the messages property, slightly confusingly,the example they've given here is a bit of a simplification.So I'm going to ignore that and click through to chat format.Here we can see the format that it wants,and hopefully that looks familiar.It's an array with objects.And each object has got two key value pairs, role and content.And this is exactly what we have in conversation array.We've got an array of objects, and each objecthas got two key value pairs with role and content.And if we look closer here, we cansee that the first object has the role of system,and the content is an instruction.So in the object we sent to the API,our messages property just needs to hold conversation array.So just to recap, the object we sent to the APIwill have two properties, model, which is GPT-4,and messages, which should hold conversation array.And you can think of messages as beinga replacement for the prompt propertythat we used in the previous project.OK, so let's do this as a challenge.And we're working here inside fetch replyand inside the object that we're going to send to the API.I want you to give this object a model property of GPT-4,give it a messages property, whichshould hold our conversation array,and then ask a question, hit Send,and log out the response to see if it works.Now, just before you do that, youmight have noticed that I'm not nudging youto include a max tokens property.In the past, we found that max tokens defaulted to 16.That was when we were using the text DaVinci 003model on the create chat completions end point.Things are different.Because we're building up the conversationand sending it with every request,trying to define a single max tokens figure is impossible.And in fact, the default with GPT-4 is much higher anyway,so it's not going to cause a problem.OK, code up this object, and then we'll have a look together.OK, so hopefully you got that working just fine.So this should be quite straightforward.The model is GPT-4, and of course, that is in a string.And the message is our conversation array.Let's just come down here and log out the response.And I'll hit Save, and I'm going to ask it a question.I've asked, what is the capital of Tunisia?And we've got a response, and I'm justgoing to copy that response and paste it into the editorso we can see it really clearly.We've got loads of info here, just like before,but the important bit is right here with the content.The capital of Tunisia is Tunis.So we have successfully made our first requestto the GPT-4 model.OK, next we need to use this response in two ways.We need to update the DOM, and weneed to update the conversation array.So let's look at that next.Next, we need to update the DOM, and weneed to update conversation array.So we're going to go straight into a challenge,and I've got the challenge right here.We're working inside the fetch reply function.So I want you to pass the completion to the rendertypewriter text function so it updates the DOM.And we've got the render typewriter text functionright here, and it takes in a parameter.Now once you've done that, push an object to conversation array.This object should have a similar formatto the object we pushed in line 21,but the role should hold the string assistant,and the content should hold the completion weget back from the API.Let's just have a quick look at line 21.Here it is.It's actually line 22.We're pushing this object.It's got the role of user, and the contentis the user input dot value.So the object that we pushed to conversation arrayis going to have a very similar format.Now once you've done that, you can log out conversation arrayto check it's working.And of course, you should see the DOM updated by the rendertypewriter text function.Now I've given you a big hint here.To save yourself some time and work,have a close look at the responsebefore tackling number two.And I've actually left the responsethat we logged out in the last scrim right here,because that will help you.OK.Pause now, get this challenge sorted,and I'll see you back here in just a moment.OK, hopefully you got that working just fine.So I'm going to come in here, and I'llcall the render typewriter text function.And what do we need to pass it?Well, if we come down to this response,we can see that we've got the actual completion right here.And we can access that by saying response dot data.And we want what we've got at the zero index of that array.And then we want to access the content in that object.So quite a convoluted line of code.But let's just write all of that in here.So it's response dot data dot choices.Then we want the element at position zero.Then we want to access the message property.And then the content.OK, next let's push an object to conversation array.Now luckily, and it's what I was getting at with this hint,I don't actually need to build an object.If we have a look again down at the response,let's see what we've got right here.Well, we've got an object, and it'sgot two key value pairs, role and content.The role is assistant, and the content is the completion.So that is exactly what we want already formatted.So I hope you noticed that, and you didn't extract the textand then write the code to build a new object.OK, so back up here, we're taking almost everythingthat we've got here.But because we want the whole object,we'll take away the dot content.And now let's just log out conversation array.I'll hit Save, and let's ask a question.What is the currency of Peru?And we've got an answer.The currency of Peru is the Peruvian soul.That's great.Fantastic answer.And if we open up the console and have a look,we can see conversation array.And it's got three objects in it, the instruction,the user inputted text, and now the objectwith the completion we've just got back from the API.OK, so our chatbot is essentially working.Now, I just want to ask it a couple of questions.What I'm keen to see is, is it keepingthe context of the conversation?Does it have a memory that it's gettingfrom our conversation array?So I'm going to ask it for pi.OK, and it's given me a very long answer.All I really wanted was the number 3.14159.But that's good, because now I can check its memory.I'm going to say, give it to me to three decimal places.And what's interesting to see hereis, does it understand it to be pi, which we were justtalking about?If it does, it's got a memory, and it'skeeping the context of the conversation.Let's find out.And there we are, pi to three decimal places is 3.142.So it has a memory, and that is exactly whatwe want from a chatbot.OK, so we've pretty much nailed the chatbot,or at least its basics.So let's take a look at a few more tweakswe can make to really level up our chatbot skills.Now, one danger you can run into with chatbotsis that they can get repetitive.No one likes a conversation with someone that just saysthe same thing over and over.So let's take a look at how we can deal with that next.At the moment, we're only using two propertieswhen we make a request to the API.We're using the model and the messages.And they are both required.Now, in the previous project, we used max tokens, which,as I said, is not so helpful here.And we also use temperature, which you're welcome to addif you think your chatbot is not performing optimally.You can just go ahead and add it right here.And just like with the DaVinci model, it defaults to one.Now, I don't think we need to change the temperature on this,so I'm actually going to delete that.What I do want to look at, though,is two settings, frequency penalty and presence penalty.And what they do is offer some controlover how repetitive our output is,because we want the language to sound natural,and we don't want to find ourselves saying,can you stop saying that?Now, we're going to look at these two settings togetheras they are similar and they're easy to confuse.So let's take presence penalty first.Presence penalty will be a number from minus two to two,and you can change it in increments of 0.01.It defaults to zero, so that is what we're using nowbecause it's unset.At higher numbers, presence penalty increasesthe model's likelihood of talking about new topics.So what does that mean in the real world?Well, let's imagine a conversation between two friends,and this conversation is taking placeat low presence penalty.So one friend says, hey, give me some good news.And the other friend says, Manchester United won six nil.It was the best game ever.I've never seen Real Madrid fans looking so unhappy.Manchester United are the best.Let me tell you about the game in detail.Hmm, we all know someone like that, right?Now, what would happen to this conversationif we could flip it to a high presence penalty?The first friend says, hey, give me some good news.And the reply is, well, my team won on Saturday.My investments are doing well.My brother's out of hospital, the sun's shining,and I'm getting married next June.So you can see that instead of obsessingover Manchester United,they're actually talking about more topics.Okay, let's compare that to frequency penalty.The settings are very similar.It's a number from minus two to two,and you can change it in increments of 0.01.It also defaults to zero.At higher numbers, it decreases the model's likelihoodof repeating the exact same phrases.Okay, let's again imagine a conversationbetween two friends,and this will take place at low frequency penalty.So the first friend says, hey, how was your week?And the reply is,I went to a literally unbelievable party.There were literally millions of people trying to get in.Brad Pitt was there,and I spent literally the whole evening with him.Me and Brad are literally best friends now.And we've all met that person, right?The one who says literally a lot, or basically,or you know what I mean.Okay, if we repeat that at a high frequency penalty,hey, how was your week?I went to an amazing party.There were literally thousands of people trying to get in.Brad Pitt was there,and I spent the whole evening with him.Me and Brad are best friends now.Same unbelievable story,but the word literally has been used only once.So the frequency penalty will allow the word to be used,but it will stop it being overused.Okay, that's the theory.In the next scrim, let's get practical.Okay, so the conversation we looked at in the previous scrimwas of course very contrived.Actually, presence penalty is a very subtle setting,and it can be hard to see it in action.In fact, it's only really noticeablewhen you're generating large amounts of text.So rather than watch me churning out loads of text,you're going to have to do some investigation on your own.So I'm going to come in here,and I'm going to set presence penalty to zero.And that is, of course, its default setting.And now I want you to spend some time experimenting.So you could just have a general chat with the chatbotat different presence penalty settings,but it's likely better if you ask it somethingthat will generate a long answer.It's only then that you'll really seepresence penalty in action.So here are some ideas.If you're a glass half full kind of person,you could ask it to tell youwhat is great and wonderful about the world.And if you're a glass half empty person,you could ask it to tell youwhat is wrong and terrible about the world.Either way, use the same prompt two or more times,but with different presence penalty settingsand see what you get.And if you don't notice too much, don't worry.This is a subtle setting.And at least now you know it's there.So if you do have problems in this area down the line,you'll know what to do.Okay, take some time to do that now.And then when you're ready in the next grim,we'll look at frequency penalty.Okay, let's do some experimentation togetherwith frequency penalty.And let's remind ourselves firstwhat frequency penalty is supposed to do.We use a high frequency penaltyto decrease the model's chancesof repeating the same phrases.So what I'm going to do is set you a challengewhich will involve generating some textwhich is likely to have some repeated words and phrases.Now, because we're going to generate a lot of textand it will actually be pretty painfulto watch the render typewriter text functiontrundle through all of it,I've actually commented out that function call right hereand I've replaced it with this console.logso we can just log out the completion.Now I've also put a file up here called output.mdand we can paste our completions in thereand save them for comparison.So here is your challenge.I want you to set the frequency penalty to zero.Give the chatbot this query,generate 20 ways to say you can't buy thatbecause you're broke.Paste the results into output.mdand then repeat that processwith frequency penalty set to two.Once you've done that,you can examine the differences between the two outputsand see what frequency penalty is doing.Now I've just put a warning here,do not set frequency penalty to minus twoand I've said that because it actually breaks thingsquite spectacularly,it will just churn out the same word again and againand again until all of the tokens it's allowedhave been used upand in fact, it will probably crash the mini browser.Okay, pause now, have a go at that challenge.I'm going to go through the same processand we'll have a look at the two completionsand compare them.Okay, so hopefully you managed to do that just fine.So I'm just going to quickly go through that processand paste my completions into output.md.Okay, so I've got my two outputsand if we compare them side by side,well, they both start okay.So we've got at frequency penalty zero,your financial situation doesn't permit youto make that purchaseand then unfortunately,your funds are insufficient for buying that item.Both of those are fine, both great English.Let's have a look at the first two that we've gotwhen frequency penalty was set to two.Unfortunately, your current financial situationdoesn't allow for that purchase.It seems your wallet is feeling a bit lightto acquire that item.Okay, a little bit quirky, but no problem.Now let's come to the very endbecause it's the last part that's going to be most difficultwhen the frequency penalty is high.Now number 20 here was with your financial setting,it's infeasible to add that to your possessions.Well, that's okay, it's correct English.It's a little bit strange.Now down here, we've got monetary scarcitydictates frugality and disciplinedespite passions give merit where it's due,nullifying all impulses towards luxury, at least for now.I can't decide if that's poetry or gibberish.I think it's just gibberish.And actually, if we look a little bit further up,we can see that by setting the frequency penalty high,we've really caused open AI problemsbecause this is the first timethat we're actually seeing bad English.We're actually getting completionsthat don't seem like they come from a human.Take for example, number 17.It's apparent after analyzing existing revenue streams,financing the stream can simply just about only be squeezedfrom another worldly dimension entirely.Don't know what that means.Or number 18, empty pockets rarely find footingwhen chasing certain ambitions.In our material world,might as well try catching stardust instead.Again, kind of poetic,but these weird little mistakes as well,there's a comma there, but no space.Now, one other thing I want to show you is this.I'm just going to highlight every instanceof the word financial.Now we can see if I scroll down,that word appears seven times,but five of those times are when frequency penaltywas set to zero and only two of themwere when it was set to two.So that shows us that the frequency penaltyis penalizing the word financial.It's only letting it appear twice.And when we're talking about money,it is quite an important word.Let's do the same thing with the word purchase.Again, the word purchase is used seven times,five times with frequency penalty at zeroand just twice with frequency penalty set to two.So we can really see why the model is strugglingto generate new language.Okay, so what is the bottom line?Well, here is my general advicefor presence penalty and frequency penalty.And I'm going to express this as a flow chart.Firstly, ask yourself, is there a problem?If the answer is no, do nothing.If the answer is yes, then my advice is this.Don't go over one for either setting.Don't go under one for either setting.You can experiment outside of those parameters,but I would recommend staying inside themelse you run the risk of gettingsome pretty strange results.And lastly, it's all about making small changes and testing.If you just make a small change and test,you'll very quickly find the settingswhich work for you and get you the results you want.So what are we going to do in this app?Well, I'm going to leave presence penalty at zero.I don't think it's doing too much for us anyway.And frequency penalty, I'm going to put to 0.3.And I'm going to do that just becauseI've had to play around with this for a long time.And I think that is where we get the best results.You of course are free to differ.Okay, so the chatbot is working pretty well.So next, I want to go back to where we startedto this instruction right hereand have a bit of fun with itand just see how we can alter the chatbots personalityand why that might be useful.When you're ready for that, let's move on.Let's have some fun and change the chatbots personality.So here's a challenge for you.Update the content properties valueto change the chatbots personality.So you just need to alter this string right here.You could ask it to be cheeky or funny or talk in rhymeor go for something practical.Maybe you want a shorter answer or even a one word answer.I'll leave that up to you.Pause now and have a go.Okay, hopefully you managed to get a good effect.Now I'm British, we love sarcasm.So I'm going to make this a sarcastic chatbot.And let me ask it something.And there we are, it's had a pretty good effect.It says you should definitely go to the most boring placeon earth, your local park.Why explore beautiful beaches, breathtaking mountainlandscapes or exotic cities with rich culturewhen you could just sit on a bench and watch the grass grow.Sounds like a dream vacation.Okay, that's pretty sarcastic and I like it.But actually there is a more serious side to this as wellbecause we can actually get the chatbotto behave exactly as we want it to.Perhaps you want a chatbot that's going to interactwith children, perhaps you want a chatbotthat's going to interact with people for whom Englishor whichever language you're working inis not their first language.So you might want it to simplify the language a little bit.And perhaps you don't want such long answers.We have actually got some quite long answers so far.So I might change this to keep the answers short.And I'll ask it a big question.What is quantum computing?And look at that, the most concise definitionyou'll ever get, advanced computing using quantum bits.Okay, so that's good to know.You can control the chatbots personalityand it really is that simple.Okay, so we're pretty much donewith the mechanics of this chatbot.What I want to do next is use a Google Firebase databaseso we can persist the chats even when we refresh and reload.Let's do that next.Okay, so we're going to add a Google Firebase databaseto this project so we can persist the chat.Now, what does that mean?Well, let's check our specific aims.We want to persist the chat so that a user can pick upwhere they left off after a refresh or reload.So the conversation will be stored in the databaseand the user can close the page, turn off their laptopand come back and continue the conversationat a later date.We want to give the user the ability to reset the chatso they should be able to delete the conversationand start a fresh conversation from the beginning.So how is this going to work?Let's take a look at a diagram.At the moment, all of our code is on the front endand we've got an array holding our conversation.We send that off to open AIand it sends us back a response.What we're going to do now is remove the arraywhere we store the conversation on the front end.We're going to create a databaseand we're going to store the conversation arrayin that database.When we need it, we'll bring it down to the front endand use it when we make calls to the open AI API.To start this off, we need a Google Firebase accountand we need to set up a database.So let's start doing that next.We need a Google Firebase account.So head over to the homepageand actually the image on this slide is a link.Click on it and it's going to take you straight there.When you're there, click on Get Startedand that is going to take you to a signup page.And once you've entered your detailsand set up your account,you'll end up on a page looking like this.Click Create Projectand here we need to give the project a name.I'm going for know it all dash open AIbut of course you can call yours whatever you want.And now it's going to ask us if we want Google Analyticsand for this project, I'm going to turn it off.Now hit Create Projectand it will take a few moments to set things up.And when it's ready, you can just click Continue.Now we've created our project, go over to Buildand then from the dropdown menu, select Realtime Database.Click Next, click Create Database.But if you're interested in finding out a little bitabout the different types of database that Firebase offers,then do click this linkand that will give you a little bit more info.For this project, we're using the Realtime Databasewhich is the easier one to work with.So create database and then in the popup,select the server that's nearest to you.I'm in the UK, so my nearest is Belgium.Click Next and it's going to offer uslocked mode or test mode.I'm going for test modeand that does mean that anybody with my database referencewill be able to view, edit or delete any of my data.Now that's fine for the purposes of this course.By the time this gets published, I will have locked this down.I recommend starting in test mode.It's just a little bit easierto not have to deal with the security rulesat the beginning.You can always read up on that laterand make some changes to the security rules if necessary.And there we are, we have our database.And the most important thing here is this URL.That is the URL we'll be usingto communicate with our database.So let me just zoom in on that.There it is.I'm going to click here to copy itand then in our code,I'm just going to create a little comment hereand paste it in.And we'll use that in the next grimwhen we start adding the Firebase setupto this code right here in index.js.We need to add the Firebase dependency.So I'm going to come over here to the three-dot menu.And when I click on that, a menu appearsand you can't actually see that in the recording,but I'm going to select add dependencyand a pop-up appearsand I'm just going to type in Firebase.And I'll click addand we can see that the Firebase dependencyhas appeared over here on the left-hand side.Now, if you're working locally,you can install this via MPMand you can check out the Firebase docs on that right here.Again, this screenshot is a linkjust click it to go straight through to those docs.And by the way, you can also use a CDN to work with Firebaseif you prefer to do it that way.Okay, now we've got the Firebase dependency setup.We need to import some methods.So I'm going to come right up here to the topand we'll say importand then inside curly braces,I'm going to say initialize app.And we're importing that from Firebase slash app.Next, I'm going to import get database and ref.And these are coming from Firebase slash database.Okay, that's all the methods that we need.Now I'm going to come down hereand set up a const called app settings.And this is going to hold an objectand it's going to have one key value pair.Database URL is the keyand the value will be a stringcontaining the URL that we got when we set up the database.And we can delete that comment now.Underneath app settings,I'm going to set up another constand this one will be database.And here we'll use one of the methodsthat we've just imported, get database.Next, I'm going to come down here and set up a const app.And now we will use one of the methodsthat we just imported.So I'm going to say initialize appand I'll pass in the app settings.Now we need a const database.And again, we'll use one of the methodswe just imported, get database.And we'll pass in app.And finally, we'll set up a constcalled conversation in database.And I've just shortened database to DB.And we'll set that equals to refand we'll pass in database.So what we've just done thereis set up a const called conversation in DBand it stores a reference to our database.And that's really important because now conversation in DBis going to be our single source of truthfor the conversation we have with the chatbot.Okay, those are all the basic settings we need for now.We will add a few more methods later as we go on.Now, before we do anything else,we do need to make a few changes to the HTML and CSS.I want to add a clear button right here.So I'm going to go over to index.htmland I'll come in here and just paste in the clear button.And I'll hit save and of course we've broken the CSS.So let's head over to index.cssand we need to make a couple of changes.So firstly, I'm going to come down hereand paste in some CSS for the new button.And as soon as I do that,you can see that things start to change over here.Now I've used the selector clear-btnand if we have a quick look back at index.html,the button has already got that class added.And the most important part of this CSSis actually this property right here,grid area clear-btn.And we're using that because the layout up hereuses CSS grid.So if we come up here to the chatbot header selector,this is where we're setting display gridand we've got the grid template areas right here.And I'm going to change this dot for clear-btn.And now things are starting to come into alignment.So clear-btn is the grid areathat we've got on the clear-btn selector.Now we've still got a flat edge to this buttonand that's because at the moment down on line 137,we are currently selecting all buttonsand we've got styles set up for this submit buttonthat we've got right here.And the submit button has a border left of zero.Now, if we go back to index.html,we've got the submit button right hereand it's actually already got a CSS class of submit-btn.So how about we come over hereand we replace this with the more specific selector.Okay, that has had the effectof giving us a full rounded button,which is what we want right here.Now all we need to do is bring this into alignmentby coming up to the support ID selectorand taking this property right here,text align right and changing it to center.Okay, now we've got it looking how we want itand we're good to move on.Next, we need to figure out how to push our user's inputto the database.Right here, we're pushing our user's inputto conversation array,but now we want to store the user's input in the database.That is going to be the single source of truth.So let's use Firebase's push methodto push it to the database instead.To get access to the push method,we need to add it to the list of imports.So I'll come up here and add it in right there.And then back down in the event listener,let's come in hereand we're going to delete conversation array.And now we've got pushand that is no longer the standard JavaScript array method.That is now the Firebase push method.And what we need to pass itis the reference of the database we want to add to.And the reference to that database we've got up here,it is conversation in DB.So we'll say push and then in brackets,conversation in DB, a comma,and then the object which we want to push.And that is of course, exactly the same object.And it's as easy as that.So now let's go ahead and type something in hereand we'll hit send.And let's take a look at what we've got in the database.And there we are, it has appeared.If you log into your real time database,you'll pretty much instantly seeexactly what we've just pushed to the database.So we've got the content, hello, know it all,and the role of user.So that is our object.Now doing that leaves conversation arraylooking pretty redundant.We don't want to store our conversation here anymore,but that leaves us with an issue.We've got this instruction objectand we need to keep it somewhere.But storing it in the databasewith the rest of the conversationhas actually got two disadvantages.Number one, if we ever want to edit the instructionto change the chatbots personality or behavior,we'll actually have to edit the database directly.And number two, when we want to clear the conversation,we're going to get caught up in JavaScript spaghettimaking sure we don't delete the instruction,but do delete everything else.So we'll be making work for ourselves.The solution that I think is bestis that we keep the instruction right here in index.jswhere it's easily accessible and easily editable,and we just add it to the arraywe're sending to OpenAI with each request.So what I'm going to do is change conversation arrayto instruction object.And now it's an object, let's delete the square brackets.And when we update fetch reply,we'll add this to the array we send off to the OpenAI API.And actually updating fetch replyis what we need to come on to next.The next thing we need to dois make some changes to fetch reply.We know we need to send the entire conversationwith every request to the OpenAI API.But now that the conversation's stored on the database,we need to fetch it before we can include itwith our request.And with Firebase, we do that with the get method.But before we can use the get method,we need to add it to our list of imports.So let's come up here and we'll just put it after push.Now get is a method, so we'll give it the bracketsand we're going to pass in the reference to our database,just like we did with the push method.Now we're going to chain a thenand here we'll have a callback functionand that function gets a parameter snapshot.And snapshot is the data in our databaseas it exists at this time.Now inside the body of this function,let's be safe and use an ifjust to make sure a snapshot exists.So if, for example, writing to the database right herein the event listener failed,then we would want to know about that.So let's just say else, no data available.Because if what we send to the OpenAI APIis not the array of objects it expects,it's going to give us an error anyway.So it's a good idea to check what's going on here.Now in here, we can make our request to the OpenAI API.So let's just cut and paste all of this code.And let's just format that nicely.Now we're actually not quite ready to call the API.So I'm actually going to comment out all of that code.And let's just come in here and log out snapshot.Now remember, we've already got something in our database.So there should be something for us to log out.So rather than write anything more in hereand add to the database,I'm just going to call the fetch reply function.Now when I hit save, let's just see what we log out.Well, there we are.We can see the contents of our database.We've got an object.It's got a content key with hello know it alland a role key with user.But at the beginning,it's also got a Firebase identifier of some kind.And we don't want to be sending that to OpenAI.It would just really confuse it.All we want is an array of objects.So let's check what the Firebase docs say.And they talk about this val method and it says here,it extracts a JavaScript value from a data snapshot.Well, that is exactly what we want to do.Now, if you'd like to read up more about valin the Firebase docs, this screenshot is a link.So just click on it and it will take you straight there.So I'm going to come in hereand where we've got snapshot, I'm going to call val.And let's just save and see what happens.Okay, so on its own,it doesn't make any difference.We've still got Firebase's identifier and then our object.So let's just check something else we can use from MDN.And again, this screenshot is a link to this page on MDN.Now object.values, let's see what it says here.It says the object.values static methodreturns an array of a given object'sown innumerable string keyed property values.Okay, that sounds like a bit of a mouthful,but the important thing here is it returns an arrayand an array is what we want.So let's just experiment with it and see what we get.So I'll come in here and say objects.valuesand then in brackets, we'll have our snapshoton which we've called the val method.Okay, let's hit save.And look at that, down in the console,we have got an array and it's got our object in it.And that is the exact correct formatthat we need to send to the OpenAI API.But we're not quite ready to send it yet.We need to think about the instruction.So let's do a little bit more workin fetch reply in the next scrim.We need to get the array that we can see in the consoleoff to the OpenAI API.So I'm going to come in hereand resurrect the old conversation array.And we'll use it to store the arraywe get back from the database.And then if I uncomment all of this code,we're now going to send conversation array offto the OpenAI API with each request.Now to check it's working,I'm going to log out the responseand I'll just take this opportunityto delete the console.logand also the function called to fetch replythat we were just using as a test.And now we can give this a try, but wait a second,we've actually forgotten about our instruction object.We need that in the conversation that we sendto the OpenAI API.So we need to include it in conversation array.And in fact, you can do that as a challenge.So I'm just going to come in hereand paste the challenge right therebecause that is where you'll need to write some code.And I've just said, add instruction objectto the front of conversation array.But I've put a warning here,you're going to get an error when you do this.Try to debug it.Okay, we're already logging out the response.So pause now, get this challenge sortedand I'll see you back here in just a minute.Okay, hopefully you got it working.So we can do this with unshift.So we'll say conversation array dot unshiftand then we'll pass in the instruction object.Okay, now let's hit save and we'll give it a try.Oh, but we're getting an error.And I did warn you that you would.Now it's saying unexpected reserved word.So what could be the problem here?Well, we're using await hereand we can only use await inside an async function.And that's what we're doing, isn't it?We've got async right here.Well, actually no, because this awaitis inside the callback function that we've got right here.So that is the function that should be async.So let's delete async from here and add it in right here.Okay, let's save and try again.And there we are, it's working.So the final thing that we need to do with this functionis uncomment these two lines of code right here.And in the next grim,let's see what changes we need to make to them.This line of code right here,which sends the completion to render typewriter textis absolutely fine.We don't need to change that.But here, we don't want to update conversation array.Remember, conversation array is now hereand it just holds the array we get back from the databasewhen we use this get method.Our single source of truth is on the database.So what we actually need to be doing right hereis updating the database.So here is a challenge for you.I want you to add the completion to the databaseand then ask the chatbot something to check it's working.Now to complete this challenge,you can look back at the code we've already written.And remember, this code here gives us an objectwhich is already formatted in the way we need it.Okay, pause now, get this challenge doneand I'll see you back here and we'll have a look together.Okay, hopefully you managed to do that just fine.So we need to use the push methodand we need to pass it the database ref,which is conversation in DB.And then we give it the object we want to pushand we can do that with this code right here.Okay, let's delete this line of codeand we'll save and give it a try.I'll ask it a simple questionand it's given me a reply, it's looking good.Let's just see if we've successfully updated the database.So this is what we originally had in the database.We've made a few changes to it since thenand now look, we've got my question,what is a Frisbee and the answer, a flying disk.So the code that we just wrote right hereis definitely working.Okay, so things are going well,but we've got a bit of an issue.If I just refresh the mini browser,in the database, we have got a whole conversationthat I don't know about as a user, it's not shown here.And that's a problem because if I now start typinga question, I'm not aware that I'm actually continuinga conversation and in fact, I might well have forgottenwhat I wrote before.So that means we've got two more jobs to do.We need to render the existing conversation outwhen the app loads so the user can seewhat they've already said.And we also need to wire up this start over buttonso that a user can reset the conversationwhenever they want.So let's start on the first task of rendering outthe conversation on load next.We need a function that will render out the conversationas it exists on the database when the app loadsso the user can see what has already been discussed.Now I've set you a challenge to do thisand it might seem like a big challenge,but actually this function is just going to recyclebits of code we've already writtenand it's a good opportunity for you to get some morepractice with Firebase.So the challenge is this, create a function calledrender conversation from DB, which will renderany existing conversation in the database.Now this function should be called when the app loads.Now take all the time you need to do this.There are a few things to think aboutand if you need any extra help, I've created a file up herecalled hint.md and it's got some tips in therethat will really help you.Now if you don't want any help, pause now and get started.I'm going to open hint.md so those watching on YouTubecan pause it and read it.Okay, good luck with the challenge and when you're ready,I'll show you my way.Okay, hopefully you managed to do that just fine.So let's come down here and set up this function.Now the first thing that we need this function to dois to get the conversation from the database.So we'll use the get method and we'll pass inthe reference to the database.We'll chain on then and we know the callback function herewill be an async function and it will have the snapshotas a parameter.Inside the body of this function, let's use an ifto make sure the snapshot existsbecause if there is no snapshot,if there's nothing in the database,this function need not do anything.And now we want to get that snapshot as an array of objectsand we can do that by saying object.valuesand we'll pass in snapshot and we'll need the val method.Now we can iterate over that array using a for eachand we'll represent each item in the databasewith database object, which I'll shorten to dbobj.Now for each database object,we want to create a new speech bubbleand we can do that with document.createElementand we'll create a div.Now we'll need to add some classes to that divand that goes with every speech bubble is just speech.Now the second CSS class is dependent on whether it's a humanor the AI that's speaking.So I'm going to open up the back ticksand both classes start with speech dashand now I'll use dollar sign and curly bracesand in here we're going to use a ternary.So I'm going to say database object.roleand I'm going to ask if that is triple equals to user.If it is, this CSS class should be speech dash human.And if it's not, it should be speech dash AI.Okay, now we need to append that speech bubbleto chatbot conversation,which we took control of right up here on line 23and apologies in hint.md.I think I said it was line 22, but I'm sure you found it.So let's say chatbot conversation dot append childand the element we want to append is new speech bubble.And lastly, we need to add the text to the speech bubble.Now I did say in hint.md, make sure that a malicious usercan't use this to input JavaScript.So hopefully you didn't use inner HTML to do this.Text content is secure because anything which is inputtedis just going to be passed as text.It cannot be passed as HTML with script tagsand with executable JavaScript inside them.Lastly, we just want to move the conversation downso the latest message is always in viewand we've done that several times in the app with scroll topand we're setting chatbot conversation dot scroll topequal to chatbot conversation dot scroll height.Now to check it's working, all we need to do is call it.And if we call it right there,it should run every time the app loads.Let's hit save and see what happens.And there we are, our conversation is rendered.So everything that we've got in the database,we can see it all right here is now rendered automaticallyas soon as we load.And we can see that the ternary has been successfulbecause we've got different speech bubblesdepending on whether it's the AIor the human that has spoken.Okay, that's a really good job.The final task then is to wire up this start over button.Let's do that in the next screen.Okay, so at the moment when the page loads,the conversation as it exists in the databaserenders automatically.What we want to do now is wire up this start over buttonso we can clear the conversation.So I'm going to come in herejust above the last function we wrote,although it doesn't really matter where we write this code.And I'm going to say document dot get element by ID.And I want to take control of this button.So if we just check in the HTML quickly,we've got that button right hereand it's got clear dash BTN.Now I'll add an event listener to listen out for clicks.Now, when a click is detected,we've got a very easy way of clearing the database.And to do that, we use the remove method.Now, of course, before we can use the remove method,we need to import it.So let's add it to the list right here.And all we need to do with remove,and you can probably guess this by now,is pass it the database reference.Now that is going to clear the database,but obviously it's not going to update the HTML.So let's add one more lineand I'll say chatbotconversation dot innerHTML is equals two.And then we just need our hard coded messagethat goes right at the beginning of any conversation.And we can get that from the HTML.Here it is right here.So let's copy it and then we'll paste it herein inverted commas.And I'm just going to bring it all onto one line.And this is a safe use of innerHTMLbecause this is hard coded HTML.The user has no way to access thator update it in any way.Okay, let's give it a try.So I'm going to come over hereand I'll just click the start over button and look,everything disappears.We're back to our single hard coded message.Now let's check the database.I've just taken a screenshot of it.So that is how it looked before and now it's empty.So this is working.And if I come in here and I'll actually ask the chatbot,is this a new conversation?And it says yes.I'm going to ask it a couple of questions.Now let's refresh.The conversation is there.It seems to be working.Let's ask it if I've already asked it some questions.And it replies yes.What did I ask you?New convo, how are you questions?Well, yeah, that's a fair summary.I did ask it, is this a new conversation and how are you?And remember, it's giving us very short answersbecause we did leave the instruction right up hereas you're an assistant that gives very short answers.Maybe let's just change that back to,you are a helpful assistant.What have I asked you today?And there we are, it knows everything.I'm going to click start over to clear the conversation.I'll try again, what have I asked you today?And look, it's telling us that it cannot recallany past interactions with us from separate sessions.And that proves that this is working.The start over button is doing exactly what we want it to.Okay, so that is a really good job.Congratulations on getting to the end of this project.Let's just take one last grim to recap what we've doneand talk about where we go from here.Congratulations on finishing the know-it-all chatbot app.Now you have got the foundations you needto build any human language capable chatbot that you want.Let's just recap what we've studied.We have used the GPT-4 modeland the create chat completions endpoint.We've given our chatbot a personalityvia the instruction object.We've seen how we can use the presence penalty settingto encourage the chatbot to talk about new topics.And we've used frequency penaltyto control how repetitive the chatbot iswhen it selects words and phrases to use.We saved our conversation as a single source of truthin a database so the conversation can be persistedand the user can come back to itand pick it up at a later date.Now it's always a good ideato really make a project your own.So why don't you give the bot a specific function?So you could tweak the AIso that it has a specific purpose.This tech doesn't have to be a general purpose chatbot.It could be a coding expert, a poetry generator,an academic assistant.You could use the instruction objectto train it to provide textin the specific style and format you needfor writing reports at work, for example.The only limit is your imagination.And once you've done that,you could change the style and themeso it matches the chatbot's new purpose.And of course, it's always a good ideato build again from scratch.And if you don't need practicewith the HTML, CSS, and JavaScript,you could just rebuild the API specific partsto really get that syntax to stick in your brain.It would also be good to add some error handling.We haven't really looked at error handling in this course.We're focusing very much on the AI.But whenever you're working with APIs,error handling is more than a good idea.It's essential reallyif you're taking anything to production.So do do a bit of research on that.But whatever you do, remember to take a break.Take a bit of time to consolidate what you've learnedbefore moving on to the next project.Okay, so we are going to enterthe fantastic world of fine tuning.And I've put here making AI models work for us.So what exactly do I mean by that?Well, in earlier projects,we have used two types of prompt.We've used the zero shotwhere we just give an instruction or ask a question.We've also used the few shot approachwhere we give an instructionand we use examples to demonstrate what we're looking for.Now those work fine for our purposes,but they have two big drawbacks.Firstly, prompts have size limits.We're limited in how much we can include in a prompt.Secondly, larger prompts use more tokens,so will be expensive when scaled.But there's actually a bigger problem than that.OpenAI's models have been trained on textopenly available on the internet.Now that's great for when you want to use themfor creativity, general Q&A,like we've been doing with our chatbot,translation and many other general tasks as well.But what it's not good for is answering questionsthat are specific to your circumstances.So consider this, you have a companyand that company has specific policies and systems.So you have your own opening hours,you might have shipping fees, a returns policy,of course you'll have contact detailsand many other things besides.Now imagine you ask a chatbot like the one we just made,a specific question about your company.What are you going to get back?Well, you're going to get hallucinations.And what are hallucinations?Well, if the AI doesn't know the answer,it gives you a linguistically plausible incorrect answer.So it basically goes into the world of fantasy.Now, although they're improving,AI models are not that good at saying, I don't know.Remember, what these models do is predict the likelihoodof a token or language chunk coming next.And this is one of the biggest problems with AIwhen working with facts.So if I ask what my company's opening hours are,it will likely say something like 9 a.m. to 5 p.m.and close on Sundays,just because that is a plausible answer.Now, fine tuning can help with this problem.By uploading your own dataset,you can give the model the information it needsto answer questions specific to your situation.So let's go.And we're going to start by thinking abouthow we can convert our chatbot,which we still have all of the code for right here,into a finely tuned support bot for my new company.So let's check that out next.Okay, so for this fine-tuned chatbot,we're going to use a lot of the same HTML and CSSas the previous project.But before we get to work on the AI,let's just make some quick changes to the designso it better fits our purpose.Up here, I've got the new We Wing It logo,which is just drone-logo.So let's just swap that out right here.And because that logo is slightly smaller,we need to just make a quick change to the CSS.Right here on line 54,the logo has got a width of 45 pixels.I'm going to change that to a width of 50 pixels.Okay, that's looking better.Now back in index.html, we need to change the nameto We Wing It drones.And the sub-header will now be delivery support chat.And to give us a little bit of extra room in the header,I'm just going to bring this down to ID.And let's just update that.It doesn't do anything, it's just for aesthetics.Now I'm also going to change this one hard-coded message.So now it's going to say,how can I help you with your We Wing It drone delivery?And lastly, we should come up here and change the title,even though it doesn't make any differencein the mini browser.Okay, let's save that.And there we are, everything is looking fine.Now the rest of the CSS and HTML is going to stay the same,but under the hood, we're going to completely changethe way we use open AI.So this is We Wing It,an accident-prone drone delivery companywith some very unhappy customers.Now We Wing It needs a way to communicatewith their customers quickly and easily,so they want an AI support bot.Let's just check what exactly we're trying to achieve here.We want a chat bot with the ability to answer questionsspecific to our company.If the chat bot doesn't know the answer,rather than hallucinate,it should advise the user to email or phone.Okay, let's crack on.Now we know what we're doing and why we're doing it.Let's take a high-level overview of the AI processto get an idea of how we're going to do it.So how do we get this highly tuned chat bot off the ground?Let's have a quick look at the whole process.Firstly, we need data.This is just like the examples we usedin the few-shot prompts,but it's going to be much longer and specifically formatted.So we'll be using the CSV formator the comma-separated values format.It also works in JSON format,but basically at this point,we need to make sure the chat bothas got all of the information it needsto do its job properly.Now secondly, as the fine-tune processtakes a long time to run, we don't want errors.So let's use OpenAI's data preparation toolto process our data so the format is correctand it won't get rejected.Now this is a CLI or command line interface tool,and if you haven't used the command line before,don't worry, we'll go through it step by step.The third thing we need to do is actually upload our datato OpenAI and tell it to make our fine-tuned model.Again, we do this with a CLI tool.It's very quick to get it going,but it can take a long, long timefor the request to be processed.Now when that process ends,we will have our own special endpoint,which we can then use with our chat bot.But at that point, we'll need to think about the changeswe need to make to our existing code,because to use the new model,we'll have to make some adjustments.All of the code we've got at the momentis very specific to the GPT-4 model we've been using.We'll have to change things up a little bit here.Okay, so that's how it works.Let's make a start on the data.Okay, so we need some data to fine-tune our model,so let's deal with that next.And the first question is,how much data do you need to fine-tune a model?Well, the advice from OpenAI is you should provideat least a few hundred high-quality examplesideally vetted by human experts.And what's more, OpenAI saysincreasing the number of examplesis usually the best and most reliable wayof improving performance.So if you were setting this up in the real world,you would basically grab all of your company'ssupport tickets and customer service emailsand anything else relevant that you can lay your hands on.And then as OpenAI recommends,you would have a human check it for accuracy and relevance.Now for the app we're building today,we're going to use a relatively small amount of data,but the principle is exactly the same.That is what I want to show you,the principle of how to fine-tune data.Now how we format that data is really important.OpenAI wants the data to be in JSON-L formatand the docs give us an example.Now JSON-L is data formatted with JSON on each line.Each line has to be valid JSON in its own rightand each line must end with a new line character.Now, if you haven't used JSON-L before, don't worry.We won't be writing it ourselves.We'll be using a special tool to create it.So we'll actually be working with much simpler CSVor comma separated values dataand we'll let OpenAI's tool do the heavy lifting.Now as well as wanting JSON-L format,OpenAI gives us some further criteriafor the format of our data.It wants each prompt to end with a separatorto show where the prompt ends and the completion begins.It wants each completion to start with a white spaceand it wants each completion to end with a stop sequenceto inform the model where the completion ends.Now the stop sequence is somethingthat we haven't needed yet, but we will talk about itwhen we get to that point in the projectand everything will become clear.To be honest, all of this sounds like a bit of a painand actually in their example data,they didn't even show us exactly what they wantedwith the stop sequences and the separator.So we don't even have that to help us.But good news is right here.You can use our CLI data preparation toolto easily convert your data into this format.So we're going to let that tool do everything for us.So don't worry at all if that looks intimidating.Okay, in the next grim,let's take a look at the data we'll be using.Okay, let's take a look at the data we're going to use.Now writing JSON out by hand is a pain.So I've organized this in a spreadsheetusing comma separated values or CSV.All we've got here is two columns,prompt and completion.Each prompt is a question from a customerand each completion is an answer from customer service.So we've just got two columns.I think we can work with that.And I've got 38 pairs of prompts and completions.Ideally, I would have 10 times that number or even more.But this small dataset is going to allow usto see the principle of how fine tuning works.Now I've also pasted the CSV data into this file right here.And it doesn't look like it's formatted,but actually CSV formatting is really simple.We've got the two column headings right here.And then each line contains one prompt completion pair.So this is the prompt right hereand this is the completion after the comma.Now I just want to draw your attentionto the last few pairs because here I've done somethingwhich is just a little bit more complex.It's a little bit tricky to see.So I'm just going to take this last prompt completion pairand space it out a little bit.Now, instead of just having one question and one answer,the prompt actually consists of several parts.The first part is a summary.Then we've actually got a short conversation.So we've got something that the customer has askedand then we've got the agent's reply.And then the customer has responded to the agent.And then we finish with the agent and a spaceand then we get the completion at the very end.So basically all of that is the promptand that is the completion.Now I've done that just to show youthat these prompts don't have to just be one questionand one answer.They can actually involve lots and lots of dialogue.So if you have got a lot of customer service data,you can format it in this way with the completionjust being the final answer to the queryand that is going to really help train your chatbot.Now you don't need to stick to one data style.As long as you're working with prompts and completions,you can mix as I've done here,some of the prompts will be one questionand some of the prompts will actually be whole conversations.Okay, let me just put this data back as it was.Now, as we're going to be working with this datain the terminal, you need to download itor have some data of your own in a similar format.You can download it just by clicking on this slideand that's going to take you throughto a Google Sheets versionwhich you can save a local copy ofor you can come down here to this cog iconand when you click on that, it will bring up a menuand click download a zip which will give you a zipped folderand when you unzip it,you'll see all of the files from this project.The one you're interested in of courseis the We Wing It Data CSV.So I'm going to take that fileand save it in my apps folder in a file called We Wing Itand there we are.There is my data ready for the next step.Okay, we've got some work to do with this databefore we can actually upload it and fine tune a model.We are going to use OpenAI's data preparation toolto do that for us but before we can do that,we need to set up our command line interface environment.So next, let's open up the terminal and tackle that.For the next part of the project,we're going to be using the terminal or command prompt.If you're new to using the terminal,it can look pretty intimidating.It's actually not that bad and to help you along,I've created a file over here called terminal-commands.mdand I've pasted in all of the commands we're usingin this scrim so you can refer to that quicklyand easily if you need to.Now to open the command prompt in Windows,you can use the Windows key plus Sand enter CMD in the search field.On MacBook, it should be right there in the launcherand of course in either case,you could use the terminal in VS Code.Now I've got the terminal open and the OpenAI toolthat we're going to use requires Python 3.Now if you've already got Python 3 installed,then you're good to go.If you've never used Python beforeand you're starting to freak out,don't worry, we're not coding in Python.It's just needed in the background to run OpenAI's tools.Now you can check to see if you've got Python 3 installedwith this command.So it's just Python 3 dash dash versionand when I hit enter,it tells me that I've got Python 3.11.1.Now if you haven't got Python installed,you can click on this slideand that is going to take you to the official Python siteor if you're on Mac, you can use Homebrewor if you're on Linux, you can probably get Pythonfrom your distros repository.Check their docs for details.Now in a moment,we're also going to need the pip package manager.If you have Python installed,you probably already have pipand you can check by doing pip dash dash versionand that tells me that I have got pip installed.If for some reason you haven't got pip installed,this command right here, python3 dash m,ensure pip dash dash upgradewill install the latest version.Okay, now we should be good to go.So let's install the openAI CLI using pip installdash dash upgrade openAI.That should install the openAI tooland you can check that by running the openAI commandand that should give you a list of commandsthat are specific to this openAI tool.Now there's one more thing I want to do.The fine tune model we createis going to be specific to us, only we can use it.So the openAI tool will need our API key.We don't need that to prepare the data,but we will need it before we upload.So we might as well do it right now.You can add the openAI key with this command.It's basically export and then everything that we've gotin this mth.js file in this line of code right here.But be sure to swap out this colon for an equals.Now when you've done that, press enterand you're not going to get any special acknowledgementthat your key's been accepted.Just assume it has been.And now with all of that setup complete,we're ready to work with the data separation tool.So let's get stuck into that next.Okay, so we've got the openAI CLI up and runningand we've given it our API key.Now let's use it to prepare our data.And again, I've listed the CLI commandsthat I'm going to use in this file right here.So our first task is to cd to the folderwhere we've stored our data.Now I've saved my data in a folder called we-wingitin apps, which is in documents.So let's head back to the terminaland I'm going to say cd documents slash apps slash we-wingit.CD here stands for change directory.And of course you'll need to navigate to wherever it isyou saved your data file.Okay, having navigated to the correct folder,we can start our fine-tune preparation.So we do that with this command.And what we're doing here is telling the terminalto use the openAI fine-tunes tool to prepare our data.Now this F flag is going to identify the file of datathat we want to prepare.Now my data was called we-wingit-data.csv.So what I need to do is just put thatright there on the end.Now at this point, you might run into a problem.The first few times I did this, it worked fine.And then suddenly at this point,I started to hit an error.Well, that's the nature of working with new technology.Things can change.And the error I got was this, missing pandas.Well, if openAI wants pandas, openAI gets pandas.So what you need to do then is say pip install openAI pandas.Once you've done that, hit enter, let it do its thing.And then we can try the data preparation task once again.So this is the exact same command.This time it works and it gives us some information.It knows our file is formatted as a CSV file.It also complains about the numberof prompt completion pairs we're using and says,in general, we recommend having at least a few hundredexamples.Well, we know that already,but this is for demonstration purposes.So it's absolutely fine.Now I'm going to save you reading the rest of this text herebecause actually it's telling us something we already know.We talked about the format of our dataand all of the features that we need.And we know that we need a separator to inform the modelwhen the prompt ends and the completion begins.We know that each completion needs to startwith a single white space.And we know that each completion should endwith a stop sequence to inform the modelwhen the completion has ended.But this tool is great because it's basically goingto do everything for us.So down at the bottom, it's already told usthat it's necessary to convert this to JSON L.That's absolutely fine.It's recommending us to add a suffix separatorto all of our prompts.Well, let's say yes to that.Now it's recommending adding a suffix endingof a new line character to all of the completions.Let's say yes to that and press enter.And now it's recommending us to add a white space characterto the beginning of all of the completions.Again, let's say yes.Now we just need to confirm that we're ready to proceedand it goes through its processand it tells us that it has created this file for us.And it invites us to take a look,which is a really good idea.If you go back to your folder,wherever you stored your data,you should see this prepared JSON L file waiting for you.Now, just so we can see this data,I'm going to copy it into a file in the editor.And there we are.And you can see that it's added the prompt keyand completion key to each pair.It's added white space before the start of every completion.It's added a new line characterat the end of every completion.And of course it's added a separatorat the end of every prompt.And we could have done all of that by handand just used the tool to check,but wow, what a lot of boring work that would have been.Okay, next we need to fine tune our data.So let's come on to that in the next scrim.Okay, let's get to work on the fine tune.At the end of the data preparation process,we got this instruction.So let's just break down what that is telling us to do.Firstly, we're using the open AI CLI toolto access the API.Then we need to use this fine tunes dot create command.And we use the T flag here to introduce our training data.And we save that in a file called we dash wing it dash dataunderscore prepared dot JSON L.Our training data, which has been preparedinto the JSON L format.Now we need to add just a little bit more to the end.The docs tell us that we can use an M flagto specify the base model to use.And we're going to use the DaVinci model.If we leave that blank,it will actually default to the older query model.Okay, let's put that command in the terminal.And when I press enter, we get this message.Now open AI needs to enqueue this and it takes some time.The quickest for me has been a few minutes.The longest was literally all night.Now down here, it says stream interrupted,client disconnected.That is really common.It doesn't mean that the fine tune process has stopped.It just means that open AIis no longer giving us live updates.And what we can do is take this command here,paste it and run it.And that will reconnect us to the information stream.And eventually we'll get this message with an emojithat tells us we have been successful.And then what we see down hereis actually our very own fine tuned model.It's everything from DaVinci right up until the date.Now that's pretty cool,but before we can use that model in our app,we need to make some changes to our JavaScript.So let's go ahead and do that next.Okay, so to use this model,we need to update our existing code.The first thing to remember hereis that we have fine tuned a DaVinci base model.And at the time of recording,you can't fine tune GPT-4.That means that we need to get rid ofloads of this specific format.Now I've divided this process into several partsand we'll have challenges for them over several scrims.The first task is to change this array,which is holding the conversation.DaVinci models just need a string holding the conversationand we won't be using an instruction.Here are two mini challenges to do just that.Firstly, change conversation array to conversation string.And you can initialize it to an empty string.Now I've just put a warning here.Think about how this is going to work.Is there any other change you need to make?I'm just going to let you think about that.Once you've done that,you can come down here and update conversation stringwith just the user's input.So instead of pushing this whole object,all we actually want to pushis whatever the user has inputted.Then you can just log out conversation stringto check it's working.And I've disabled the fetch reply functionas at the moment, we just get an errorif we sent off the string instead of the array of objectsto the current endpoint that we've got in our coderight here.Okay, pause now, take all the time you needand I'll see you back here in just a moment.Okay, hopefully you managed to do that just fine.So let's just delete everything we've got here.We're going to make this conversation string.I'm just using the abbreviation STRand we'll initialize that to an empty string.Next, we need to come down hereand update conversation string with just the user's input.So again, we need to convert conversation arrayto conversation string.And instead of push, we can just use plus equals.And let's log out conversation string and hit save.Okay, I'll just type something in the boxand look, we get an errorand it's a type error assignment to constant variable.Well, I did warn you here,think about how this is going to work.Is there any other change you need to make?Well, yes, we need to change this const for a let.Let's try again.And there we are, it is working.So that is two of the jobs off the list.Let's move on to what happensinside the fetch reply function.Next up, we need to change the end point.Create chat completion is specific to models like GPT-4.We are going back to the completions endpointwhich uses create completion.So I'm just going to come in here and delete chat.Now for your challenge,I want you to swap out the model GPT-4for your fine tuned model.And you can get the model namefrom right at the end of the fine tune process.Now, if you've closed your terminal window, don't worry,log into open AI, go to the playground,come up here to where we've got modeland just click this down arrow.That will bring up a list of all the regular modelsand also all of the fine tune models that you have created.Now for the second part of the challenge,our fine tune model needs a propertycalled prompt not messages.So you just need to swap out messages for prompt.And you also need to update this referenceto conversation array.Conversation array does not exist anymore.Once you've done that,you can run a test by logging out the response.Now, before you do the challenge,I'm just going to uncomment this fetch reply function call.And I have already commented out these two lines of code.When we've got the endpoint working properly,we'll uncomment them and make some adjustments.Okay, pause now, get this challenge sortedand I'll see you back here in just a moment.Okay, hopefully you managed to do that just fine.So I'm going to come down hereand I'm going to just grab the name of my fine tune modeland I've got it right here.And I just need to paste it right here.Next, this messages property needs to become promptand conversation array needs to become conversation string.Okay, let's log out the response and see what we get.And I'm just going to hit saveand ask a random question in here.Let's open up the console and see what we get.And there we are, we've got a response.And the response is a little bit strange.I'm just going to copy it into the editorso you can see it clearly.The response to my question, how are you today?Was bizarrely this, it sounds like you've beenon a real roller coaster, I'm sorry.Well, that's okay.We've still got quite a long way to gobefore we get this fine tune chatbot working.So it doesn't matter at allthat it's giving us quite a random answer.The important thing is we're managing to make an API callto this new model and we're getting a response.So in the next grim, let's get to workon these two lines of code right here.We need to make a few more changes to the JavaScriptbefore we can do some testing.So at the moment in these two commented lines of code,we are pushing to the old conversation arrayand we're also sending our completionto render typewriter text.Those two lines of code are not going to work anymore.We need to make some changes.So firstly, let's uncomment this line of codeand we'll change this to conversation string.And instead of using push, we will of course use plus equals.And what is it that we needto update conversation string with?Well, I've just pasted in the response that we got up hereand it's pretty similar to the responses we were gettingwhen we were using the chat GPT models.Now, if we look down here, this one ends with messages.Messages doesn't exist.We've got choices,but the completion is actually stored in text.So let's just change message for text.And of course we don't need these brackets.And now that we're updating conversation string,just with the completion,we can actually reuse this code herebecause we also need to send the completionto render typewriter text.So let's just paste that in here and now it should work.So I'm just going to delete a couple of console.logsand let's delete all of this ugly code as welland give it a test.And okay, it's working.And it said, I've got some lovely thingsfor sale in my shop.I hope you like.Now the reason why it's finished on like with no punctuationis because now we're using a DaVinci model again,we need to set max tokensat the moment it is set to 16 by default.Let's set it to something much higher.And I'm just going to try that again.Wow, and now it's gone a little bit crazy.All I said was, hey there.And it's given us all of this stuff,which is sort of related to the data we uploaded.It certainly got the email address right.And it's given us some rather random phone numbers,although this one is not too far awayfrom the one we told it about.And then it starts going on about using cookieson the website.Well, this is more than just hallucination.It's actually gone a bit crazy.And what's worse is that it still didn't finishon a complete sentence.So if we whacked max tokens up to something much higher,like a thousand, I've got a feelingthat this crazy chatbot would go on and on.But hey-ho, at least it's working.The basic mechanics are fine.So in the next grim,let's start figuring out what's going wrong.So we have the fine-tune chatbot working or sort of,because actually it's giving us nonsensical gibberish.So let's just check the settings we have.The presence penalty and frequency penaltyaren't doing anything very much.They're almost at their default.So I'm not too worried about them.Now with open AI, when the completions are a bit weird,the first thing we might think of is temperature.Remember, temperature controls how daring the model will be.How creative, how inventive.Now we don't want creative, we want factual.So let's put the temperature down to zero.And let's see if that has had any effect.Okay, that completion is like something from a horror movie.Now the chatbot is claiming to be a human.It's begging us not to kill it.And it's just saying, please, please, please.And then creating a word so long it actually breaks our CSS.So I'm just going to refresh to get rid of that,because it's just a bit scary.Okay, so the temperature hasn't magically solved the problem,but I think a low temperature will be useful.So I'm going to leave it there.Now, before we do anything else,let's go back to the criteria for the format of our data.The first one that we had says,each prompt ends with a separator to inform the modelwhen the prompt ends and the completion begins.And actually when we were prepping the data,it told us that it would use this arrow as the separator.So what we need to do is add the separatorto the end of our prompt.And I've got the JSONL file right here.And we can see that each prompt does indeed endwith a space and an arrow separator.Now we're not adding those separatorsto our conversation string.And I think that might be causing part of the problem.So in fact, I'm just going to log outconversation string right here.And let's be brave and just see if the chatbotis going to scare us again.And it's done the same creepy thing again.Now let's just have a quick look down in the console.And what we can see there,if I just cut and paste it into the editor,is that we're just getting one continuous line of text.So hey, and I'm not a robot,look like they're being said by the same speaker.But in fact, that was our prompt.And this is the beginning of the completion.So we have got problems there.And that brings us to a challenge.And your challenge is this.I want you to add the arrow separatorto the end of our promptas it is added to conversation string.And I've put here a space before the arrow separatorbecause that is how it's formatted in our JSON-L data.Okay, I'm going to leave the console.log that I just added.So when you're done with this,you can just type something into the chatbotand give it a test.Pause now, get that sorted,and I'll see you back here in just a minute.Okay, hopefully you managed to do that just fine.So I want to come down here and put this in backticks.And now we'll use the dollar sign and the curly bracesso we can access the user input.value.I'm going to start with a spaceand I'm going to end with a space and an arrow separator.Okay, let's give that a try.Okay, so we've seen an improvement there.This is by no means perfect,but at least it's working a little bit.Now it feels like we're talking to a representativeof the We Wing It company.It's got the email address.It's still giving us a load of hallucination and weirdness.And if we look down in the console,we have at least got our separator between hey,which was our prompt, and odia,which was the beginning of the completion.So we've made some small progress here.But what else could be going wrong?Let's just go back to our data formatting criteria.So we've sorted the first one.Secondly, it says each completionshould start with a single white space.Well, if we have a look down in the console,that appears to be true.Or is it?I think the next thing that we should dois come down here to fetch replyand where we're updating conversation string,with the completion, we should explicitly adda white space at the beginning.So again, I'm going to put this in back ticks,use the dollar sign and curly bracesto access the completion from the response.And now I'll add my white space at the beginning.Okay, let's hit save and try that one more time.And that's not really made any improvement.I think that's just as crazy as it was before.But we have now got that white space there for sure.We know it's there.We've ruled that out as a potential cause of problems.So let's go back to the data criteriaand look at the third one.Each completion should end with a stop sequenceto inform the model when the completion ends.Well, we're back with the mysterious stop sequence.We keep coming across itand we've never really looked at it in detail.So why don't we deal with that next?Let's take a look at the stop sequence,a way of stopping the model from generating tokens.So what exactly is it and how does it work?Well, it's an optional setting that tells the APIto stop generating tokens at a given point.The completion will never contain the stop sequenceand the stop sequence is an array.And that's because we can have multiple stopsin a stop sequence.Now all of that is quite theoretical.So let's just jump straight into an exampleand you'll see what I mean.Right here, I've got a basic API request set upusing the text DaVinci 003 model.And I'm just asking it to list some great booksto read on the topic of coding.So I will uncomment this function call and hit saveand let's open up the console and see what we get.And there we are, we get 10 good book recommendations.Now I'm going to come in here underneath the max tokensand I'm going to add a stop sequenceand the property that we want is just stop.The stop sequence is an arrayand each individual stop will be a string.Now we can have up to four stops in this array.I'm only going to use one.And if we look at the formatting of what's in the console,each list item starts with a number and a dot.So it's one dot,code the hidden language of computer hardware and softwareby Charles Petzold,two dot, Python crash course by Eric Maths.So the stop that I put in here just to experiment withis going to be two dots.Let's see what happens when I press save.We get a list with only one item.So what happened here?Well, if you'll remember,the completion will not contain the stop sequence.So the model was prevented from writing two dots.And because it won't write a stop sequence,at that point, the completion is cut off.So if we wanted a list of five books,we could change this to six dot.And there we are, we have got a list of five books.Now you can use anything as a stop.You can put whatever characters in thereyou might find in your completion,but you just need to know what you're doing with it.Obviously, if you put something like the letter A,well, that's going to cause all sorts of problems.There we are.The completion has actually been cut offon the fourth letter of the book title,which was obviously an A.Now, when we're working with chat bots,it's very common to use the new line valueas a stop sequence.Why?Because often you want the bot to give youone paragraph as an answer,and then you want the user to respond.If you don't use a stop sequence with a chat bot,you run the risk of the chat bot answeringand asking questions and having a conversation with itselfthat becomes ever more bizarre and illogicaluntil it hits the token limit and that stops it.Now with the general purpose chat bot we built with GPT-4,we didn't need to add a stop propertybecause GPT-4 has actually got that specific syntax,the object with the role and the content properties.DaVinci and other models don't have that,so we can use the new line character as a stopto stop the bot from continuing the conversation on its own.Okay, let's go back to the app and add a stop property.Okay, so if we refer back to our slide,we can see that each completion should endwith a stop sequence to inform the modelwhen the completion ends.And when we were preparing our data,we actually selected this optionto add a suffix ending of a new line character,which is backslash N.So as we add completions to our conversation,we need to include this new line character at the endas a stop sequence.Now we're also using this arrow as a separator,and when experimenting with this,I sometimes found arrows popping up in completionsand some cases where the chat bot seemedto just get into a conversation with itself,asking itself questions and giving itself answers.So we're actually going to add the arrowas a stop sequence as well,because we never want the model to generate an arrow.Okay, so here is your challenge and it comes in two parts.Firstly, I want you to add the new line character,which is backslash N and the separator as a stop sequence.And actually, you don't need to have a spacein the stop sequence.Secondly, I've said here,I want you to add something to the line belowwhere we update conversation string.So that is this line of code right here.I'm going to leave you to think about that.What would it be good to add to that line?Okay, pause now, get that challenge sorted,and I'll see you back here in just a moment.Okay, so hopefully you managed to do that just fine.So let's come in here and we'll add our stop.And we know that that will be an arrayand it will be an array of strings.So the first string is going to be the new line character,and the second string will be the arrow separator.And of course, it doesn't matter what order they go in.Now, the second challenge,add something to the line belowwhere we update conversation string.Well, if we refer back to this slide,we're going to add a suffix ending of backslash Nto all completions.So this is the completion that we're getting back.Let's just add a new line character to the end of that.And what that is going to dois make it really clear to the modelwhen it reads conversation stringthat it has reached the end of a completionbecause that is what the new line character will tell it.And likewise, the arrow separatorthat we're adding to the stop sequence here,which we're already adding to conversation stringright here in the event listeners anonymous function,that will tell the modelthat it's reached the end of a prompt.Okay, let's hit save and see if it's worked.So I'll start again just by saying, hey.All right, and I'm still gettinga pretty strange response here.Now I'm going to ask a question from our data.And if we have a quick look at the data,we can see that the customer support teamhas a phone number.So I'm going to ask it, what is your phone number?Okay, and look,we're getting a much better quality response.It knows the phone number.It is still hallucinating.We're only here from nine to six 30 weekdays.That is not actually true,but the answer is much shorterand it's much more manageable.Now I'm going to ask it a questionit can't know the answer tobecause it simply isn't in the data.I'll ask it, who is your CEO?Okay, interesting.It completely makes up a person, Richard Quing.So for some reason, the large language modelhas decided that Richard Quingis the most probable name for a CEO of our company.And it's also made up an email address for himbut using atwewingit.com.So again, it's a hallucination,but it's an interesting one.So I think where we are at the momentis that this chatbot works,it can see its data,it's giving us short manageable answers,which makes sense,but we're still getting too many hallucinationsit is not accurate.Now we are going to get hallucinationsbecause as I said at the beginning,we're not really using enough data.We've got enough data to show the principle,but not enough data for a full production ready app.But that said, there is one last really important aspectof fine tuning that I want to tell you aboutand it is an epochs.What does that mean?Well, when we were building the model,you might have noticed that as the model was fine tuning,it completed various epochs.And in this case, it completed four epochs.Well, maybe four epochs just wasn't enough.So in the next grim,let's talk about what epochs are,how we can get more of themand how that is going to help us.So let's check that out next.Let's talk about an epochsand I've put here the number of data cycles.So what exactly are an epochs?Well, the N stands for number.So it's the number of epochs.And what that basically means is that it controlsthe number of times open AI will cyclethrough the training dataset when fine tuning the model.Now it defaults to fourand that is likely fine for larger datasetswith hundreds or thousands of prompt completion pairs.But for smaller datasets, it isn't enough.The disadvantage of using higher numbersand therefore more cycles through the training datais that it costs more to do the fine tunewith a small dataset like ours,it's still going to be pretty cheap.The other thing to think about is thatif you're using a massive dataset,it will take a long time.Now an epochs is something we setwhen we send the training data to be fine tuned.We can't set it from within our app.So what we need to do is go back to the CLIand we're going to add thisto the end of the fine tuning command.It's just dash dash N underscore epochsand then the number of epochs you want.And I'm going to go for 16.You don't have to go for 16,but I got much improved results using 16.You could go higher,but just remember it costs more each time.So that is the same command we used before.Here's the N epochs added on the end.And so the final command will look like this.It's everything we did beforeplus this N epochs on the end with the double dash.So here is a challenge for you.Use open AI CLI tool to build a new fine-tuned modelwith N epochs set to 16.You don't need to prepare the data again.That command is all you need.Once you've gone through that process,you will get a new model nameand you can slide it in right here,replacing the old model.Once you've done that,go ahead and test it by asking itabout weaving its phone number or emailor anything else from the data that we've got right here.Go ahead and do that.It won't take very long at all to set up.It might take quite a while for the APIto actually do the fine-tuning process.So make yourself a cup of teaand we'll have a look at this together when it's done.Okay, hopefully you got some good results with that.So I'm going to come over to the terminal.There is the command to create the fine tune.I'm going to add the N epoch 16 on the end and press enter.And then eventually having gone through its process,it's completed all of these epochs down to 16.And finally, I have got my new modeland here it is right here.So let's go ahead and swap the old model for the new model.Okay, let's hit save and do some testing.So I'm going to start off asking about the phone number.Okay, and that is a really nice answer.It's got the phone number correct and it's also said,we prefer it if you only phone us in an emergency.Now that's really interestingbecause if we look at the data,we mentioned the phone number several times.If we come down to line 19, well, we can see here,we've got the straightforward question,what is your phone number?And if I just move the mini browser out of the way,it does actually say,we prefer it if people only phone us in an emergencyand it gives exactly the same times as the chatbottold us right here.So the chatbot is successfully using our dataand that is really, really good.And it's also suggested they email us instead.Okay, now I want to ask it somethingit can't know the answer to, who is your CEO?In the previous scrim, it hallucinated an answer to this.So let's see what it does.Who is your CEO?And it says, I'm sorry,I don't know the names of the people working here.Now that's really interesting.I've made sure to include in this data,various I don't know statements.If we have a look right here on line 18, for example,what material are your drones made of?Completion, I don't know the answer to that question.Check out line 24, who is your press officer?I'm sorry, I don't know the names of members of staff.And again, on line 32, we have, are your drones recyclable?I'm really sorry,I don't know the answer to that question.Now traditionally, AI is not very good at saying,I don't know, it prefers to hallucinate.But we've effectively given it permission to do that.So do bear that in mind when working with chatbot data,it's good to teach it to say, I don't know,as this will help stop it hallucinating.Let's just ask a few more questions.So I'm going to say, how much is insurance?And it's telling me it's three pounds 75 per delivery.And if I come up onto line eight, well, there we are.It says it's a flat rate of three pounds 75 per drone order.So again, that is pretty good.Let's ask it something a little bit more random.I've said your drone crashed into my house.Okay, it says, please contact us by emailand we'll arrange to pay for any damage.I'm going to say, I want compensation.And there we are.It's giving a very logical rational answer.Now it's not being particularly humane.It's not being touchy feely.It's not being that conversational.And that, to be honest, is a shortcoming of our data.We just need much, much more data.And we need much more of this kind of datathat we've got at the bottom,where we've got these entire conversationsplaying out before we get to the completion,because that is the quality data.That's what really helps the chatbot communicate well.So although I think we've done very well here,you will find limitations with this chatbot quite quickly.You're going to come across idiosyncrasiesand hallucinations.But as I've said many times,if you wanted to take this to production,you would need a lot more data.But what we've done here has really proved the principle.It's working really well on a really small data set,so that is really good.And of course, your results might differ.Perhaps you're using your own data,or perhaps the model has simply been updated somewhatbetween the time that this was recordedand the time that you're actually building this app.And that is the nature of workingwith this new frontier in technology.Now the next thing that I want to do is take this appand deploy it live on the internetwith the API key safely hidden.That's quite a process.We've got quite a bit to do.So let's make a start next.Okay, so our mission is to deploy our support bot,but keep the API key hidden.And we're going to do this using Netlify.So right now, if we were just to deploy thisas a front-end only project,the API key would be visible right thereon every user's machine and easily obtainablefrom the DevTools network tab.Let's just zoom in.Oops, there it is.Our API key is there for all to see.And that is what we need to avoid.What we want is for you to be ableto share the projects you've made with OpenAIwithout fear of your key being compromised.And actually, the process we're about to go throughcan be used anytime you need to keep an API key hidden.It's not specific to OpenAI in any way.So how are we going to do this?Well, let's take a high-level overview.Now, at the moment, we've got a front-end project,and what we've been doing is storing the API keyon the front-end, making a request to the OpenAI API,and getting back a completion that we use on the front-end.But now, we're going to stop doing thatand do something completely different.We are going to send our requestto a Netlify serverless function.The serverless function will have access to the API keyfrom a secure store.The serverless function will then make the callto the OpenAI API.The API will pass the response backto the serverless function,and the serverless function will pass the responseback to the front-end,and we will use the completion from that response.But most importantly, this API key in its special storeis never visible to the front-end,so it won't be visible in the DevTools Network tab.Now, there are a few prerequisitesthat I'll just mention quickly.You are going to need a free Netlify account.That's really easy to get.I'm also going to assumeyou have a basic knowledge of GitHub,because we will be deploying to Netlify directly from GitHub.If you know how to publish a project to a GitHub repo,that is enough.We'll also be making fetch requests,and if you've followed this course so far,you won't have any problem with that.We won't really be doing anything more sophisticatedthan we've already done,and you'll also need VS Code or a similar editor.Okay, that's the overview.Let's put it into practice.So firstly, we need to get our project stored locally.So come down here and click on this cog icon,and that will bring up a menu.Click Download as Zip, and then unzip that folderand save it somewhere sensible.I've saved mine in this folder calledwewingit underscore deploy,and it's inside another folder called apps.Now, let's open that in VS Code.Now, before we forget,and to save us from running into an error later,I want to open up index.js and come onto line two.We won't be importing the API key like this anymore.So let's go ahead and delete that import statement.If you skip this step,when we deploy the project to Netlify,you will get an error and it will be a bit frustrating.So best to remember to do it now.Next, we need to open up the terminal,and I'll zoom in on it,and I'm going to run npm install,and this will download the dependenciesdefined in the package.json file,and it will generate a node modules folderwith the installed modules.The dependency that we've been using is the OpenAI API,and we still need it when we deploy to Netlify.Okay, we run that, we let it do its thing,and then we can see that the node modules folderhas appeared.The next step is to publish to GitHub.So you're welcome to do thisin whichever way you're comfortable with.I've got the GitHub and pull requests extension installed,so I will go with this icon right here,and I'm going to come down hereand click on publish to GitHub.I'm going to publish mine to a private repository.Now it's asking me here which files should be includedin the repository.Really important to ignore the m.js file,so I'll untick that.Now you could also delete it.It doesn't matter if you delete it or ignore it,just make sure you don't include it in your repo.If you choose to delete it,make sure you've got a copy of it somewhere handyas we will be using it again shortly.Okay, I'll click okay.I'll let VS Code do its thing,and then when the process is completed,we can see that we've got the gitignore fileand m.js is in that file.So that is exactly what we want.And of course at this point,you can log into GitHub and check it's workedif you want to be sure.Okay, so we've got the project stored in a repo.We've either ignored or deleted the API key.Next, we need to set up a Netlify account.Okay, next up, we need a Netlify account.It's really easy to do, click on this slide,and it's gonna take you through to the signup page,which looks like this.Now I'm going to sign up with GitHub,and then once it's done its thing,it will take me to the dashboard.And from here, I'm going to select add new site.I'll import an existing project,and it will invite me to connect to a git provider.I'll choose GitHub,and it's going to say no repositories found.And that's absolutely fine.Click configure Netlify on GitHub,and this will open a pop-up pageand you can scroll downand either select all repositoriesor select repositories individually.I'm going to do that one,and I'll choose the repository.I'll just type in we wing it underscore deploybecause that's the name of my repo,and click save.And we'll be taken to a settings page.And on here, we can leave everything as it isand just scroll down to the bottomand click on deploy site.As the site deploys,we will see site deploy in progress right hereand then eventually published.So now the site is live,we can click on open production deploy,and that is going to actually take us to our site.We've got our own funky Netlify URL right here,and let's see if it works.So we can just come down here,type in a question, press send,and we'll wait and nothing happens.Let's open up dev tools and we've got plenty of errors.Well, that isn't actually a problem.We've only done the first stageand actually it would be really weird if it worked.It doesn't have an API key right now.So our next step is to get our API key to Netlify,and we're going to store itin a Netlify environment variable.Let's come on to that next.What we need to do now is give Netlify the API key.Now, if you remember the function that we'll be usingto actually do the heavy lifting of making the API call,we'll have special access to our API key.So on the Netlify site, come over here to site settings,and we're going to click on environment variables,and we can click add a variable,and then I'm going to select add a single variable.That takes us to this page,and we need to add a key and a value.So let's take a look at our code right herebecause this is essentially the same information.This is going to be our key,and the actual API key will be the value.So back on this form then,we'll have open AI API key in here,and the actual API key stored here as the value.Then click create variable,and we can see that the open AI API key has been added.So what we've done here is we've stored our API keyin a Netlify environment variable.So now, if we scroll up and we launch our site,again, we can try asking a question,but we're going to have the same result.We'll still get errors.And that figures, Netlify has the API key,but we're not doing anything with it in the code.And anyway, at the moment,all we've got is our front-end code,and if it did work,the API key would still be visible in DevTools.The fact that we've stored it in an environment variabledoesn't mean you can't then display it on the front-end.You actually can.That is why we need the serverless functionto make the API call away from the front-end.Okay, so what we need to do next thenis work on the serverless function.But in order to set up a serverless function,we need to get hands-on with the terminal againand install Netlify's CLI or command line interface.So let's do that next.Okay, so to integrate a serverless function,we need the Netlify CLI.So let's come back to the terminal,and just to help out,I've created a document here called terminal-commands.md,and I've just listed the terminal commandsthat we'll be using in this scrim.So we're going to come in here with the first command,which is install netlify-cli-g.So I'm installing this globally.That's what the dash G means.So we can hit enter,and eventually you'll get shown something like this.Now, if we just type netlify and hit enter,we'll get taken to a list of Netlify commands.And the one that we're really interested inis init for initialize.And we're going to use that to configure our site.So down here, let's say netlify init.And now it's going to ask us a series of questions.The first one is connect this directoryto an existing Netlify site.Now we've got two options here,and we can just move up or down with the arrow keys.But the first option is the one we want,so I'll just press enter.Now it's asking us if we want to usethe current git remote origin,and it's correctly identifiedthe we wing it underscore deploy repository that I'm using.So that's fine, click enter.And there we are, it says directory linked.That is what we want to see.And if we go back to the full screen of VS code,we've now got a new.netlify folder.Okay, in the next grim, we'll use the CLIto give us the boilerplate for a serverless function.Okay, let's get to work on a serverless function.The Netlify CLI is going to give us some boilerplate.So in the terminal, let's say netlify functions colon create.We'll hit enter, and we're going to get some options.The first one is for an edge function.We don't want that, so we can use the arrow keyto come down to serverless function, press enter.And it's going to ask us a few questions.The language that we want is JavaScript, so hit enter.Now it's telling us to pick a template.And we've got some interesting options here,including this one or fetch, which talks about APIs.But because we've already got the open AI dependency,and we're not really dealing with authentication,I'm going to go with this basic hello world function,and we're going to adapt it from there.So let's hit enter.Now it's asking me for a name.The default is hello world.We definitely don't want that.I'm going to go for fetch AI,which I think is a reasonably descriptive name.And the function is instantly created.And now if we look at the whole of VS code,we've got a new folder here, netlify.Let's click into it.Here's our function, fetch AI.Let's click on that.And there we are.That is the boilerplate for our serverless function.And at the moment it's basically returning hello subject.Well, we can see from this line of code right herethat unless we put a query string parameter in,the subject will be world.So this should return hello world.And if we open up a browserand we actually navigate to.netlify slash functionsslash the name of our function,and I have actually put that right herein this terminal commands MD file.And when we go to that URL, what we get is this message,hello world.So we're seeing the object returnedfrom that serverless function.And so this URL is now my endpoint.This is what I'm going to call from the front endinstead of calling the open AI API directly.So next we need to go back to the editorand make some changes to index.js.We want to make it so that instead of callingthe open AI API directly,we make a fetch request to this new endpoint.So let's do that next.Okay, so we need to completely changethis fetch reply function.So instead of calling the open AI API directlyfrom the front end,now we're going to call the netlify serverless function.Now I'm going to set you a challenge to update fetch replyright here in the Scrimba editor.But when we're done,we're going to need to paste this into VS codeand push it to GitHub to trigger a redeploy.First, we need a URL to call.And we've already seen the URL,we looked at it before,and I've got it right here in the URL bar.So I'm just going to come in hereand paste it in a const called URL.And now it's time for a challenge.And it is quite a long challenge.And this is where I'm assumingyou have some knowledge of fetch requests.But do take all of the time you needand feel free to search online if you need to.When I do this, I'm going to use async await,but you don't have to,you can use a fetch request and chain then statementsif you prefer to do it that way.Also, I'm just going to comment these two lines of code.When we've got this working in the console,we can uncomment these and update them as needed.But we'll do that after we've gotthe serverless function working properly.Okay, let's check out the challenge.So I want you to make a fetch request to the URLthat we've got saved here using the following details.The method should be POST.In the headers, the content type should be text slash plane.And the body should hold conversation string,which remember we have got stored right here.Now, once you've made the fetch request,you can save the response to a const and log it out.Then copy and paste the updated fetch reply functionto VS code and delete any unnecessary code from index.js.Push the changes to GitHub to trigger a redeploy.And remember that will take some seconds,maybe as long as a minute.And then navigate to your Netlify site,put something in the text input.It doesn't actually matter whatbecause it's not going to be renderedand it's not going to be sent to open AI.Hit send and then what you should seein the console is hello world.And that will show that from the front end,we're successfully managing to access the serverless functionand get whatever it returns.Okay, quite a lot to do.So pause now, take all of the time you needand we'll have a look together in just a moment.Okay, so hopefully you managed to do that just fine.So I'm going to come down hereand I'm going to set up a new const responseand I'm going to await a fetch request.The first thing a fetch request needs is a URL.Well, we've got that saved right here.And now we need to pass it an object.So we've got all of the details here.Firstly, the method should be postand then we need some headersand this will hold an objectand it's going to have a single key value pair.The key will be content typeand the value will be text slash plane.Lastly, it needs a bodyand the body will hold conversation string.Okay, then I'm going to come underneath thatand set up a const called dataand we will await the response JSON.And let's just log out data.Now we've got plenty of code here that we don't need.All of this code down here, we can safely deletebut I'm just going to comment it outbecause we will need to copy and paste it later.And likewise, right up at the top,all of this code that brings in open AI,we no longer need and I will comment it out.Then I'm going to copy the fetch reply functionand I'm going to bring it over to VS codeand I'm going to paste it in.And of course, I haven't copied over the codeI commented out apart from these two lineswhich we will be using here in the future.Now staying in VS code, up at the top,we've got these lines of code here, we can delete them.When you've done that, you can save,push it to GitHub and that will trigger a Netlify redeploy.And remember, that will take a few seconds,maybe even a couple of minutes.When it's done, navigate to our site, send a messageand then what you see in the consoleshould be the object with hello world.And that will show you that the front-end codehas successfully communicated with the serverless function.And that means we need to get to workon this serverless function, next. I've just pastedthis serverless function into the Scrimba editor.And again, when we're done, it will need to go backinto VS code so it can be pushed to GitHubto trigger a redeploy.Now, before we do anything else,let's delete all of the code we don't need.Okay, that is the bare bones of the serverless function.Now, what we've got at the endmight look a little bit unfamiliar.Don't worry about that.That is just exporting this handler functionto make it available to the rest of the app.And that syntax there is actually from Node.jsso it's not familiar to front-end developers.The next thing to do is bring in open AI.And remember, we used npm installto load in the dependencies we needso we have access to them across our project,including in this serverless function.Now, the code we need to do thatis code we're very familiar with.In fact, we just commented it out in index.js.So let's head over to index.js and let's uncomment that.Now, we will not be importing our API keyfrom this mf.js file.Remember, we've ignored that or deleted it.It's not available on Netlify.So let's delete that line of code.Now, the API key that we've got storedin the Netlify environment variableis available to us in this serverless function.And we can access it using process.envand then the name of the API key.So luckily, we don't need to change this line of code at allbecause this is going to fetch our API keyfrom the environment variable we set up earlier.So now we've bought in open AI,we need to actually use it down here inside the try block.So let's head back to index.jsand we'll take the second block of codethat we've got commented out right here.That is looking pretty good,but we need to do something with conversation string.We don't have access to conversation string in this fileand we can't just import it as this serverless functionwill not be part of the front end code.Remember, we're actually calling this serverless functionusing a fetch request.And we've got the fetch request right hereand conversation string is being sentin the body of the fetch request.Now back in fetch AI, we're taking in an event parameter.And from that event parameter,we can actually access the body.So I'm going to come down hereand replace conversation string with event.body.So now when the fetch request comes in,the conversation string will be in the body,fetch AI takes in the event parameterand accesses conversation string,which will be stored in the body of the event object.Okay, I think that's looking good.We can't test it yet,because first we need to deal withwhat we actually get back from the API.We've got this return down here,so we need to do something with that.Let's come onto it in the next screen.Now we need to deal with what the serverless functiongets back from the open AI API.Now that's no problem.We've worked with the API long enough by nowto know that what we get back is a response objectand that we need the data from it.So working down here, inside the return statement,and we've got the body, we're calling JSON.stringifyand then in here, I've pasted a challenge for you.I want you to add a key value pair.The key should be replyand the value should be response.data.Now, once you've done that, paste the codeinto fetchai.js in VS Codeand push it to GitHub to redeployand see what gets logged out when you test.Okay, pause now, get that sorted,and I'll see you back here in just a moment.Okay, so all I need to do is come in hereand add the key value pair.So the key is replyand the value is response.data.Okay, let's copy that and I'm going to paste itover here in VS Code and I've just formatted ita little bit more neatlyand obviously without the challenge text.Now, I'll go through the process.We've gone through several times.I'm going to push it all up to GitHuband wait for the redeploy.When the redeploy is complete,I'm going to navigate to the site.I'm just going to say, hey,and then what we see in the consoleis the data from the response objectand look what we've got here, a completion.Hi there, how can I help you?Okay, that is big progress.We have just got one more step to takewhere we take this completion and get it rendered.Let's do that next.Okay, so the last thing that we need to dois deal with these two lines of code.So let's go straight into a challenge.I want you to update the two commented lines of codeto get this working.Once you've done that,you can push to GitHub to redeploy and then test.Now, when this was purely a front-end project,we were taking our completion from the response.Now we've got the response stored in data.So it's just a question of working outwhere you get the completion from within the data object.Okay, pause now, get it sortedand we'll have a look together in just a moment.Okay, hopefully you got that working just fine.Now, these lines of code are almost correct,but now we have this data objectand what we want is stored in the reply.So I'm going to delete response.And let's go for data.reply.choicesand everything else can stay the same.Okay, let's copy that over to VS Codeand I'll just update these two lines right here.Then we'll push to GitHub to trigger a redeployand I'll ask the chatbot a question.We get back a completion, it's looking good, it's workingand best of all, when we open up the network tab,there is absolutely no sign of our API key.So there we are.We have successfully deployed our open AI projectto the live internet with the API key hidden.And now you can safely share your projectsand use them in your portfoliowithout fear of your API key being compromised.Now you might be thinking, wait there,anyone can just access my serverless function.They can write their own fetch request to the URL,which of course is available on the front end.And then from there, they'll be able to useand abuse my open AI API key.Well, they can't, this endpoint is only goingto accept fetch requests from its own domain.Now we can prove that right here in Scrimbabecause if we want to make a fetch requestto this endpoint right here from inside a scrim,that should not be possiblebecause scrims are hosted on scrimba.comand this endpoint is using my custom Netlify URL.Okay, let's hit save and I'm going to open up the consoleand I'll just say, hey, and there we are, we get an error.We are not able to make a fetch requestto that URL from within Scrimba.com.And you can repeat that test from your own domain,check out the dev tools and look in detailat the error you get.Now, of course, if for some reason we wanted other domainsto be able to access our endpoint,we would be able to do that with the cause policy.Cause is the cross origin resource sharingand it is quite a big topic,but if it's completely unfamiliar to you,I do recommend you read up on it at some pointbecause it is really importantwhen you start working with APIs and endpoints.Okay, we are done with this project.Let's just take one more scrim to recap what we've studiedand talk about where you go next.I just want to say massive congratulationson finishing this course.You now have the AI foundations you needto tackle almost any web dev related AI task.Let's just have a quick look back at what we've studied.So we looked at how to use the open AI API.We used various models, including the GPT-4 model,text DaVinci 003 and our own fine tuned model.We looked at prompt engineering,including the zero shot approach, the few shot approachand the specific object syntax neededfor the create chat completions endpoints.We worked on building chatbotsand on fine tuning a model using our own data.So the chatbot gave us answersspecific to our circumstances.And of course, along the way,we've had loads of challenges.So where next for you and AI?Well, it would be great to fine tune with more data.You could get a fine tuned bot production ready.Now that will require you to findand organize a lot of data.Also keep an eye on the AI scene.There is a lot going on with text and imagesas we've seen here, but also with voiceand of course with video.And in terms of how you use that in your personal projects,I recommend you find a need for AI and then build an app.So work on something that you've identifiedas a problem that needs solving and use AI to solve it.The best portfolio projects are unique to you.Now, whatever you do,why not head over to Scrimba's Discord serverand go to the Today I Did channel.This screenshot is actually a link.It will take you straight there.And you can let everybody knowthat you finished the course and tell them how you got on.And when it comes to stretch goals in your own projects,why not share them in the I Built This channel.Show off your work and get great feedback from your peers.And lastly, do let me know how you got on with the courseand show me what projects you've built.You can catch me right here on Twitter.And all that remains to be said is thank you very muchfor completing this course and I wish you all the very best.\n"