iTranslated by AI
Building a Chat App with GPT-4 using Semantic Kernel
GPT-4 on Azure AI Services has enabled various creative possibilities through AI chat.
In this article, I will describe how to implement a chat application using Blazor Server and a Microsoft library called Semantic Kernel.
First, install Semantic Kernel via NuGet. Since it is currently in Preview, you need to check the "Include prerelease" option to find it.

Next, we will implement a class to call Semantic Kernel.
It will be used by injecting it from Razor components.
using Markdig;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.AI.ChatCompletion;
using Microsoft.SemanticKernel.Connectors.AI.OpenAI.ChatCompletion;
namespace SemanticKernelBlazorSample.Logic
{
public class SementicKernelLogic
{
public IKernel kernel;
public IChatCompletion GtpChat4 { get; set; }
private readonly ILogger<SementicKernelLogic> _logger;
private readonly IConfiguration _configuration;
private readonly OpenAIChatHistory chatHistory;
public SementicKernelLogic(ILogger<SementicKernelLogic> logger, IConfiguration configuration)
{
_logger = logger;
_configuration = configuration;
string baseUrl = _configuration.GetValue<string>("BaseUrl") ?? string.Empty;
string key = _configuration.GetValue<string>("Gtp4Key") ?? string.Empty;
kernel = new KernelBuilder().Configure(c =>
{
c.AddAzureChatCompletionService("gpt-4", "Gtp-4", baseUrl, key);
}).WithLogger(_logger).Build();
GtpChat4 = kernel.GetService<IChatCompletion>();
chatHistory = (OpenAIChatHistory)GtpChat4.CreateNewChat();
}
public async Task<string> Run(string input)
{
chatHistory.AddUserMessage(input);
var setting = new ChatRequestSettings
{
Temperature = 0.8,
MaxTokens = 2000,
FrequencyPenalty = 0.5
};
string reply = await GtpChat4.GenerateMessageAsync(chatHistory,setting);
var pipeline = new MarkdownPipelineBuilder().UseAdvancedExtensions().UseAutoLinks().UseBootstrap().UseDiagrams().UseGridTables().Build();
var htmlReply = Markdown.ToHtml(reply, pipeline);
chatHistory.AddAssistantMessage(reply);
return htmlReply;
}
}
}
In the constructor, please configure the parameters according to your environment.
And for the Run method, which actually queries the Azure AI Service, we first adjust the familiar parameters within ChatRequestSettings.
There is room for improvement here, such as moving these settings outside of the method.
Then, we query the Azure AI Service using GenerateMessageAsync(), and the result is stored in reply.
As usual, reply returns as marked-up text, so it is cleaner to perform post-processing, such as converting it to HTML for display, before presenting it.
I implemented the Razor side as follows:
@page "/"
@using SemanticKernelBlazorSample.Data;
@using SemanticKernelBlazorSample.Logic
@inject SementicKernelLogic logic
<textarea rows="4" cols="80" @bind=Search /><br />
<button type="submit" @onclick="OnSearch">Search</button><br />
@if (Messages != null)
{
<table class="table table-striped">
<tbody>
@foreach (var message in Messages.OrderByDescending(x => x.Time))
{
<tr>
<td>@message.Name</td>
@if (message.Name == "Reply")
{
<td>@((MarkupString)message.Message)</td>
}
else
{
<td>@message.Message</td>
}
</tr>
}
</tbody>
</table>
}
@code {
private string? Search;
private string? Response;
private List<ChatMessage> Messages = new();
private async void OnSearch()
{
if (!string.IsNullOrWhiteSpace(Search))
{
ChatMessage UserMessage = new();
UserMessage.Name = "User";
UserMessage.Message = Search;
Messages.Add(UserMessage);
Search = string.Empty;
StateHasChanged();
Response = await logic.Run(UserMessage.Message);
ChatMessage reply = new();
reply.Name = "Reply";
reply.Message = Response;
Messages.Add(reply);
StateHasChanged();
}
Search = string.Empty;
}
}
Finally, you should be able to make it work by registering SementicKernelLogic as a service in Program.cs using AddScoped.

Discussion