Coding a ChatBot in C# and .NET Blazor using Azure AI from Scratch

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hi everyone and welcome to coding with Tom in today's video we're going to create a chatbot website we're going to do it in.net framework using Blazer server and code mainly in c-sharp we're also going to use azure's open AI service now don't worry if you've never used either of these before I'm going to take you step by step through the process if you like this video please click like subscribe and hit the notification Bell let's start off with a demo of the software that you're going to be creating in this video so let me start it up here what you'll see is this very simple screen that has a chat window and you'll see our check bubbles will go in there and then a clear chat button to clear the chat history and the text entry area so let's start off the chat by asking what is pizza so my message goes to the top right here what is pizza and then the response on the left is from the Azure AI chat gpt35 model it's a description of Peter I'm going to ask a follow-up question what is the main ingredient that question is also sent to chatgpt and the language model comes up with a context aware answer so it still knows we're talking about pizza you're going to see later in the code how we do this this entire thread of conversation is considered really one request that you keep adding to each time providing additional knowledge to the model so that the context is retained for example if I clear the chat and simply ask what is the main ingredient you'll see that it doesn't actually know what I'm talking about because it doesn't know we're talking about pizza because that has nothing to do with this threat of conversation also I've trained the system ahead of time to not allow questions other than that about food so if I say what is the color of the sky it's going to respond with I can only answer questions about food I'm going to take a little time to show you the Azure open AI Service website this is a good place to get started when you're working with the Azure open AI service because it provides for a playground here for you to test out the models and an area for you to configure the models that you're going to use in your applications you can get to it by going to oai.azure.com and if you have a valid subscription to Azure it's going to then ask you to sign a few more agreements for the use of this service so once you've done that and you're approved you can come into this website and you can see we have two sections we have this playground section and a management section in the management section this is where you set up the models that you're going to use in our case we're going to use the gpt35 model so let's do that first we can't actually use the playground until we've set up some deployments so I'm going to go and create a deployment by hitting deployments and you can see I have one here already but what I'm going to do is show you what you would do if you didn't have one you just go to create new deployment and you hit the drop down and you pick the model that you want to use in our case we use the gpt35 turbo and then you give it a name of your choosing and then you would hit create and it would create it I'm going to cancel because I already have one so now that there is a deployment in place you'll be able to use it in the playground so I'm going to go to the playground and if I click on chat and you haven't gone to the playground before it's going to ask you to choose the deployment that you'd like to use but I did already so it has my deployment here on the right already chosen so you could choose the one you just created if you if you didn't choose it already already so what we have here are three different sections we have the assistant setup section the chat session section and the configuration section let's start over here with assistant setup this is the area where you configure how the language model is going to answer the questions that is are sent to it now it provides a default system message here you are an AI assistant that helps people find information that's very generic that kind of instruction is going to allow the language model to pretty much answer any question so what I'm going to do is make it a little more specific I only wanted to answer questions about food so I'm going to tell it to do that you can only answer questions about food if the user asks a question on another topic respond with and I'm going to put in quotes I only answer questions about food now this system message is going to be included anytime we use the library for any chat request now also you can add examples here which I'm not going to do but it allows you to create a format for how the responses are going to look so you can look into that on your own if you want to explore that more what I'm going to do is just save the changes and now that I've done that I can actually use this chat session window to play with this model using that system message so what I'm going to do is try to ask about pizza so what is pizza this is a food so it should answer and it does and I can continue this thread of conversation here because it has the context of it and say what is the main ingredient and it continues to give me more information about pizza I knew we were asking about pizza because it knows these questions were asked prior now if I go ahead and clear this chat and ask the same question what is the main ingredient it's not going to know we're talking about because the whole context is gone since I cleared it so it's actually going to tell me I need more context what food are you referring to so I could answer but I'm not going to what I'm going to do though is ask a question not about food what is the color of the sky and you'll see it can't answer that question it'll say I'm sorry but I can answer questions related to food please ask me a question about food so you can see that the system message is actually working now you can also go to the configuration section over here and play with the configuration settings a little bit more there's a section called parameters here that has a lot of other options that I'm not going to go into but you can explore those further if you'd like another nice feature on this page is the view code button what it does is it takes this chat session and it actually creates code that would implement the chat session in a couple different languages when you first do it it comes up in Python since we're going to be doing C sharp I can go to this drop down and switch it to C sharp and what you'll see is an example set of code that you could actually copy into your project and it would do the exact same thing that this chat just did now there's some caveats to that because it actually provides you with two different ways of doing it in C sharp there's this object called the streaming chat completions object and then if that's line 12 here and if I scroll down to line 34 there's just a regular chat completions object so what it does is it repeats the process twice in this example a streaming chat completion allows the response to come a little bit at a time and I know if you've used Bing or if you use chat EBT you've seen that happen where words kind of come one after the other that would be a streaming chat completion if you use the regular chat completion it'll just return the complete response when it's ready and that's what we're going to do in our example now another thing to note about this sample code is it's a good place to look for your variables that you need to connect to azure open Ai and there's three in particular you need to have your url which is something.openii.azure.com the something is what you decided to be then there's a deployment model which is the name you gave it over in the deployments page and then there's also a secret key now to get to the secret key it doesn't even show the secret key here in the source code but if you scroll down to the bottom here there's a copy option where you can copy this key so we're going to need to have that key for later and I'll mention it again when we configure our website so I'm just going to close this window now we're actually going to use code similar to that source code but I'm going to go through and explain it more in detail when we get to that point well that's enough introduction so let's go ahead and create a new project I opened up visual studio 2022 and I'm going to hit the create new project button we're going to do a Blazer server app so you can scroll down and find it or search for it if it's not in your recent project templates now there's two choices here Blazer server app and Blazer server app empty we're going to use the actual Blazer server app and then I'm just going to delete things out of it that I don't want to use so we're going to hit next I've got to give it a location so this is as good as any I'm going to call it Blazer Copilot two and what I'm going to do is have it place the solution project in the same directory that's just an organizational thing I like I'll hit next I also don't like top level statements so I make sure that box is checked and you want to use.net7 now if you plan to implement authentication in your application later you could do that from the beginning but for this example I'm not going to bother and I'll just hit create and once you've done this you get the standard Blazer example program if we run that you'll see um the hello world with the home counter with a clicker and a fetch data which fetches bogus weather forecast data so this is our foundational application that we're going to just modify to make this chat application so let me go ahead and start modifying this and removing things I don't want so let me close this and what I'm going to do is I don't really want those other pages so I'm going to go into pages and I don't want the counter and I don't want this fetch data example so I'm going to delete those two I also in the data don't want the weather forecast or weather forecast service we're going to create our own service so I'll delete those two in the shared area we have a main layout which is fine the main layout has a nav menu I actually will get rid of the nav menu entirely so I'm just going to take this and delete it and then delete this nav menu component here now there's a survey prompt component on the index page so if I go back to the index page you'll see there's a survey prompt I'm just going to delete that too and this index page is going to be the main page that I put my new chat component on so I'm going to change this title to chat and I'm going to eliminate this hello world and the welcome to your new app we'll come back to this though later because this is where our chat component is going to live now I also then can delete this survey prompt component because I don't need that anymore so I'm going to right click and delete that since I've deleted these few things I have to go to the program.cs now too and illuminate some things out of there for example we have this weather forecast service that no longer exists so I'm going to delete that line and you can see here it's trying to refer to this Blazer co-pilot to data Library which since it has no objects in it doesn't exist either so I'm just going to get rid of that for now and now we should be able to run the application and we do we have a very clean looking index page with just an about button on it which we're probably going to get rid of as well so let me close this and go back to index now it's not on the index page that is actually part of the main layout so if I go to main layout I can eliminate this div which has this link to Microsoft with about now I could just replace it though with taps chat client or whatever you like and that'll just show up on the top now I mentioned before there are some variables you need to have in your configuration to allow you to connect to the Azure open AI service for now we're going to store them in the app settings.json so to do that I'm going to go to appsettings.json and I'm going to add some configuration options in here I'm going to create a section actually just for my open AI configuration settings let me go ahead and paste that in here now you'll see I've obscured some of the information but you're going to have something similar you're going to have the URL for your particular instance of openai and azure.com you're going to have the key and then you're going to have the name of your deployment model here so you're going to get this information back from the Azure AI website that I showed you before and then you're going to put it in here now let me click away from this app settings.json I'll go over to index.razer and magically the correct values for me are going to be in the app settings Json file because I pause the video and put them in now to make this work we're going to create two different things we're going to create a Blazer component that's going to handle all the user interface and I'm also going to create a service that's going to handle the interaction with the Azure openai API for these two different parts of the program to communicate we're going to need to have a object to transmit the data between them and since we're dealing with messages I'm going to create a simple class to store the contents of the messages so what I'm going to do here is go to the data folder and right click and do add class I'm going to call it message and let me paste in the implementation so what we have here is a class that has three different properties the first one is a time stamp the second one is a body which is the actual text that's going back and forth and then the third one is a Boolean variable that says whether it's a request or response so if it is request that means it's a message that the user of the application is sending in to the language model if this is true if it's false then it's actually a response from openai so we're going to be able to tell which direction it's going based on that Boolean variable now I've created a Constructor here that just lets the user create a message with a given body and whether or not it's a request or response so what it does is it just sets the timestamp to now and assigns these properties the values now let's create a service that will actually handle the interaction with the azure openai so I'm going to create another folder in here called services so let me do right click and do add new folder I'm going to call it services and then in here I'm also going to create a class I'm going to call this the chat service class chat service.cs and let me go ahead and paste the implementation of this class now you'll notice there's some errors here because there's libraries that we need to include in order to make this work we're actually going to have to include some packages from azure so to do this we're going to have to go to our tools menu and go to our nuget package manager and manage the nuget packages for this solution now notice I have the include pre-release checkbox checked that's important because the Azure open AI API is in pre-release at this point so if I go to browse and I search for Azure AI open AI you'll see that there is a beta version of the API available so I'm going to click that I'm going to include it in this project and hit install and accept the terms now if I go back here notice these things still don't work because it needs to reference those packages so if I hit Alt Enter I'm going to get the tip to at the top of my page put this using Azure AI open AI so I'm going to go ahead and accept that and that fixes that problem now obviously an Azure key credential is something else we need to include and that's the it's in the Azure Library so I'll hit Alt Enter and fix that all that did is it went up here and it put these two usings in okay so let's go through this the only variable that this class has is a i configuration object this object allows us to read the configuration file that we put our secrets in and this configuration object is going to get injected into this class by the framework because it'll see a Constructor on this class the chat service class that takes a iconfiguration object as its parameter so when this is spun up the configuration object that is system-wide that is able to access my app settings.json is going to be passed into this chat service via injection and assigned to this member variable which is right here configuration now the other variable that's here is just our system message that we're going to be using to tell our language model how to behave and this is similar to what I showed you before on the playground the contents here are you are an AI assistant that helps people find information about food for anything other than food respond with I can only answer questions about food so you can tweak this based on your needs but this is just a value that I stored here as a member variable now the main functionality of this service is in this get response method and it really is the actually the only method in this entire service that we're going to need and what it is is it is a function that takes in a list of messages now this is just a list of the message objects that we just created before which I call a message chain it takes those messages including the system message sends it to the language model and then retrieves a response and that response is a single message that we're going to display to the user at the end of their chat session so to make this work what I do is I first I have a string variable here that I just set to blank because we don't have a response from the language model yet now the first thing you need to do though is open up a client object an openai client object which you can create by passing in some parameters so you have to pass in the URL to your openai instance which it gets from the configuration object and also the key the secret key that it needs to log in so that is going to be your Azure key credential object and it's going to get that also from the app settings.json file so that will get us connected now the next thing we need to do is actually call the API so to call the API what we're going to do is pass in a bunch of options so there's this thing called the chat completions options object that you have to populate with information and it's all the information you're going to need to get a response from the large language model so we instantiate a new one and what we can do is set all of these parameters these are some default values that I got from the playground so I just kind of left them as is temperature max tokens nucleus sampling Factor frequency penalty presence penalty these were the defaults that they had so I just left them now below you'll see there's this messages collection as part of the options object and in that list we're going to add all of the messages that are currently in our conversation now how do we know what those messages are well they've been passed in here this message chain so what we're going to do is go through the message chain and add them to the messages that we're going to pass back to the language model before we do that we're going to add a chat message and that's the object that the API uses to store the messages of the system message so this is that message above that's going to tell it to only answer questions about food and that has a chat role of dot system so you're always going to pass in one system message to every request that you make and it's going to be the first message you put in usually so after that we're going to then Loop through our message chain and we're going to add user and assistant messages now the user message is the message that we're sending in for that the user typed and the assistant message is a record of a response that came back from the language model so as we go through all of our message chain messages we can say if it's a request then we know that that's a user message because it's a request coming from our system to the open AI otherwise it's one of the responses that we got so we can go through and add all the messages that we have had in the chain up until that point and after we've done that we can actually call the getchat completions so this response object is what is returned from that client calling the get chat completions async method and all we do is pass in the deployment model name which is the third parameter we haven't yet used out of our app settings.json followed by the options object that we just constructed above so that's going to call the API wait for a response and then put the response in this chat completions object now the chat completions object can actually result in more than one what they call Choice we have this configured pretty much to answer in one choice for every question but there's a possibility that there could be more than one choice as a response so I'm not going to go into detail on that but you could iterate through them if you needed to but since we're going to just take the first response that comes back and assume that it isn't broken up into multiple choices I'm going to just access the first element in that array so I get the response this is a string object which is the completions that came back the first choice of response has a message component and that message has content and that content is the actual string that contains the text that came back now once I get that string back I can construct my message object with that response that came back and the false which tells me it's actually a response it's not a request it's a response from the GPT model and then I return that new message that I just created so at the end of the day this thing is going to call the open AI routine and return an additional message based on the message chain that already was produced and just to further clarify this choices option you can actually request that the API will generate more than one choice response and it'll actually rank them based on what it believes the quality of the response is and then you can go ahead and pick one of the answers but we're not doing that we're actually only asking for one by default so we're only going to get one choice for the answer now to actually make this service load you have to add a line to program.cs so let me go over there and you can add a line that says builder.services.ad Singleton with chat service and what this will do is create an instance of the chat service and load it and inject it appropriately everywhere else in your code that it's required make sure you have a reference to the package up here that you put your service in so now that we've finished the service let's work on the user interface so I'm also going to make another folder here called components to store mychat component so let's create another folder I'll call it components and under here I'm going to add a Blazer component so that's a razor component and we're going to call it chat now let me go ahead and paste in the code for this okay so let me explain how this works we're going to inject two things into this component the JavaScript runtime which I'll talk about more later and the chat service that we just created so for those of you new to Blazer or Razer in general um Blazer code in these Razer files contains both c-sharp code and markup so it includes HTML tags and also custom tags which we're going to do in the index page but right here we're just going to use HTML tags and code and anytime you're dealing with c-sharp code it starts with the at sign so what we have here is a div that's going to have our scroll box which is going to have all of the chat messages in it so I assign this dividend ID called scroll box and that's going to be important later for making it scroll properly and inside this we're going to generate all of the messages so these are the bubbles of the user and the response and it's going to grab these out of this messages variable which is a member of the class that is behind this page so let's go down and look at that first a little bit before I jump to this you'll see there's two variables here remember variables to this class in this code section this code represents the class that is behind this file and what we have here is a chat input object which I create below and I'll in fact I'll go down there now this chat input class is very simple it's just a class with one property called text and a Constructor that sets it equal to blank you need to have a class for the Blazer edit form component that I'm using above so for two-way data binding so I have that set up so if I go up here again you'll see that I created one of these so I nude a chat input object and I also knew the list of messages so this actual message list contains the same message objects that our service is familiar with so the user interface is going to be generated from the same list of messages that we will pass back and forth to the service now if I go back up here you'll see it goes through those message objects inside of the scroll area and it puts divs in for each one of the messages now there is some CSS class for the different kinds of messages this is a message sent to the system by the user hence the name sent which we'll go into the CSS file later and show you and then there's the received which is what comes back so basically the scent is going to create the look and feel for the bubble on the right and the received is going to create the look and feel for the bubble on the left the fact that actually is on the right and the left though is additional information additional classes here with d flex and justify content and this is all part of bootstrap 5. and that allows this to be placed on the right versus placed on the left and inside of each one of these divs is just the paragraph that has the body of the message so we'll close off that scroll box I put a horizontal line in and then a button and this button is bound to the code with the clear chat method below which I'll talk about and then this edit form which is where the user will type in the text that they want to send to the model it has its own ID as well which is going to be useful later the edit form itself is bound to this chat input model below it's required to have a model and all the model is is just a class when we submit this so when someone hits enter it's going to call the submit chat button which is going to actually send the chat over to the service if I scroll over here you'll see that this text area is bound to the model's text property so the whatever they type in the box is going to be saved in that text property of the object or if we change the text property of the object it's going to update what's in the text box so it's it's both directions and then over here we have it every time someone types a character in this is what on input is if you type any character it's going to call this this update text area method now this is important for later and you'll see why so let's go down here the clear chat button is very simple all it does is it takes the list of messages that we have and it just wipes it out and since this is Blazer when that object is set to have no items the HTML encode above will run and read display the list of chat messages without anything in it automatically now here's what happens when we actually click the submit chat button what it does is pretty simple it creates a message object from the sender with the text that's in the box and true to designate that it actually is a request message going out it adds it to my messages chain so it will display it automatically on the screen but then also we're going to be able to send it into the chat service ignore this JavaScript line for a second because I'm going to explain why I added that but then this message response is going to come back from the service because we're going to call the service with the entire list of messages that we have so far so all the messages that are in the scroll box above or in this list of messages are going to be passed into the chat service so that's going to result in a message which we're then going to also add to those messages which will then of course display it in the Box above now again I'll go over this JavaScript in a second and then when we're done we clear the Box because we want the box to be empty for the person to type another message in so let me go here to update text area now this is a little bit of a I don't want to say a hack but I really wanted to have the ability to have the user hit enter and submit the textbook the text to the service when they hit enter so that's why I'm going to have to show you this little JavaScript I added and the fact that every time someone hits a key press it's going to change this model's text variable to have the current value that's that's actually in the HTML text area if I didn't do this then it wouldn't make it over like it it wouldn't be updated when they hit enter so I did that and then what I had to do also here is on after render async which is another Blazer lifecycle method is when the page is first loaded I have to call this other JavaScript method that I added called add submit on enter and pass in the chat text area because what I have to do is have it listening for that enter key and that's what it's going to do it'll listen on this object the chat text area which is the ID of the HTML tag and it's going to be listening for the person to hit enter and then submit the form automatically again this is a little bit of a hack probably could have done this a little better using another Blazer component but I wanted to keep this as simple as possible okay so let's this one won't work until I add a little bit of JavaScript because obviously these things are being called um I'll go back here and explain this before I show you the JavaScript when I submit the chat I need to scroll down because the scroll box that has all the chat messages in it will update but it won't scroll to the bottom in order to do that I had to actually trigger some JavaScript to scroll the thing all the way to the bottom as we add the chat bubbles to the window otherwise they just kept being added and you couldn't see them so I trigger this JavaScript to do that okay let me go ahead and add the JavaScript helper routines that I mentioned here so if I open up the WW root folder and right click I'll do add new item JavaScript and I'll call it jshelpers.js let me paste in the code the first method the first function here is called update scroll update scroll is called back here in chat every time we add another chat message to our div the reason we have to update the scroll is because if I keep adding these chat bubbles in it won't scroll to the bottom automatically they'll just keep being added and then they'll disappear off the screen and the user would have to scroll down manually which is not a good experience so every time I add one I call update scroll and I pass in the element ID of scroll box and that's the div that actually has the bubbles in it so if I go here to JS helpers well all that does is set a timeout and after the timeout of 100 milliseconds changes the scroll position to the height of the div and having to wait the 100 milliseconds is important because if you don't then the actual bubbles that were added aren't there at that point in time so you have to wait until they are and then once they are it will scroll to the bottom this is sort of a cluge of JavaScript but it works now these other ones here have to do with capturing the enter key in the text area so this add submit on enter is called First with the chat text area text area HTML tag and it adds the event listener for key down so anytime someone types a key in there it's going to do submit on enter and submit on enter is going to check to see if it's a return which is code 13. and if it is a return it's going to do a submit so that's going to do a form submission and it actually knows to call the form associated with that text area because it's the targets form and then prevents the default Behavior which prevents it from actually going to the next line in the text area so these additional JavaScript functions just help the user interface perform a little bit more like I expected if anyone knows a better way to do this please leave a comment below I'd be interested in seeing other ideas on this um however to make all this work we have to make sure this JavaScript file is accessible to our Blazer so to do that I have to put a reference to it in the host dot cshtml file here under pages so if I go in there and scroll to the bottom you'll see there's actually the Blazer server framework script is included and then right below it I'm just going to put another script tag that references those additional JavaScript functions now I'm going to add some additional CSS to the project CSS so if I go to WWE root you'll see there's a under CSS there is a site.css I'm going to scroll to the bottom and I'm going to paste in my additional CSS that's required and I have some styling for the text area for my scroll area sent and received Bubbles and the details involved in that now that I created this chat component and it's JavaScript Helper and CSS Associated changes I'm going to add the chat component to the index page so if I go over here to index.razer I can add a using because I have to tell it where it is so I can say using Blazer copilot 2 dot components that's where my chat component is and then I can put in a chat tag with a close and that knows to use the chat object the chat.razer on this page and now that I've done that let's start up the program so if I go up here to run it you'll see that I have my scroll area I have a clear chat button and my text area so I'm going to start asking questions what is pizza and I get a response now also I'm going to add a follow-up question what is the main ingredient and it's talking about the main ingredient for pizza because it knows the context let me ask another question off topic what is the average height of a pine tree I can all answer questions about food so you can see that it's working as I expected to now if I hit clear chat the message list is cleared so it retains no information about our um prior chat what are other ingredients is not going to know what I'm talking about it's just going to give a generic answer um not in the context of pizza so you can see that it's working exactly how I expected now that our basic chat functionality is complete I'm looking to Future now that our basic chat functionality is complete in my next video I'm going to provide memory to the chat now what this means is you provide additional information anytime someone asks a question that the language model can use to answer the more specific question based on your information for example you might have a company database of documentation that you'd like to create a copilot for what you would do is put all this documentation in Azure cognitive search and then the chat question would search against that database first provide some relevant data from that search to the language model and then come up with a more specific to your application answer the language model does not have all the information about your particular organization or application it only has general information so adding memory will let it search for the more specific information interpret it and provide a more interesting response so we'll look at that in the next video well thank you for watching coding with Tom if you enjoyed this video please click like subscribe and hit the notification Bell
Info
Channel: Effortless Coding with Tom
Views: 560
Rating: undefined out of 5
Keywords: GPT, Blazor, Openai, Azure, C#, Chat, Azure ai, .net, Copilot, ChatGPT, chatbot, From scratch, Step by step
Id: bT-0xvHYpS8
Channel Id: undefined
Length: 44min 57sec (2697 seconds)
Published: Sat Jun 17 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.