3/6/2023 Admin
Build Your Own ChatGPT Client in Blazor
The OpenAI GPT-3.5-Turbo API is a powerful tool that allows developers to create cutting-edge applications that can understand, analyze, and generate human-like text. With Microsoft Blazor, we can harness the power of this API to create a seamless client experience. In this blog post, we will explore how we can use Microsoft Blazor to build a client that calls the new OpenAI GPT-3.5-Turbo API, and demonstrate some of the exciting possibilities that this combination brings.
The primary difference between this example and the previous example covered in: Calling OpenAI GPT-3 From Microsoft Blazor is that this example calls the OpenAI GPT-3.5-Turbo API and that allows us to create interactions that have context. Meaning, the response in each interaction is based on the interactions that preceded it.
For example, when we ask the API to “List 5 reasons you would want to use this combination for web development” and click the Call ChatGPT button…
It processes the response…
…and the response is based on the previous back and forth interactions. It knows we were talking about Blazor and OpenAI.
Creating The Application
Use Visual Studio 2022 or higher.
Create a Blazor Server project.
Add the OpenAI-DotNet NuGet package.
Add a section like this to the appsettings.json file, replacing the Organization and ApiKey values with your own OpenAI values:
"OpenAIServiceOptions": {
"Organization": "** Your OpenAI Organization **","ApiKey": "** Your OpenAI ApiKey **"}
(See this article for the steps you need to get an OpenAI key and Organization Id)
Open the Index.razor page and replace all the code with the following code:
@page "/"@using OpenAI;@using OpenAI.Chat;@using OpenAI.Models;@inject IConfiguration _configuration@inject IJSRuntime _jsRuntime<PageTitle>Index</PageTitle>
Add the following Styles to the page:
<style>textarea {border: 1px dashed #888;border-radius: 5px;width: 80%;overflow: auto;background: #f7f7f7}/* improved CSS for speech bubbles */.assistant, .user {position: relative;font-family: arial;font-size: 1.1em;border-radius: 10px;padding: 20px;margin-bottom: 20px;}.assistant:after, .user:after {content: '';border: 20px solid transparent;position: absolute;margin-top: -30px;}.user {background: #03a9f4;color: #fff;margin-left: 20%;margin-right: 100px;top: 30%;text-align: right;}.assistant {background: #4CAF50;color: #fff;margin-left: 100px;margin-right: 20%;}.user:after {border-left-color: #03a9f4;border-right: 0;right: -20px;}.assistant:after {border-right-color: #4CAF50;border-left: 0;left: -20px;}.msg {font-size: medium;}</style>
Add the HTML markup:
<h1>ChatGPT</h1><p style="font-size:small"><b>Total Tokens:</b> @TotalTokens</p><div id="chatcontainer" style="height:550px; width:80%; overflow: scroll;">@foreach (var item in messages){<div>@if (item.Role == Role.User){<div style="float: right; margin-right: 20px; margin-top: 10px"><b>Human</b></div><div class="@item.Role.ToString().ToLower()"><div class="msg">@item.Prompt<br /><br /><div style="font-size:xx-small;"><i><b>(@item.Tokens)</b> Tokens</i></div></div></div>}else{<div style="float: left; margin-left: 20px; margin-top: 10px"><b>ChatGPT </b></div><div class="@item.Role.ToString().ToLower()"><div class="msg">@if (item.Prompt != null){@((MarkupString)item.Prompt)}<br /><br /><div style="font-size:xx-small;"><i><b>(@item.Tokens)</b> Tokens</i></div></div></div>}</div>}</div>@if (!Processing){<textarea rows="3" cols="60" @bind="prompt" /><br /><button class="btn btn-primary"@onclick="CallChatGPT">Call ChatGPT</button><span> </span><button class="btn btn-info"@onclick="RestartChatGPT">Restart</button>}else{<br><h4>Processing...</h4>}<br /><p style="color:red">@ErrorMessage</p>
Add the following fields:
string Organization = "";
string ApiKey = "";
List<MessageSave> messages = new List<MessageSave>();
string prompt = "Write a 10 word description of OpenAI ChatGPT";string ErrorMessage = "";
bool Processing = false;int TotalTokens = 0;
Add the OnInitialized method that will run when the page first loads. This will retrieve the Organization Id and ApiKey from the appsettings.json file:
protected override void OnInitialized(){Organization = _configuration["OpenAIServiceOptions:Organization"] ?? "";
ApiKey = _configuration["OpenAIServiceOptions:ApiKey"] ?? "";
}
Open the _Host.cshtml page and add the following JavaScript method:
<script>window.ScrollToBottom = (elementName) => {element = document.getElementById(elementName);element.scrollTop = element.scrollHeight - element.clientHeight;}</script>
This method will scroll the chat screen to the bottom, so that the active part of the conversation is always visible.
Return to the Index.razor page, and add the OnAfterRenderAsync method that will call the ScrollToBottom JavaScript method we just added:
protected override async Task OnAfterRenderAsync(bool firstRender){try
{await _jsRuntime.InvokeAsync<string>("ScrollToBottom", "chatcontainer");}catch
{// do nothing if this fails
}}
Add the following class to hold the Messages:
public class MessageSave{public string? Prompt { get; set; }public Role Role { get; set; }public int Tokens { get; set; }}
Add the following method that will be raised when the Restart button is clicked:
void RestartChatGPT()
{prompt = "Write a 10 word description of OpenAI ChatGPT";
messages = new List<MessageSave>();
TotalTokens = 0;ErrorMessage = "";StateHasChanged();}
Finally add the following method to call the ChatGPT API when the Call ChatGPT button is clicked:
async Task CallChatGPT(){try
{// Set Processing to true to indicate that the method is processing
Processing = true;
// Call StateHasChanged to refresh the UI
StateHasChanged();// Clear any previous error messages
ErrorMessage = "";// Create a new OpenAIClient object
// with the provided API key and organization
var api = new OpenAIClient(new OpenAIAuthentication(ApiKey, Organization));// Create a new list of chatMessages objects and initialize it with the
// system's introductory message
var chatMessages = new List<Message>();
chatMessages.Add(new Message(Role.System, "You are helpful Assistant"));// Add all existing messages to chatMessages
foreach (var item in messages){chatMessages.Add(new Message(item.Role, item.Prompt));
}// Add the new message to chatMessages
chatMessages.Add(new Message(Role.User, prompt));
// Call ChatGPT
// Create a new ChatRequest object with the chat prompts and pass
// it to the API's GetCompletionAsync method
var chatRequest = new ChatRequest(chatMessages);
var result = await api.ChatEndpoint.GetCompletionAsync(chatRequest);// Create a new MessageSave object with the user's prompt and other
// details and add it to the messages list
messages.Add(new MessageSave
{Prompt = prompt,Role = Role.User,Tokens = result.Usage.PromptTokens});// Create a new MessageSave object with the response and other details
// and add it to the messages list
messages.Add(new MessageSave
{Prompt = result.FirstChoice.Message,Role = Role.Assistant,Tokens = result.Usage.CompletionTokens});// Update the total number of tokens used by the API
TotalTokens = TotalTokens + result.Usage.TotalTokens;}catch (Exception ex)
{// Set ErrorMessage to the exception message if an error occurs
ErrorMessage = ex.Message;}finally
{// Clear the prompt variable
prompt = "";// Set Processing to false to indicate
// that the method is done processing
Processing = false;
// Call StateHasChanged to refresh the UI
StateHasChanged();}}
When we run the application, we can interact with it using normal conversational language.
Links
Calling OpenAI GPT-3 From Microsoft Blazor
Download
The project is available on the Downloads page on this site.
You must have Visual Studio 2022 (or higher) installed to run the code.