diff --git a/GptBlazor/Constant.cs b/GptBlazor/Constant.cs new file mode 100644 index 0000000..a9371e0 --- /dev/null +++ b/GptBlazor/Constant.cs @@ -0,0 +1,10 @@ +namespace GptBlazor; + +public class Constant +{ + public static string? ResourceName; + + public static string? DeploymentId; + + public static string? ApiKey; +} \ No newline at end of file diff --git a/GptBlazor/GptBlazor.csproj b/GptBlazor/GptBlazor.csproj index b63ba76..8e71f24 100644 --- a/GptBlazor/GptBlazor.csproj +++ b/GptBlazor/GptBlazor.csproj @@ -1,10 +1,11 @@ - + net7.0 enable enable - + c76d0bd7-b6fa-4aaa-baeb-49ab35f36fc4 + @@ -12,6 +13,7 @@ + diff --git a/GptBlazor/Pages/Index.razor b/GptBlazor/Pages/Index.razor index 3c55cc2..69ad777 100644 --- a/GptBlazor/Pages/Index.razor +++ b/GptBlazor/Pages/Index.razor @@ -14,7 +14,7 @@
Chat
-
+
@foreach (var message in _messages) { @@ -57,8 +57,8 @@
diff --git a/GptBlazor/Pages/Index.razor.cs b/GptBlazor/Pages/Index.razor.cs index 5dde70b..324e4a6 100644 --- a/GptBlazor/Pages/Index.razor.cs +++ b/GptBlazor/Pages/Index.razor.cs @@ -1,35 +1,59 @@ using System.Diagnostics.CodeAnalysis; +using BootstrapBlazor.Components; using Furion.LinqBuilder; -using GptBlazor.Entity; using GptBlazor.Service; using Markdig; using Microsoft.AspNetCore.Components; +using Microsoft.JSInterop; +using Toolbelt.Blazor.HotKeys2; +using Message = GptBlazor.Entity.Message; namespace GptBlazor.Pages; -public partial class Index +public partial class Index : IAsyncDisposable { private List _messages; + + [Inject] + [NotNull] + private IJSRuntime? JsRuntime { get; set; } [Inject] [NotNull] private OpenAiService? OpenAiService { get; set; } + [Inject] + [NotNull] + private HotKeys HotKeys { get; set; } + + private ElementReference Input { get; set; } + + private Button? SubmitButton { get; set; } + private string _userInput = string.Empty; private string _response = string.Empty; private bool _isThinking = false; - protected override async Task OnInitializedAsync() + private HotKeysContext HotKeysContext; + + protected override void OnInitialized() { - await base.OnInitializedAsync(); + base.OnInitialized(); _messages = new List(); + this.HotKeysContext = this.HotKeys.CreateContext() + .Add(ModCode.Ctrl, Code.Enter, async () => + { + await SubmitButton.FocusAsync(); + await SendMessage(); + }, exclude: Exclude.None); } private async Task SendMessage() { - if (_userInput.IsNullOrEmpty()) + //await JsRuntime.InvokeVoidAsync("focusInput", SubmitButton); + if (_userInput.IsNullOrEmpty() || _isThinking) { return; } @@ -44,10 +68,12 @@ public partial class Index }); _isThinking = true; StateHasChanged(); + await JsRuntime.InvokeVoidAsync("scrollToBottom"); await foreach (var str in OpenAiService.StreamResponseEnumerableFromChatbotAsync(input)) { _response += str; StateHasChanged(); + await JsRuntime.InvokeVoidAsync("scrollToBottom"); } _messages.Add(new Message @@ -59,5 +85,12 @@ public partial class Index _isThinking = false; _response = string.Empty; StateHasChanged(); + await JsRuntime.InvokeVoidAsync("scrollToBottom"); + await Input.FocusAsync(); + } + + public async ValueTask DisposeAsync() + { + await this.HotKeys.DisposeAsync(); } } \ No newline at end of file diff --git a/GptBlazor/Pages/_Host.cshtml b/GptBlazor/Pages/_Host.cshtml index e9ddbf4..49964eb 100644 --- a/GptBlazor/Pages/_Host.cshtml +++ b/GptBlazor/Pages/_Host.cshtml @@ -34,5 +34,6 @@ + \ No newline at end of file diff --git a/GptBlazor/Program.cs b/GptBlazor/Program.cs index 7047b7e..0c97626 100644 --- a/GptBlazor/Program.cs +++ b/GptBlazor/Program.cs @@ -1,6 +1,10 @@ +using GptBlazor; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Web; using GptBlazor.Data; +using Microsoft.Extensions.Primitives; +using Toolbelt.Blazor.Extensions.DependencyInjection; +using App = Furion.App; var builder = WebApplication.CreateBuilder(args).Inject(); @@ -9,6 +13,19 @@ builder.Services.AddRazorPages().AddInjectBase(); builder.Services.AddServerSideBlazor(); builder.Services.AddSingleton(); builder.Services.AddBootstrapBlazor(); +builder.Services.AddHotKeys2(); + +var config = App.Configuration.GetSection("ChatGpt"); +Constant.ResourceName = config["ResourceName"]; +Constant.DeploymentId = config["DeploymentId"]; +Constant.ApiKey = config["ApiKey"]; +ChangeToken.OnChange(() => config.GetReloadToken(), () => +{ + Constant.ResourceName = config["ResourceName"]; + Constant.DeploymentId = config["DeploymentId"]; + Constant.ApiKey = config["ApiKey"]; +}); + var app = builder.Build(); // Configure the HTTP request pipeline. diff --git a/GptBlazor/Service/OpenAiService.cs b/GptBlazor/Service/OpenAiService.cs index 5b92d7f..d133f27 100644 --- a/GptBlazor/Service/OpenAiService.cs +++ b/GptBlazor/Service/OpenAiService.cs @@ -6,17 +6,12 @@ namespace GptBlazor.Service; public class OpenAiService : IScoped { - private const string _resourceName = "jxgpt"; - private const string _deploymentId = "gpt35test"; - - private const string _apiKey = "e97ae651d99945e2b3bb7e666442f5e9"; - private readonly Conversation conversation; public OpenAiService() { - var api = OpenAIAPI.ForAzure(_resourceName, _deploymentId, _apiKey); + var api = OpenAIAPI.ForAzure(Constant.ResourceName, Constant.DeploymentId, Constant.ApiKey); api.ApiVersion = "2023-03-15-preview"; conversation = api.Chat.CreateConversation(); } diff --git a/GptBlazor/wwwroot/js/site.js b/GptBlazor/wwwroot/js/site.js new file mode 100644 index 0000000..9b674b1 --- /dev/null +++ b/GptBlazor/wwwroot/js/site.js @@ -0,0 +1,8 @@ +function scrollToBottom() { + var element = document.getElementById("scroll"); + element.scrollTop = element.scrollHeight; +} + +function focusInput(element) { + element.focus(); +} \ No newline at end of file