From bae50876423fdd3962bea11d644d177fe4f94017 Mon Sep 17 00:00:00 2001 From: Haiping Chen Date: Sun, 28 May 2023 11:30:27 -0500 Subject: [PATCH] Add Azure OpenAi. --- .../IChatCompletionHandler.cs | 8 ++- .../BotSharp.Abstraction/IPlatformMidware.cs | 8 ++- .../Models/RoleDialogModel.cs | 7 ++ .../BotSharp.Core/Services/PlatformMidware.cs | 13 +++- .../AzureAiServiceCollectionExtensions.cs | 21 ++++++ .../AzureAiSettings.cs | 9 +++ .../Handlers/ChatCompletionHandler.cs | 65 +++++++++++++++++++ .../Handlers/ChatCompletionHandler.cs | 17 +++-- .../ChatbotUI/ChatbotUiController.cs | 27 ++++---- src/WebStarter/Program.cs | 3 +- src/WebStarter/WebStarter.csproj | 2 + src/WebStarter/appsettings.json | 7 ++ 12 files changed, 164 insertions(+), 23 deletions(-) create mode 100644 src/Infrastructure/BotSharp.Abstraction/Models/RoleDialogModel.cs create mode 100644 src/Platforms/BotSharp.Platform.AureAi/AzureAiServiceCollectionExtensions.cs create mode 100644 src/Platforms/BotSharp.Platform.AureAi/AzureAiSettings.cs create mode 100644 src/Platforms/BotSharp.Platform.AureAi/Handlers/ChatCompletionHandler.cs diff --git a/src/Infrastructure/BotSharp.Abstraction/IChatCompletionHandler.cs b/src/Infrastructure/BotSharp.Abstraction/IChatCompletionHandler.cs index 2e7ef0bc..403a2643 100644 --- a/src/Infrastructure/BotSharp.Abstraction/IChatCompletionHandler.cs +++ b/src/Infrastructure/BotSharp.Abstraction/IChatCompletionHandler.cs @@ -1,6 +1,12 @@ +using BotSharp.Abstraction.Models; + namespace BotSharp.Abstraction; public interface IChatCompletionHandler { - Task GetChatCompletionsAsync(string text, Func onChunkReceived); + Task GetChatCompletionsAsync(string text, + Func GetInstruction, + Func> GetChatHistory, + Func onChunkReceived, + Func onChunkCompleted); } diff --git a/src/Infrastructure/BotSharp.Abstraction/IPlatformMidware.cs b/src/Infrastructure/BotSharp.Abstraction/IPlatformMidware.cs index 423d15ce..492d2680 100644 --- a/src/Infrastructure/BotSharp.Abstraction/IPlatformMidware.cs +++ b/src/Infrastructure/BotSharp.Abstraction/IPlatformMidware.cs @@ -1,6 +1,12 @@ +using BotSharp.Abstraction.Models; + namespace BotSharp.Abstraction; public interface IPlatformMidware { - Task GetChatCompletionsAsync(string text, Func onChunkReceived); + Task GetChatCompletionsAsync(string text, + Func GetInstruction, + Func> GetChatHistory, + Func onChunkReceived, + Func onChunkCompleted); } diff --git a/src/Infrastructure/BotSharp.Abstraction/Models/RoleDialogModel.cs b/src/Infrastructure/BotSharp.Abstraction/Models/RoleDialogModel.cs new file mode 100644 index 00000000..4fc56cc4 --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/Models/RoleDialogModel.cs @@ -0,0 +1,7 @@ +namespace BotSharp.Abstraction.Models; + +public class RoleDialogModel +{ + public string Role { get; set; } + public string Content { get; set; } +} diff --git a/src/Infrastructure/BotSharp.Core/Services/PlatformMidware.cs b/src/Infrastructure/BotSharp.Core/Services/PlatformMidware.cs index 287026e5..1c4815ff 100644 --- a/src/Infrastructure/BotSharp.Core/Services/PlatformMidware.cs +++ b/src/Infrastructure/BotSharp.Core/Services/PlatformMidware.cs @@ -1,3 +1,4 @@ +using BotSharp.Abstraction.Models; using Microsoft.Extensions.DependencyInjection; namespace BotSharp.Core.Services; @@ -10,13 +11,21 @@ public class PlatformMidware : IPlatformMidware _services = services; } - public async Task GetChatCompletionsAsync(string text, Func onChunkReceived) + public async Task GetChatCompletionsAsync(string text, + Func GetInstruction, + Func> GetChatHistory, + Func onChunkReceived, + Func onChunkCompleted) { var handlers = _services.GetServices().ToList(); for (int i = 0; i < handlers.Count(); i++) { var handler = handlers[i]; - await handler.GetChatCompletionsAsync(text, onChunkReceived); + await handler.GetChatCompletionsAsync(text, + GetInstruction, + GetChatHistory, + onChunkReceived, + onChunkCompleted); } } } diff --git a/src/Platforms/BotSharp.Platform.AureAi/AzureAiServiceCollectionExtensions.cs b/src/Platforms/BotSharp.Platform.AureAi/AzureAiServiceCollectionExtensions.cs new file mode 100644 index 00000000..e9b4fb49 --- /dev/null +++ b/src/Platforms/BotSharp.Platform.AureAi/AzureAiServiceCollectionExtensions.cs @@ -0,0 +1,21 @@ +using BotSharp.Abstraction; +using BotSharp.Platform.AzureAi; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; + +namespace BotSharp.Core; + +public static class AzureAiServiceCollectionExtensions +{ + public static IServiceCollection AddAzureOpenAi(this IServiceCollection services, IConfiguration config) + { + services.AddSingleton(x => + { + var settings = new AzureAiSettings(); + config.Bind("AzureAi", settings); + return settings; + }); + services.AddScoped(); + return services; + } +} \ No newline at end of file diff --git a/src/Platforms/BotSharp.Platform.AureAi/AzureAiSettings.cs b/src/Platforms/BotSharp.Platform.AureAi/AzureAiSettings.cs new file mode 100644 index 00000000..28989dd2 --- /dev/null +++ b/src/Platforms/BotSharp.Platform.AureAi/AzureAiSettings.cs @@ -0,0 +1,9 @@ +namespace BotSharp.Platform.AzureAi; + +public class AzureAiSettings +{ + public string ApiKey { get; set; } + public string Endpoint { get; set; } + public string DeploymentModel { get; set; } + public string InstructionFile { get; set; } +} diff --git a/src/Platforms/BotSharp.Platform.AureAi/Handlers/ChatCompletionHandler.cs b/src/Platforms/BotSharp.Platform.AureAi/Handlers/ChatCompletionHandler.cs new file mode 100644 index 00000000..d17cb372 --- /dev/null +++ b/src/Platforms/BotSharp.Platform.AureAi/Handlers/ChatCompletionHandler.cs @@ -0,0 +1,65 @@ +using Azure; +using Azure.AI.OpenAI; +using BotSharp.Abstraction; +using BotSharp.Abstraction.Models; +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; + +namespace BotSharp.Platform.AzureAi; + +public class ChatCompletionHandler : IChatCompletionHandler +{ + private readonly AzureAiSettings _settings; + + public ChatCompletionHandler(AzureAiSettings settings) + { + _settings = settings; + } + + public async Task GetChatCompletionsAsync(string text, + Func GetInstruction, + Func> GetChatHistory, + Func onChunkReceived, + Func onChunkCompleted) + { + var client = new OpenAIClient(new Uri(_settings.Endpoint), new AzureKeyCredential(_settings.ApiKey)); + var chatCompletionsOptions = PrepareOptions(text, GetInstruction, GetChatHistory); + + var response = await client.GetChatCompletionsStreamingAsync(_settings.DeploymentModel, chatCompletionsOptions); + using StreamingChatCompletions streaming = response.Value; + + string content = ""; + await foreach (var choice in streaming.GetChoicesStreaming()) + { + await foreach (var message in choice.GetMessageStreaming()) + { + if (message.Content == null) + continue; + Console.Write(message.Content); + content += message.Content; + await onChunkReceived(message.Content); + } + } + + Console.WriteLine(); + await onChunkCompleted(); + } + + private ChatCompletionsOptions PrepareOptions(string text, + Func GetInstruction, + Func> GetChatHistory) + { + var prompt = File.ReadAllText(_settings.InstructionFile); + var chatCompletionsOptions = new ChatCompletionsOptions() + { + Messages = + { + new ChatMessage(ChatRole.System, prompt) + } + }; + + return chatCompletionsOptions; + } +} diff --git a/src/Platforms/BotSharp.Platform.LlamaSharp/Handlers/ChatCompletionHandler.cs b/src/Platforms/BotSharp.Platform.LlamaSharp/Handlers/ChatCompletionHandler.cs index af239da7..84f6893b 100644 --- a/src/Platforms/BotSharp.Platform.LlamaSharp/Handlers/ChatCompletionHandler.cs +++ b/src/Platforms/BotSharp.Platform.LlamaSharp/Handlers/ChatCompletionHandler.cs @@ -1,7 +1,9 @@ using BotSharp.Abstraction; +using BotSharp.Abstraction.Models; using BotSharp.Platform.LlamaSharp; using LLama; using System; +using System.Collections.Generic; using System.IO; using System.Text; using System.Threading.Tasks; @@ -31,16 +33,21 @@ public class ChatCompletionHandler : IChatCompletionHandler _model.InitChatAntiprompt(new string[] { "User:" }); } - public Task GetChatCompletionsAsync(string text, Func onChunkReceived) + public async Task GetChatCompletionsAsync(string text, + Func GetInstruction, + Func> GetChatHistory, + Func onChunkReceived, + Func onChunkCompleted) { string totalResponse = ""; foreach (var response in _model.Chat(text, "", "UTF-8")) { - Console.WriteLine(response); + Console.Write(response); totalResponse += response; - onChunkReceived(response, false); + await onChunkReceived(response); } - onChunkReceived("", true); - return Task.CompletedTask; + + Console.WriteLine(); + await onChunkCompleted(); } } diff --git a/src/UiAdapters/ChatbotUI/ChatbotUiController.cs b/src/UiAdapters/ChatbotUI/ChatbotUiController.cs index 7a755dc5..26547f5e 100644 --- a/src/UiAdapters/ChatbotUI/ChatbotUiController.cs +++ b/src/UiAdapters/ChatbotUI/ChatbotUiController.cs @@ -59,22 +59,23 @@ public class ChatbotUiController : ControllerBase, IBotUiAdapter Response.Headers.Add(HeaderNames.Connection, "keep-alive"); var outputStream = Response.Body; - await _platform.GetChatCompletionsAsync(input.Messages.Last().Content, async (content, end) => - { - if (end) + await _platform.GetChatCompletionsAsync(input.Messages.Last().Content, + delegate { - if (content.Length > 0) - { - await OnChunkReceived(outputStream, content); - } - - await OnEventCompleted(outputStream); - } - else + return ""; + }, + delegate + { + return new List(); + }, + async content => { await OnChunkReceived(outputStream, content); - } - }); + }, + async () => + { + await OnEventCompleted(outputStream); + }); } private async Task OnChunkReceived(Stream outputStream, string content) diff --git a/src/WebStarter/Program.cs b/src/WebStarter/Program.cs index dc8e0399..7b8d942c 100644 --- a/src/WebStarter/Program.cs +++ b/src/WebStarter/Program.cs @@ -12,7 +12,8 @@ builder.Services.AddHttpContextAccessor(); // Add BotSharp builder.Services.AddBotSharp(); -builder.Services.AddLlamaSharp(builder.Configuration); +// builder.Services.AddLlamaSharp(builder.Configuration); +builder.Services.AddAzureOpenAi(builder.Configuration); var app = builder.Build(); diff --git a/src/WebStarter/WebStarter.csproj b/src/WebStarter/WebStarter.csproj index fec95e5d..66ecdcbc 100644 --- a/src/WebStarter/WebStarter.csproj +++ b/src/WebStarter/WebStarter.csproj @@ -23,7 +23,9 @@ + + diff --git a/src/WebStarter/appsettings.json b/src/WebStarter/appsettings.json index d430d3f5..337ac416 100644 --- a/src/WebStarter/appsettings.json +++ b/src/WebStarter/appsettings.json @@ -16,5 +16,12 @@ "ModelPath": "C:\\Users\\haipi\\Downloads\\ggml-vic13b-q5_1.bin", "InstructionFile": "Prompts\\chat-with-bob.txt", "MaxContextLength": 512 + }, + + "AzureAi": { + "ApiKey": "", + "Endpoint": "", + "InstructionFile": "Prompts\\chat-with-bob.txt", + "DeploymentModel": "" } }