chore: import upstream snapshot with attribution
This commit is contained in:
+78
@@ -0,0 +1,78 @@
|
||||
@page "/"
|
||||
@using Microsoft.SemanticKernel
|
||||
@attribute [StreamRendering(true)]
|
||||
@attribute [OutputCache(Duration = 5)]
|
||||
@rendermode InteractiveServer
|
||||
|
||||
@inject AgentCompletionsApiClient AgentCompletionsApi
|
||||
|
||||
<PageTitle>Chat</PageTitle>
|
||||
|
||||
<div class="chat-page">
|
||||
<div class="chat-container">
|
||||
<div class="chat-history">
|
||||
@foreach (var message in messages)
|
||||
{
|
||||
<div class="message @(message.Sender == "User" ? "user" : "agent")">
|
||||
@message.Text
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div class="chat-input">
|
||||
<textarea @bind="userMessage" @bind:event="oninput" @onkeydown="HandleKeyDown" placeholder="Enter your query"></textarea>
|
||||
<div class="chat-button-container">
|
||||
<button class="btn btn-primary" @onclick="SendMessage" disabled="@(string.IsNullOrWhiteSpace(userMessage))">Send</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
private List<Message> messages = new();
|
||||
private string userMessage = string.Empty;
|
||||
|
||||
private async Task SendMessage()
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(userMessage))
|
||||
{
|
||||
messages.Add(new Message { Sender = "User", Text = userMessage });
|
||||
|
||||
var prompt = userMessage;
|
||||
|
||||
userMessage = string.Empty;
|
||||
|
||||
bool agentMessageAdded = false;
|
||||
|
||||
var agentMessage = new Message { Sender = "Agent", Text = string.Empty };
|
||||
|
||||
await foreach (var update in AgentCompletionsApi.CompleteStreamingAsync(prompt, CancellationToken.None))
|
||||
{
|
||||
if (!agentMessageAdded)
|
||||
{
|
||||
messages.Add(agentMessage);
|
||||
agentMessageAdded = true;
|
||||
}
|
||||
|
||||
agentMessage.Text += update;
|
||||
|
||||
// Trigger UI update
|
||||
this.StateHasChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task HandleKeyDown(KeyboardEventArgs e)
|
||||
{
|
||||
if (e.Key == "Enter")
|
||||
{
|
||||
await SendMessage();
|
||||
}
|
||||
}
|
||||
|
||||
private class Message
|
||||
{
|
||||
public required string Sender { get; set; }
|
||||
|
||||
public required string Text { get; set; }
|
||||
}
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
.chat-page {
|
||||
display: grid;
|
||||
grid-template-rows: 1fr auto;
|
||||
height: 92vh;
|
||||
}
|
||||
|
||||
.chat-container {
|
||||
overflow-y: auto;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.chat-history {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.message {
|
||||
padding: 5px 10px;
|
||||
border-radius: 15px;
|
||||
max-width: 60%;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.message.user {
|
||||
background: linear-gradient(135deg, #007bff, #00d4ff);
|
||||
color: white;
|
||||
align-self: flex-end;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
.message.agent {
|
||||
background-color: #f1f1f1;
|
||||
color: black;
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
.chat-input {
|
||||
display: flex;
|
||||
padding: 10px;
|
||||
flex-direction: column;
|
||||
border-top: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.chat-input textarea {
|
||||
flex: 1;
|
||||
resize: none;
|
||||
}
|
||||
|
||||
.chat-input button {
|
||||
padding: 10px 20px;
|
||||
background: linear-gradient(45deg, #007bff, #00d4ff);
|
||||
border: none;
|
||||
border-radius: 25px;
|
||||
color: white;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
transition: background 0.3s ease;
|
||||
}
|
||||
|
||||
.chat-input button:disabled {
|
||||
background: #ccc;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.chat-input button:hover:enabled {
|
||||
background: linear-gradient(45deg, #0056b3, #0099cc);
|
||||
}
|
||||
|
||||
.chat-button-container {
|
||||
margin-top: 10px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
@page "/Error"
|
||||
@using System.Diagnostics
|
||||
|
||||
<PageTitle>Error</PageTitle>
|
||||
|
||||
<h1 class="text-danger">Error.</h1>
|
||||
<h2 class="text-danger">An error occurred while processing your request.</h2>
|
||||
|
||||
@if (ShowRequestId)
|
||||
{
|
||||
<p>
|
||||
<strong>Request ID:</strong> <code>@requestId</code>
|
||||
</p>
|
||||
}
|
||||
|
||||
<h3>Development Mode</h3>
|
||||
<p>
|
||||
Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred.
|
||||
</p>
|
||||
<p>
|
||||
<strong>The Development environment shouldn't be enabled for deployed applications.</strong>
|
||||
It can result in displaying sensitive information from exceptions to end users.
|
||||
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
|
||||
and restarting the app.
|
||||
</p>
|
||||
|
||||
@code{
|
||||
[CascadingParameter]
|
||||
public HttpContext? HttpContext { get; set; }
|
||||
|
||||
private string? requestId;
|
||||
private bool ShowRequestId => !string.IsNullOrEmpty(requestId);
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
requestId = Activity.Current?.Id ?? HttpContext?.TraceIdentifier;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user