add open ai plugin
This commit is contained in:
parent
18a08ce58b
commit
97ff19ccc7
15
BotSharp.sln
15
BotSharp.sln
|
|
@ -89,9 +89,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BotSharp.Plugin.MetaGLM", "
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BotSharp.Plugin.AnthropicAI", "src\Plugins\BotSharp.Plugin.AnthropicAI\BotSharp.Plugin.AnthropicAI.csproj", "{806A0B0E-FEFF-420E-B5B2-C9FCBF890A8C}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BotSharp.Plugin.AnthropicAI", "src\Plugins\BotSharp.Plugin.AnthropicAI\BotSharp.Plugin.AnthropicAI.csproj", "{806A0B0E-FEFF-420E-B5B2-C9FCBF890A8C}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BotSharp.ServiceDefaults", "src\BotSharp.ServiceDefaults\BotSharp.ServiceDefaults.csproj", "{6406DC61-0F30-42E8-A1DB-B38CDF454273}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BotSharp.ServiceDefaults", "src\BotSharp.ServiceDefaults\BotSharp.ServiceDefaults.csproj", "{6406DC61-0F30-42E8-A1DB-B38CDF454273}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BotSharp.AppHost", "src\BotSharp.AppHost\BotSharp.AppHost.csproj", "{E04FBBEF-744E-4EF3-B634-42AD9F8B68B1}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BotSharp.AppHost", "src\BotSharp.AppHost\BotSharp.AppHost.csproj", "{E04FBBEF-744E-4EF3-B634-42AD9F8B68B1}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BotSharp.Plugin.OpenAI", "src\Plugins\BotSharp.Plugin.OpenAI\BotSharp.Plugin.OpenAI.csproj", "{6507D336-3A4D-41D4-81C0-2B900173A5FE}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
|
@ -373,6 +375,14 @@ Global
|
||||||
{E04FBBEF-744E-4EF3-B634-42AD9F8B68B1}.Release|Any CPU.Build.0 = Release|Any CPU
|
{E04FBBEF-744E-4EF3-B634-42AD9F8B68B1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{E04FBBEF-744E-4EF3-B634-42AD9F8B68B1}.Release|x64.ActiveCfg = Release|Any CPU
|
{E04FBBEF-744E-4EF3-B634-42AD9F8B68B1}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
{E04FBBEF-744E-4EF3-B634-42AD9F8B68B1}.Release|x64.Build.0 = Release|Any CPU
|
{E04FBBEF-744E-4EF3-B634-42AD9F8B68B1}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{6507D336-3A4D-41D4-81C0-2B900173A5FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{6507D336-3A4D-41D4-81C0-2B900173A5FE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{6507D336-3A4D-41D4-81C0-2B900173A5FE}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{6507D336-3A4D-41D4-81C0-2B900173A5FE}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{6507D336-3A4D-41D4-81C0-2B900173A5FE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{6507D336-3A4D-41D4-81C0-2B900173A5FE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{6507D336-3A4D-41D4-81C0-2B900173A5FE}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{6507D336-3A4D-41D4-81C0-2B900173A5FE}.Release|x64.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
@ -417,6 +427,7 @@ Global
|
||||||
{289E25C8-63F1-4D52-9909-207724DB40CB} = {D5293208-2BEF-42FC-A64C-5954F61720BA}
|
{289E25C8-63F1-4D52-9909-207724DB40CB} = {D5293208-2BEF-42FC-A64C-5954F61720BA}
|
||||||
{CCF745F2-0C95-4ED0-983B-507C528B39EA} = {D5293208-2BEF-42FC-A64C-5954F61720BA}
|
{CCF745F2-0C95-4ED0-983B-507C528B39EA} = {D5293208-2BEF-42FC-A64C-5954F61720BA}
|
||||||
{806A0B0E-FEFF-420E-B5B2-C9FCBF890A8C} = {D5293208-2BEF-42FC-A64C-5954F61720BA}
|
{806A0B0E-FEFF-420E-B5B2-C9FCBF890A8C} = {D5293208-2BEF-42FC-A64C-5954F61720BA}
|
||||||
|
{6507D336-3A4D-41D4-81C0-2B900173A5FE} = {D5293208-2BEF-42FC-A64C-5954F61720BA}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {A9969D89-C98B-40A5-A12B-FC87E55B3A19}
|
SolutionGuid = {A9969D89-C98B-40A5-A12B-FC87E55B3A19}
|
||||||
|
|
|
||||||
|
|
@ -116,7 +116,7 @@ public class InstructModeController : ControllerBase
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var completion = CompletionProvider.GetImageGeneration(_services, provider: input.Provider ?? "openai",
|
var completion = CompletionProvider.GetImageGeneration(_services, provider: input.Provider ?? "openai",
|
||||||
modelId: input.ModelId ?? "dall-e", imageGenerate: true);
|
model: input.Model ?? "dall-e-3", imageGenerate: true);
|
||||||
var message = await completion.GetImageGeneration(new Agent()
|
var message = await completion.GetImageGeneration(new Agent()
|
||||||
{
|
{
|
||||||
Id = Guid.Empty.ToString(),
|
Id = Guid.Empty.ToString(),
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,8 @@ namespace BotSharp.Platform.AzureAi;
|
||||||
public class AzureOpenAiPlugin : IBotSharpPlugin
|
public class AzureOpenAiPlugin : IBotSharpPlugin
|
||||||
{
|
{
|
||||||
public string Id => "65185362-392c-44fd-a023-95a198824436";
|
public string Id => "65185362-392c-44fd-a023-95a198824436";
|
||||||
public string Name => "OpenAI/ Azure OpenAI";
|
public string Name => "Azure OpenAI";
|
||||||
public string Description => "OpenAI/ Azure OpenAI Service including text generation, text to image and other AI services.";
|
public string Description => "Azure OpenAI Service including text generation, text to image and other AI services.";
|
||||||
public string IconUrl => "https://nanfor.com/cdn/shop/files/cursos-propios-Azure-openAI.jpg?v=1692877741";
|
public string IconUrl => "https://nanfor.com/cdn/shop/files/cursos-propios-Azure-openAI.jpg?v=1692877741";
|
||||||
|
|
||||||
public void RegisterDI(IServiceCollection services, IConfiguration config)
|
public void RegisterDI(IServiceCollection services, IConfiguration config)
|
||||||
|
|
@ -27,12 +27,8 @@ public class AzureOpenAiPlugin : IBotSharpPlugin
|
||||||
});
|
});
|
||||||
|
|
||||||
services.AddScoped<ITextCompletion, TextCompletionProvider>();
|
services.AddScoped<ITextCompletion, TextCompletionProvider>();
|
||||||
services.AddScoped<ITextCompletion, OpenAiTextCompletionProvider>();
|
|
||||||
services.AddScoped<IChatCompletion, ChatCompletionProvider>();
|
services.AddScoped<IChatCompletion, ChatCompletionProvider>();
|
||||||
services.AddScoped<IChatCompletion, OpenAiChatCompletionProvider>();
|
|
||||||
services.AddScoped<IImageGeneration, ImageGenerationProvider>();
|
services.AddScoped<IImageGeneration, ImageGenerationProvider>();
|
||||||
services.AddScoped<IImageGeneration, OpenAiImageGenerationProvider>();
|
|
||||||
services.AddScoped<ITextEmbedding, TextEmbeddingProvider>();
|
services.AddScoped<ITextEmbedding, TextEmbeddingProvider>();
|
||||||
services.AddScoped<ITextEmbedding, OpenAiTextEmbeddingProvider>();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace BotSharp.Plugin.AzureOpenAI.Models;
|
|
||||||
|
|
||||||
public class OpenAiTextCompletionRequest : TextCompletionRequest
|
|
||||||
{
|
|
||||||
[JsonPropertyName("model")]
|
|
||||||
public string Model { get; set; } = string.Empty;
|
|
||||||
}
|
|
||||||
|
|
@ -4,7 +4,6 @@ namespace BotSharp.Plugin.AzureOpenAI.Models;
|
||||||
|
|
||||||
public class TextCompletionRequest
|
public class TextCompletionRequest
|
||||||
{
|
{
|
||||||
|
|
||||||
[JsonPropertyName("prompt")]
|
[JsonPropertyName("prompt")]
|
||||||
public string Prompt { get; set; } = string.Empty;
|
public string Prompt { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,8 @@ public class ChatCompletionProvider : IChatCompletion
|
||||||
|
|
||||||
public virtual string Provider => "azure-openai";
|
public virtual string Provider => "azure-openai";
|
||||||
|
|
||||||
public ChatCompletionProvider(AzureOpenAiSettings settings,
|
public ChatCompletionProvider(
|
||||||
|
AzureOpenAiSettings settings,
|
||||||
ILogger<ChatCompletionProvider> logger,
|
ILogger<ChatCompletionProvider> logger,
|
||||||
IServiceProvider services)
|
IServiceProvider services)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
namespace BotSharp.Plugin.AzureOpenAI.Providers.Chat;
|
|
||||||
|
|
||||||
public class OpenAiChatCompletionProvider : ChatCompletionProvider
|
|
||||||
{
|
|
||||||
public override string Provider => "openai";
|
|
||||||
|
|
||||||
public OpenAiChatCompletionProvider(AzureOpenAiSettings settings,
|
|
||||||
ILogger<OpenAiChatCompletionProvider> logger,
|
|
||||||
IServiceProvider services) : base(settings, logger, services)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
namespace BotSharp.Plugin.AzureOpenAI.Providers.Embedding;
|
|
||||||
|
|
||||||
public class OpenAiTextEmbeddingProvider : TextEmbeddingProvider
|
|
||||||
{
|
|
||||||
public override string Provider => "openai";
|
|
||||||
|
|
||||||
public OpenAiTextEmbeddingProvider(AzureOpenAiSettings settings,
|
|
||||||
ILogger<OpenAiTextEmbeddingProvider> logger,
|
|
||||||
IServiceProvider services) : base(settings, logger, services) { }
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
using BotSharp.Abstraction.Files.Models;
|
|
||||||
using OpenAI.Images;
|
using OpenAI.Images;
|
||||||
|
|
||||||
namespace BotSharp.Plugin.AzureOpenAI.Providers.Image;
|
namespace BotSharp.Plugin.AzureOpenAI.Providers.Image;
|
||||||
|
|
@ -10,7 +9,7 @@ public class ImageGenerationProvider : IImageGeneration
|
||||||
protected readonly ILogger _logger;
|
protected readonly ILogger _logger;
|
||||||
|
|
||||||
private const int DEFAULT_IMAGE_COUNT = 1;
|
private const int DEFAULT_IMAGE_COUNT = 1;
|
||||||
private const int IMAGE_COUNT_LIMIT = 3;
|
private const int IMAGE_COUNT_LIMIT = 5;
|
||||||
|
|
||||||
protected string _model;
|
protected string _model;
|
||||||
|
|
||||||
|
|
@ -44,7 +43,6 @@ public class ImageGenerationProvider : IImageGeneration
|
||||||
var response = imageClient.GenerateImages(prompt, imageCount, options);
|
var response = imageClient.GenerateImages(prompt, imageCount, options);
|
||||||
var values = response.Value;
|
var values = response.Value;
|
||||||
|
|
||||||
var content = string.Empty;
|
|
||||||
var images = new List<ImageGeneration>();
|
var images = new List<ImageGeneration>();
|
||||||
foreach (var value in values)
|
foreach (var value in values)
|
||||||
{
|
{
|
||||||
|
|
@ -67,9 +65,9 @@ public class ImageGenerationProvider : IImageGeneration
|
||||||
}
|
}
|
||||||
|
|
||||||
images.Add(image);
|
images.Add(image);
|
||||||
content += $"{image.Description}\r\n";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var content = string.Join("\r\n", images.Select(x => x.Description));
|
||||||
var responseMessage = new RoleDialogModel(AgentRole.Assistant, content)
|
var responseMessage = new RoleDialogModel(AgentRole.Assistant, content)
|
||||||
{
|
{
|
||||||
CurrentAgentId = agent.Id,
|
CurrentAgentId = agent.Id,
|
||||||
|
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
namespace BotSharp.Plugin.AzureOpenAI.Providers.Image;
|
|
||||||
|
|
||||||
public class OpenAiImageGenerationProvider : ImageGenerationProvider
|
|
||||||
{
|
|
||||||
public override string Provider => "openai";
|
|
||||||
|
|
||||||
public OpenAiImageGenerationProvider(AzureOpenAiSettings settings,
|
|
||||||
ILogger<OpenAiImageGenerationProvider> logger,
|
|
||||||
IServiceProvider services) : base(settings, logger, services)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,19 +1,15 @@
|
||||||
using Azure.AI.OpenAI;
|
using Azure.AI.OpenAI;
|
||||||
using Azure;
|
using Azure;
|
||||||
using OpenAI;
|
|
||||||
using System.ClientModel;
|
|
||||||
|
|
||||||
namespace BotSharp.Plugin.AzureOpenAI.Providers;
|
namespace BotSharp.Plugin.AzureOpenAI.Providers;
|
||||||
|
|
||||||
public class ProviderHelper
|
public class ProviderHelper
|
||||||
{
|
{
|
||||||
public static OpenAIClient GetClient(string provider, string model, IServiceProvider services)
|
public static AzureOpenAIClient GetClient(string provider, string model, IServiceProvider services)
|
||||||
{
|
{
|
||||||
var settingsService = services.GetRequiredService<ILlmProviderService>();
|
var settingsService = services.GetRequiredService<ILlmProviderService>();
|
||||||
var settings = settingsService.GetSetting(provider, model);
|
var settings = settingsService.GetSetting(provider, model);
|
||||||
var client = provider == "openai" ?
|
var client = new AzureOpenAIClient(new Uri(settings.Endpoint), new AzureKeyCredential(settings.ApiKey));
|
||||||
new OpenAIClient(new ApiKeyCredential(settings.ApiKey)) :
|
|
||||||
new AzureOpenAIClient(new Uri(settings.Endpoint), new AzureKeyCredential(settings.ApiKey));
|
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,72 +0,0 @@
|
||||||
using BotSharp.Abstraction.MLTasks.Settings;
|
|
||||||
using BotSharp.Plugin.AzureOpenAI.Models;
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Net.Mime;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.Json;
|
|
||||||
|
|
||||||
namespace BotSharp.Plugin.AzureOpenAI.Providers.Text;
|
|
||||||
|
|
||||||
public class OpenAiTextCompletionProvider : TextCompletionProvider
|
|
||||||
{
|
|
||||||
private readonly IServiceProvider _services;
|
|
||||||
private readonly ILogger<OpenAiTextCompletionProvider> _logger;
|
|
||||||
|
|
||||||
public override string Provider => "openai";
|
|
||||||
|
|
||||||
public OpenAiTextCompletionProvider(AzureOpenAiSettings settings,
|
|
||||||
ILogger<OpenAiTextCompletionProvider> logger,
|
|
||||||
IServiceProvider services) : base(settings, logger, services)
|
|
||||||
{
|
|
||||||
_services = services;
|
|
||||||
_logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override async Task<TextCompletionResponse> GetTextCompletion(string apiUrl, string apiKey, string prompt, float temperature, int maxTokens = 256)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var http = _services.GetRequiredService<IHttpClientFactory>();
|
|
||||||
using var httpClient = http.CreateClient();
|
|
||||||
AddHeader(httpClient, apiKey);
|
|
||||||
|
|
||||||
var request = new OpenAiTextCompletionRequest
|
|
||||||
{
|
|
||||||
Model = _model,
|
|
||||||
Prompt = prompt,
|
|
||||||
MaxTokens = maxTokens,
|
|
||||||
Temperature = temperature
|
|
||||||
};
|
|
||||||
var data = JsonSerializer.Serialize(request, _jsonOptions);
|
|
||||||
var httpRequest = new HttpRequestMessage
|
|
||||||
{
|
|
||||||
Method = HttpMethod.Post,
|
|
||||||
RequestUri = new Uri(apiUrl),
|
|
||||||
Content = new StringContent(data, Encoding.UTF8, MediaTypeNames.Application.Json)
|
|
||||||
};
|
|
||||||
var rawResponse = await httpClient.SendAsync(httpRequest);
|
|
||||||
rawResponse.EnsureSuccessStatusCode();
|
|
||||||
|
|
||||||
var responseStr = await rawResponse.Content.ReadAsStringAsync();
|
|
||||||
var response = JsonSerializer.Deserialize<TextCompletionResponse>(responseStr, _jsonOptions);
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError($"Error when {Provider}-{_model} generating text... {ex.Message}");
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override string BuildApiUrl(LlmModelSetting modelSetting)
|
|
||||||
{
|
|
||||||
var endpoint = modelSetting.Endpoint.EndsWith("/") ?
|
|
||||||
modelSetting.Endpoint.Substring(0, modelSetting.Endpoint.Length - 1) : modelSetting.Endpoint;
|
|
||||||
return endpoint ?? string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void AddHeader(HttpClient httpClient, string apiKey)
|
|
||||||
{
|
|
||||||
httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {apiKey}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
using BotSharp.Abstraction.MLTasks.Settings;
|
using BotSharp.Abstraction.MLTasks.Settings;
|
||||||
using BotSharp.Plugin.AzureOpenAI.Models;
|
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Net.Mime;
|
using System.Net.Mime;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
@ -96,7 +95,7 @@ public class TextCompletionProvider : ITextCompletion
|
||||||
_model = model;
|
_model = model;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual async Task<TextCompletionResponse> GetTextCompletion(string apiUrl, string apiKey, string prompt, float temperature, int maxTokens = 256)
|
private async Task<TextCompletionResponse> GetTextCompletion(string apiUrl, string apiKey, string prompt, float temperature, int maxTokens = 256)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
@ -117,10 +116,10 @@ public class TextCompletionProvider : ITextCompletion
|
||||||
RequestUri = new Uri(apiUrl),
|
RequestUri = new Uri(apiUrl),
|
||||||
Content = new StringContent(data, Encoding.UTF8, MediaTypeNames.Application.Json)
|
Content = new StringContent(data, Encoding.UTF8, MediaTypeNames.Application.Json)
|
||||||
};
|
};
|
||||||
var rawResponse = await httpClient.SendAsync(httpRequest);
|
|
||||||
rawResponse.EnsureSuccessStatusCode();
|
|
||||||
|
|
||||||
var responseStr = await rawResponse.Content.ReadAsStringAsync();
|
var httpResponse = await httpClient.SendAsync(httpRequest);
|
||||||
|
httpResponse.EnsureSuccessStatusCode();
|
||||||
|
var responseStr = await httpResponse.Content.ReadAsStringAsync();
|
||||||
var response = JsonSerializer.Deserialize<TextCompletionResponse>(responseStr, _jsonOptions);
|
var response = JsonSerializer.Deserialize<TextCompletionResponse>(responseStr, _jsonOptions);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
@ -131,7 +130,7 @@ public class TextCompletionProvider : ITextCompletion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual string BuildApiUrl(LlmModelSetting modelSetting)
|
private string BuildApiUrl(LlmModelSetting modelSetting)
|
||||||
{
|
{
|
||||||
var url = string.Empty;
|
var url = string.Empty;
|
||||||
var endpoint = modelSetting.Endpoint.EndsWith("/") ?
|
var endpoint = modelSetting.Endpoint.EndsWith("/") ?
|
||||||
|
|
@ -141,7 +140,7 @@ public class TextCompletionProvider : ITextCompletion
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void AddHeader(HttpClient httpClient, string apiKey)
|
private void AddHeader(HttpClient httpClient, string apiKey)
|
||||||
{
|
{
|
||||||
httpClient.DefaultRequestHeaders.Add("api-key", $"{apiKey}");
|
httpClient.DefaultRequestHeaders.Add("api-key", $"{apiKey}");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,4 +14,6 @@ global using BotSharp.Abstraction.MLTasks;
|
||||||
global using BotSharp.Abstraction.Agents;
|
global using BotSharp.Abstraction.Agents;
|
||||||
global using BotSharp.Abstraction.Files;
|
global using BotSharp.Abstraction.Files;
|
||||||
global using BotSharp.Abstraction.Utilities;
|
global using BotSharp.Abstraction.Utilities;
|
||||||
|
global using BotSharp.Abstraction.Files.Models;
|
||||||
|
global using BotSharp.Plugin.AzureOpenAI.Models;
|
||||||
global using BotSharp.Plugin.AzureOpenAI.Settings;
|
global using BotSharp.Plugin.AzureOpenAI.Settings;
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>$(TargetFramework)</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<LangVersion>$(LangVersion)</LangVersion>
|
||||||
|
<VersionPrefix>$(BotSharpVersion)</VersionPrefix>
|
||||||
|
<GeneratePackageOnBuild>$(GeneratePackageOnBuild)</GeneratePackageOnBuild>
|
||||||
|
<GenerateDocumentationFile>$(GenerateDocumentationFile)</GenerateDocumentationFile>
|
||||||
|
<OutputPath>$(SolutionDir)packages</OutputPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="OpenAI" Version="2.0.0-beta.5" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\Infrastructure\BotSharp.Abstraction\BotSharp.Abstraction.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace BotSharp.Plugin.OpenAI.Models;
|
||||||
|
|
||||||
|
public class TextCompletionRequest
|
||||||
|
{
|
||||||
|
[JsonPropertyName("model")]
|
||||||
|
public string Model { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[JsonPropertyName("prompt")]
|
||||||
|
public string Prompt { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[JsonPropertyName("max_tokens")]
|
||||||
|
public int MaxTokens { get; set; } = 256;
|
||||||
|
|
||||||
|
[JsonPropertyName("temperature")]
|
||||||
|
public float Temperature { get; set; } = 0;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace BotSharp.Plugin.OpenAI.Models;
|
||||||
|
|
||||||
|
public class TextCompletionResponse
|
||||||
|
{
|
||||||
|
[JsonPropertyName("id")]
|
||||||
|
public string Id { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("choices")]
|
||||||
|
public IEnumerable<TexCompletionChoice> Choices { get; set; } = new List<TexCompletionChoice>();
|
||||||
|
|
||||||
|
[JsonPropertyName("usage")]
|
||||||
|
public TexCompletionUsage Usage { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TexCompletionChoice
|
||||||
|
{
|
||||||
|
[JsonPropertyName("text")]
|
||||||
|
public string Text { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("finish_reason")]
|
||||||
|
public string FinishReason { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TexCompletionUsage
|
||||||
|
{
|
||||||
|
[JsonPropertyName("prompt_tokens")]
|
||||||
|
public int PromptTokens { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("completion_tokens")]
|
||||||
|
public int CompletionTokens { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("total_tokens")]
|
||||||
|
public int TotalTokens { get; set; }
|
||||||
|
}
|
||||||
34
src/Plugins/BotSharp.Plugin.OpenAI/OpenAiPlugin.cs
Normal file
34
src/Plugins/BotSharp.Plugin.OpenAI/OpenAiPlugin.cs
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
using BotSharp.Abstraction.Plugins;
|
||||||
|
using BotSharp.Abstraction.Settings;
|
||||||
|
using BotSharp.Plugin.OpenAI.Providers.Embedding;
|
||||||
|
using BotSharp.Plugin.OpenAI.Providers.Image;
|
||||||
|
using BotSharp.Plugin.OpenAI.Providers.Text;
|
||||||
|
using BotSharp.Plugin.OpenAI.Providers.Chat;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
|
||||||
|
namespace BotSharp.Plugin.OpenAI;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// OpenAI Service
|
||||||
|
/// </summary>
|
||||||
|
public class OpenAiPlugin : IBotSharpPlugin
|
||||||
|
{
|
||||||
|
public string Id => "a743e90f-7cbc-4e47-b8a0-2f8e44f894c7";
|
||||||
|
public string Name => "OpenAI";
|
||||||
|
public string Description => "OpenAI Service including text generation, text to image and other AI services.";
|
||||||
|
public string IconUrl => "https://logosandtypes.com/wp-content/uploads/2022/07/openai.svg";
|
||||||
|
|
||||||
|
public void RegisterDI(IServiceCollection services, IConfiguration config)
|
||||||
|
{
|
||||||
|
services.AddScoped(provider =>
|
||||||
|
{
|
||||||
|
var settingService = provider.GetRequiredService<ISettingService>();
|
||||||
|
return settingService.Bind<OpenAiSettings>("OpenAi");
|
||||||
|
});
|
||||||
|
|
||||||
|
services.AddScoped<ITextCompletion, TextCompletionProvider>();
|
||||||
|
services.AddScoped<IChatCompletion, ChatCompletionProvider>();
|
||||||
|
services.AddScoped<IImageGeneration, ImageGenerationProvider>();
|
||||||
|
services.AddScoped<ITextEmbedding, TextEmbeddingProvider>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,376 @@
|
||||||
|
using OpenAI.Chat;
|
||||||
|
|
||||||
|
namespace BotSharp.Plugin.OpenAI.Providers.Chat;
|
||||||
|
|
||||||
|
public class ChatCompletionProvider : IChatCompletion
|
||||||
|
{
|
||||||
|
protected readonly OpenAiSettings _settings;
|
||||||
|
protected readonly IServiceProvider _services;
|
||||||
|
protected readonly ILogger<ChatCompletionProvider> _logger;
|
||||||
|
|
||||||
|
protected string _model;
|
||||||
|
|
||||||
|
public virtual string Provider => "openai";
|
||||||
|
|
||||||
|
public ChatCompletionProvider(
|
||||||
|
OpenAiSettings settings,
|
||||||
|
ILogger<ChatCompletionProvider> logger,
|
||||||
|
IServiceProvider services)
|
||||||
|
{
|
||||||
|
_settings = settings;
|
||||||
|
_logger = logger;
|
||||||
|
_services = services;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<RoleDialogModel> GetChatCompletions(Agent agent, List<RoleDialogModel> conversations)
|
||||||
|
{
|
||||||
|
var contentHooks = _services.GetServices<IContentGeneratingHook>().ToList();
|
||||||
|
|
||||||
|
// Before chat completion hook
|
||||||
|
foreach (var hook in contentHooks)
|
||||||
|
{
|
||||||
|
await hook.BeforeGenerating(agent, conversations);
|
||||||
|
}
|
||||||
|
|
||||||
|
var client = ProviderHelper.GetClient(Provider, _model, _services);
|
||||||
|
var chatClient = client.GetChatClient(_model);
|
||||||
|
var (prompt, messages, options) = PrepareOptions(agent, conversations);
|
||||||
|
|
||||||
|
var response = chatClient.CompleteChat(messages, options);
|
||||||
|
var value = response.Value;
|
||||||
|
var reason = value.FinishReason;
|
||||||
|
var content = value.Content;
|
||||||
|
var text = content.FirstOrDefault()?.Text ?? string.Empty;
|
||||||
|
|
||||||
|
RoleDialogModel responseMessage;
|
||||||
|
if (reason == ChatFinishReason.FunctionCall)
|
||||||
|
{
|
||||||
|
responseMessage = new RoleDialogModel(AgentRole.Function, text)
|
||||||
|
{
|
||||||
|
CurrentAgentId = agent.Id,
|
||||||
|
MessageId = conversations.Last().MessageId,
|
||||||
|
FunctionName = value.FunctionCall.FunctionName,
|
||||||
|
FunctionArgs = value.FunctionCall.FunctionArguments
|
||||||
|
};
|
||||||
|
|
||||||
|
// Somethings LLM will generate a function name with agent name.
|
||||||
|
if (!string.IsNullOrEmpty(responseMessage.FunctionName))
|
||||||
|
{
|
||||||
|
responseMessage.FunctionName = responseMessage.FunctionName.Split('.').Last();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (reason == ChatFinishReason.ToolCalls)
|
||||||
|
{
|
||||||
|
var toolCall = value.ToolCalls.FirstOrDefault();
|
||||||
|
responseMessage = new RoleDialogModel(AgentRole.Function, text)
|
||||||
|
{
|
||||||
|
CurrentAgentId = agent.Id,
|
||||||
|
MessageId = conversations.Last().MessageId,
|
||||||
|
FunctionName = toolCall?.FunctionName,
|
||||||
|
FunctionArgs = toolCall?.FunctionArguments
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
responseMessage = new RoleDialogModel(AgentRole.Assistant, text)
|
||||||
|
{
|
||||||
|
CurrentAgentId = agent.Id,
|
||||||
|
MessageId = conversations.Last().MessageId
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// After chat completion hook
|
||||||
|
foreach (var hook in contentHooks)
|
||||||
|
{
|
||||||
|
await hook.AfterGenerated(responseMessage, new TokenStatsModel
|
||||||
|
{
|
||||||
|
Prompt = prompt,
|
||||||
|
Provider = Provider,
|
||||||
|
Model = _model,
|
||||||
|
PromptCount = response.Value.Usage.InputTokens,
|
||||||
|
CompletionCount = response.Value.Usage.OutputTokens
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return responseMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> GetChatCompletionsAsync(Agent agent,
|
||||||
|
List<RoleDialogModel> conversations,
|
||||||
|
Func<RoleDialogModel, Task> onMessageReceived,
|
||||||
|
Func<RoleDialogModel, Task> onFunctionExecuting)
|
||||||
|
{
|
||||||
|
var hooks = _services.GetServices<IContentGeneratingHook>().ToList();
|
||||||
|
|
||||||
|
// Before chat completion hook
|
||||||
|
foreach (var hook in hooks)
|
||||||
|
{
|
||||||
|
await hook.BeforeGenerating(agent, conversations);
|
||||||
|
}
|
||||||
|
|
||||||
|
var client = ProviderHelper.GetClient(Provider, _model, _services);
|
||||||
|
var chatClient = client.GetChatClient(_model);
|
||||||
|
var (prompt, messages, options) = PrepareOptions(agent, conversations);
|
||||||
|
|
||||||
|
var response = await chatClient.CompleteChatAsync(messages, options);
|
||||||
|
var value = response.Value;
|
||||||
|
var reason = value.FinishReason;
|
||||||
|
var content = value.Content;
|
||||||
|
var text = content.FirstOrDefault()?.Text ?? string.Empty;
|
||||||
|
|
||||||
|
var msg = new RoleDialogModel(AgentRole.Assistant, text)
|
||||||
|
{
|
||||||
|
CurrentAgentId = agent.Id
|
||||||
|
};
|
||||||
|
|
||||||
|
// After chat completion hook
|
||||||
|
foreach (var hook in hooks)
|
||||||
|
{
|
||||||
|
await hook.AfterGenerated(msg, new TokenStatsModel
|
||||||
|
{
|
||||||
|
Prompt = prompt,
|
||||||
|
Provider = Provider,
|
||||||
|
Model = _model,
|
||||||
|
PromptCount = response.Value.Usage.InputTokens,
|
||||||
|
CompletionCount = response.Value.Usage.OutputTokens
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reason == ChatFinishReason.FunctionCall)
|
||||||
|
{
|
||||||
|
_logger.LogInformation($"[{agent.Name}]: {value.FunctionCall.FunctionName}({value.FunctionCall.FunctionArguments})");
|
||||||
|
|
||||||
|
var funcContextIn = new RoleDialogModel(AgentRole.Function, text)
|
||||||
|
{
|
||||||
|
CurrentAgentId = agent.Id,
|
||||||
|
FunctionName = value.FunctionCall?.FunctionName,
|
||||||
|
FunctionArgs = value.FunctionCall?.FunctionArguments
|
||||||
|
};
|
||||||
|
|
||||||
|
// Somethings LLM will generate a function name with agent name.
|
||||||
|
if (!string.IsNullOrEmpty(funcContextIn.FunctionName))
|
||||||
|
{
|
||||||
|
funcContextIn.FunctionName = funcContextIn.FunctionName.Split('.').Last();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute functions
|
||||||
|
await onFunctionExecuting(funcContextIn);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Text response received
|
||||||
|
await onMessageReceived(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> GetChatCompletionsStreamingAsync(Agent agent, List<RoleDialogModel> conversations, Func<RoleDialogModel, Task> onMessageReceived)
|
||||||
|
{
|
||||||
|
var client = ProviderHelper.GetClient(Provider, _model, _services);
|
||||||
|
var chatClient = client.GetChatClient(_model);
|
||||||
|
var (prompt, messages, options) = PrepareOptions(agent, conversations);
|
||||||
|
|
||||||
|
var response = chatClient.CompleteChatStreamingAsync(messages, options);
|
||||||
|
|
||||||
|
await foreach (var choice in response)
|
||||||
|
{
|
||||||
|
if (choice.FinishReason == ChatFinishReason.FunctionCall)
|
||||||
|
{
|
||||||
|
Console.Write(choice.FunctionCallUpdate?.FunctionArgumentsUpdate);
|
||||||
|
|
||||||
|
await onMessageReceived(new RoleDialogModel(AgentRole.Assistant, choice.FunctionCallUpdate?.FunctionArgumentsUpdate));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (choice.ContentUpdate.IsNullOrEmpty()) continue;
|
||||||
|
|
||||||
|
_logger.LogInformation(choice.ContentUpdate[0]?.Text);
|
||||||
|
|
||||||
|
await onMessageReceived(new RoleDialogModel(choice.Role.ToString(), choice.ContentUpdate[0]?.Text ?? string.Empty));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected (string, IEnumerable<ChatMessage>, ChatCompletionOptions) PrepareOptions(Agent agent, List<RoleDialogModel> conversations)
|
||||||
|
{
|
||||||
|
var agentService = _services.GetRequiredService<IAgentService>();
|
||||||
|
var fileService = _services.GetRequiredService<IBotSharpFileService>();
|
||||||
|
var state = _services.GetRequiredService<IConversationStateService>();
|
||||||
|
var settingsService = _services.GetRequiredService<ILlmProviderService>();
|
||||||
|
var settings = settingsService.GetSetting(Provider, _model);
|
||||||
|
var allowMultiModal = settings != null && settings.MultiModal;
|
||||||
|
|
||||||
|
var messages = new List<ChatMessage>();
|
||||||
|
|
||||||
|
var temperature = float.Parse(state.GetState("temperature", "0.0"));
|
||||||
|
var maxTokens = int.Parse(state.GetState("max_tokens", "1024"));
|
||||||
|
var options = new ChatCompletionOptions()
|
||||||
|
{
|
||||||
|
Temperature = temperature,
|
||||||
|
MaxTokens = maxTokens
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var function in agent.Functions)
|
||||||
|
{
|
||||||
|
if (!agentService.RenderFunction(agent, function)) continue;
|
||||||
|
|
||||||
|
var property = agentService.RenderFunctionProperty(agent, function);
|
||||||
|
|
||||||
|
options.Tools.Add(ChatTool.CreateFunctionTool(
|
||||||
|
functionName: function.Name,
|
||||||
|
functionDescription: function.Description,
|
||||||
|
functionParameters: BinaryData.FromObjectAsJson(property)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(agent.Instruction))
|
||||||
|
{
|
||||||
|
var instruction = agentService.RenderedInstruction(agent);
|
||||||
|
messages.Add(new SystemChatMessage(instruction));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(agent.Knowledges))
|
||||||
|
{
|
||||||
|
messages.Add(new SystemChatMessage(agent.Knowledges));
|
||||||
|
}
|
||||||
|
|
||||||
|
var samples = ProviderHelper.GetChatSamples(agent.Samples);
|
||||||
|
foreach (var sample in samples)
|
||||||
|
{
|
||||||
|
messages.Add(sample.Role == AgentRole.User ? new UserChatMessage(sample.Content) : new AssistantChatMessage(sample.Content));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var message in conversations)
|
||||||
|
{
|
||||||
|
if (message.Role == AgentRole.Function)
|
||||||
|
{
|
||||||
|
messages.Add(new AssistantChatMessage(string.Empty)
|
||||||
|
{
|
||||||
|
FunctionCall = new ChatFunctionCall(message.FunctionName, message.FunctionArgs ?? string.Empty)
|
||||||
|
});
|
||||||
|
|
||||||
|
messages.Add(new FunctionChatMessage(message.FunctionName, message.Content));
|
||||||
|
}
|
||||||
|
else if (message.Role == AgentRole.User)
|
||||||
|
{
|
||||||
|
var text = !string.IsNullOrWhiteSpace(message.Payload) ? message.Payload : message.Content;
|
||||||
|
var textPart = ChatMessageContentPart.CreateTextMessageContentPart(text);
|
||||||
|
var chat = new UserChatMessage(textPart)
|
||||||
|
{
|
||||||
|
ParticipantName = message.FunctionName
|
||||||
|
};
|
||||||
|
|
||||||
|
if (allowMultiModal)
|
||||||
|
{
|
||||||
|
if (!message.Files.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
foreach (var file in message.Files)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(file.FileUrl))
|
||||||
|
{
|
||||||
|
var uri = new Uri(file.FileUrl);
|
||||||
|
var contentPart = ChatMessageContentPart.CreateImageMessageContentPart(uri, ImageChatMessageContentPartDetail.Low);
|
||||||
|
chat = new UserChatMessage(textPart, contentPart) { ParticipantName = message.FunctionName };
|
||||||
|
}
|
||||||
|
else if (!string.IsNullOrEmpty(file.FileData))
|
||||||
|
{
|
||||||
|
var (contentType, bytes) = fileService.GetFileInfoFromData(file.FileData);
|
||||||
|
var contentPart = ChatMessageContentPart.CreateImageMessageContentPart(BinaryData.FromBytes(bytes), contentType, ImageChatMessageContentPartDetail.Low);
|
||||||
|
chat = new UserChatMessage(textPart, contentPart) { ParticipantName = message.FunctionName };
|
||||||
|
}
|
||||||
|
else if (!string.IsNullOrEmpty(file.FileStorageUrl))
|
||||||
|
{
|
||||||
|
var contentType = fileService.GetFileContentType(file.FileStorageUrl);
|
||||||
|
using var stream = File.OpenRead(file.FileStorageUrl);
|
||||||
|
var contentPart = ChatMessageContentPart.CreateImageMessageContentPart(BinaryData.FromStream(stream), contentType, ImageChatMessageContentPartDetail.Low);
|
||||||
|
chat = new UserChatMessage(textPart, contentPart) { ParticipantName = message.FunctionName };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
messages.Add(chat);
|
||||||
|
}
|
||||||
|
else if (message.Role == AgentRole.Assistant)
|
||||||
|
{
|
||||||
|
messages.Add(new AssistantChatMessage(message.Content));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var prompt = GetPrompt(messages, options);
|
||||||
|
return (prompt, messages, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private string GetPrompt(IEnumerable<ChatMessage> messages, ChatCompletionOptions options)
|
||||||
|
{
|
||||||
|
var prompt = string.Empty;
|
||||||
|
|
||||||
|
if (!messages.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
// System instruction
|
||||||
|
var verbose = string.Join("\r\n", messages
|
||||||
|
.Select(x => x as SystemChatMessage)
|
||||||
|
.Where(x => x != null)
|
||||||
|
.Select(x =>
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(x.ParticipantName))
|
||||||
|
{
|
||||||
|
// To display Agent name in log
|
||||||
|
return $"[{x.ParticipantName}]: {x.Content.FirstOrDefault()?.Text ?? string.Empty}";
|
||||||
|
}
|
||||||
|
return $"{AgentRole.System}: {x.Content.FirstOrDefault()?.Text ?? string.Empty}";
|
||||||
|
}));
|
||||||
|
prompt += $"{verbose}\r\n";
|
||||||
|
|
||||||
|
prompt += "\r\n[CONVERSATION]";
|
||||||
|
verbose = string.Join("\r\n", messages
|
||||||
|
.Where(x => x as SystemChatMessage == null)
|
||||||
|
.Select(x =>
|
||||||
|
{
|
||||||
|
var fnMessage = x as FunctionChatMessage;
|
||||||
|
if (fnMessage != null)
|
||||||
|
{
|
||||||
|
return $"{AgentRole.Function}: {fnMessage.Content.FirstOrDefault()?.Text ?? string.Empty}";
|
||||||
|
}
|
||||||
|
|
||||||
|
var userMessage = x as UserChatMessage;
|
||||||
|
if (userMessage != null)
|
||||||
|
{
|
||||||
|
var content = x.Content.FirstOrDefault()?.Text ?? string.Empty;
|
||||||
|
return !string.IsNullOrEmpty(userMessage.ParticipantName) && userMessage.ParticipantName != "route_to_agent" ?
|
||||||
|
$"{userMessage.ParticipantName}: {content}" :
|
||||||
|
$"{AgentRole.User}: {content}";
|
||||||
|
}
|
||||||
|
|
||||||
|
var assistMessage = x as AssistantChatMessage;
|
||||||
|
if (assistMessage != null)
|
||||||
|
{
|
||||||
|
return assistMessage.FunctionCall != null ?
|
||||||
|
$"{AgentRole.Assistant}: Call function {assistMessage.FunctionCall.FunctionName}({assistMessage.FunctionCall.FunctionArguments})" :
|
||||||
|
$"{AgentRole.Assistant}: {assistMessage.Content.FirstOrDefault()?.Text ?? string.Empty}";
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Empty;
|
||||||
|
}));
|
||||||
|
prompt += $"\r\n{verbose}\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!options.Tools.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
var functions = string.Join("\r\n", options.Tools.Select(fn =>
|
||||||
|
{
|
||||||
|
return $"\r\n{fn.FunctionName}: {fn.FunctionDescription}\r\n{fn.FunctionParameters}";
|
||||||
|
}));
|
||||||
|
prompt += $"\r\n[FUNCTIONS]{functions}\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return prompt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetModelName(string model)
|
||||||
|
{
|
||||||
|
_model = model;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
using OpenAI.Embeddings;
|
||||||
|
|
||||||
|
namespace BotSharp.Plugin.OpenAI.Providers.Embedding;
|
||||||
|
|
||||||
|
public class TextEmbeddingProvider : ITextEmbedding
|
||||||
|
{
|
||||||
|
protected readonly OpenAiSettings _settings;
|
||||||
|
protected readonly IServiceProvider _services;
|
||||||
|
protected readonly ILogger<TextEmbeddingProvider> _logger;
|
||||||
|
|
||||||
|
private const int DEFAULT_DIMENSION = 1536;
|
||||||
|
protected string _model;
|
||||||
|
|
||||||
|
public virtual string Provider => "openai";
|
||||||
|
|
||||||
|
public int Dimension { get; set; }
|
||||||
|
|
||||||
|
public TextEmbeddingProvider(
|
||||||
|
OpenAiSettings settings,
|
||||||
|
ILogger<TextEmbeddingProvider> logger,
|
||||||
|
IServiceProvider services)
|
||||||
|
{
|
||||||
|
_settings = settings;
|
||||||
|
_logger = logger;
|
||||||
|
_services = services;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<float[]> GetVectorAsync(string text)
|
||||||
|
{
|
||||||
|
var client = ProviderHelper.GetClient(Provider, _model, _services);
|
||||||
|
var embeddingClient = client.GetEmbeddingClient(_model);
|
||||||
|
var options = PrepareOptions();
|
||||||
|
var response = await embeddingClient.GenerateEmbeddingAsync(text, options);
|
||||||
|
var value = response.Value;
|
||||||
|
return value.Vector.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<float[]>> GetVectorsAsync(List<string> texts)
|
||||||
|
{
|
||||||
|
var client = ProviderHelper.GetClient(Provider, _model, _services);
|
||||||
|
var embeddingClient = client.GetEmbeddingClient(_model);
|
||||||
|
var options = PrepareOptions();
|
||||||
|
var response = await embeddingClient.GenerateEmbeddingsAsync(texts, options);
|
||||||
|
var value = response.Value;
|
||||||
|
return value.Select(x => x.Vector.ToArray()).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetModelName(string model)
|
||||||
|
{
|
||||||
|
_model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
private EmbeddingGenerationOptions PrepareOptions()
|
||||||
|
{
|
||||||
|
return new EmbeddingGenerationOptions
|
||||||
|
{
|
||||||
|
Dimensions = GetDimension()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private int GetDimension()
|
||||||
|
{
|
||||||
|
var state = _services.GetRequiredService<IConversationStateService>();
|
||||||
|
var stateDimension = state.GetState("embedding_dimension");
|
||||||
|
var defaultDimension = Dimension > 0 ? Dimension : DEFAULT_DIMENSION;
|
||||||
|
|
||||||
|
if (int.TryParse(stateDimension, out var dimension))
|
||||||
|
{
|
||||||
|
return dimension > 0 ? dimension : defaultDimension;
|
||||||
|
}
|
||||||
|
return defaultDimension;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,222 @@
|
||||||
|
using OpenAI.Images;
|
||||||
|
|
||||||
|
namespace BotSharp.Plugin.OpenAI.Providers.Image;
|
||||||
|
|
||||||
|
public class ImageGenerationProvider : IImageGeneration
|
||||||
|
{
|
||||||
|
protected readonly OpenAiSettings _settings;
|
||||||
|
protected readonly IServiceProvider _services;
|
||||||
|
protected readonly ILogger _logger;
|
||||||
|
|
||||||
|
private const int DEFAULT_IMAGE_COUNT = 1;
|
||||||
|
private const int IMAGE_COUNT_LIMIT = 5;
|
||||||
|
|
||||||
|
protected string _model;
|
||||||
|
|
||||||
|
public virtual string Provider => "openai";
|
||||||
|
|
||||||
|
public ImageGenerationProvider(
|
||||||
|
OpenAiSettings settings,
|
||||||
|
ILogger<ImageGenerationProvider> logger,
|
||||||
|
IServiceProvider services)
|
||||||
|
{
|
||||||
|
_settings = settings;
|
||||||
|
_services = services;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async Task<RoleDialogModel> GetImageGeneration(Agent agent, List<RoleDialogModel> conversations)
|
||||||
|
{
|
||||||
|
var contentHooks = _services.GetServices<IContentGeneratingHook>().ToList();
|
||||||
|
|
||||||
|
// Before
|
||||||
|
foreach (var hook in contentHooks)
|
||||||
|
{
|
||||||
|
await hook.BeforeGenerating(agent, conversations);
|
||||||
|
}
|
||||||
|
|
||||||
|
var client = ProviderHelper.GetClient(Provider, _model, _services);
|
||||||
|
var (prompt, imageCount, options) = PrepareOptions(conversations);
|
||||||
|
var imageClient = client.GetImageClient(_model);
|
||||||
|
|
||||||
|
var response = imageClient.GenerateImages(prompt, imageCount, options);
|
||||||
|
var values = response.Value;
|
||||||
|
|
||||||
|
var images = new List<ImageGeneration>();
|
||||||
|
foreach (var value in values)
|
||||||
|
{
|
||||||
|
if (value == null) continue;
|
||||||
|
|
||||||
|
var image = new ImageGeneration { Description = value?.RevisedPrompt ?? string.Empty };
|
||||||
|
if (options.ResponseFormat == GeneratedImageFormat.Uri)
|
||||||
|
{
|
||||||
|
image.ImageUrl = value?.ImageUri?.AbsoluteUri ?? string.Empty;
|
||||||
|
}
|
||||||
|
else if (options.ResponseFormat == GeneratedImageFormat.Bytes)
|
||||||
|
{
|
||||||
|
var base64Str = string.Empty;
|
||||||
|
var bytes = value?.ImageBytes?.ToArray();
|
||||||
|
if (!bytes.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
base64Str = Convert.ToBase64String(bytes);
|
||||||
|
}
|
||||||
|
image.ImageData = base64Str;
|
||||||
|
}
|
||||||
|
|
||||||
|
images.Add(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
var content = string.Join("\r\n", images.Select(x => x.Description));
|
||||||
|
var responseMessage = new RoleDialogModel(AgentRole.Assistant, content)
|
||||||
|
{
|
||||||
|
CurrentAgentId = agent.Id,
|
||||||
|
MessageId = conversations.LastOrDefault()?.MessageId ?? string.Empty,
|
||||||
|
GeneratedImages = images
|
||||||
|
};
|
||||||
|
|
||||||
|
// After
|
||||||
|
foreach (var hook in contentHooks)
|
||||||
|
{
|
||||||
|
await hook.AfterGenerated(responseMessage, new TokenStatsModel
|
||||||
|
{
|
||||||
|
Prompt = prompt,
|
||||||
|
Provider = Provider,
|
||||||
|
Model = _model,
|
||||||
|
PromptCount = prompt.Split(' ', StringSplitOptions.RemoveEmptyEntries).Count(),
|
||||||
|
CompletionCount = content.Split(' ', StringSplitOptions.RemoveEmptyEntries).Count()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return responseMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
private (string, int, ImageGenerationOptions) PrepareOptions(List<RoleDialogModel> conversations)
|
||||||
|
{
|
||||||
|
var prompt = conversations.LastOrDefault()?.Payload ?? conversations.LastOrDefault()?.Content ?? string.Empty;
|
||||||
|
|
||||||
|
var state = _services.GetRequiredService<IConversationStateService>();
|
||||||
|
var size = state.GetState("image_size");
|
||||||
|
var quality = state.GetState("image_quality");
|
||||||
|
var style = state.GetState("image_style");
|
||||||
|
var format = state.GetState("image_format");
|
||||||
|
var count = GetImageCount(state.GetState("image_count", "1"));
|
||||||
|
|
||||||
|
var options = new ImageGenerationOptions
|
||||||
|
{
|
||||||
|
Size = GetImageSize(size),
|
||||||
|
Quality = GetImageQuality(quality),
|
||||||
|
Style = GetImageStyle(style),
|
||||||
|
ResponseFormat = GetImageFormat(format)
|
||||||
|
};
|
||||||
|
return (prompt, count, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetModelName(string model)
|
||||||
|
{
|
||||||
|
_model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
private GeneratedImageSize GetImageSize(string size)
|
||||||
|
{
|
||||||
|
var value = !string.IsNullOrEmpty(size) ? size : "1024x1024";
|
||||||
|
|
||||||
|
GeneratedImageSize retSize;
|
||||||
|
switch (value)
|
||||||
|
{
|
||||||
|
case "256x256":
|
||||||
|
retSize = GeneratedImageSize.W256xH256;
|
||||||
|
break;
|
||||||
|
case "512x512":
|
||||||
|
retSize = GeneratedImageSize.W512xH512;
|
||||||
|
break;
|
||||||
|
case "1024x1024":
|
||||||
|
retSize = GeneratedImageSize.W1024xH1024;
|
||||||
|
break;
|
||||||
|
case "1024x1792":
|
||||||
|
retSize = GeneratedImageSize.W1024xH1792;
|
||||||
|
break;
|
||||||
|
case "1792x1024":
|
||||||
|
retSize = GeneratedImageSize.W1792xH1024;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
retSize = GeneratedImageSize.W1024xH1024;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return retSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
private GeneratedImageQuality GetImageQuality(string quality)
|
||||||
|
{
|
||||||
|
var value = !string.IsNullOrEmpty(quality) ? quality : "standard";
|
||||||
|
|
||||||
|
GeneratedImageQuality retQuality;
|
||||||
|
switch (value)
|
||||||
|
{
|
||||||
|
case "standard":
|
||||||
|
retQuality = GeneratedImageQuality.Standard;
|
||||||
|
break;
|
||||||
|
case "hd":
|
||||||
|
retQuality = GeneratedImageQuality.High;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
retQuality = GeneratedImageQuality.Standard;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return retQuality;
|
||||||
|
}
|
||||||
|
|
||||||
|
private GeneratedImageStyle GetImageStyle(string style)
|
||||||
|
{
|
||||||
|
var value = !string.IsNullOrEmpty(style) ? style : "natural";
|
||||||
|
|
||||||
|
GeneratedImageStyle retStyle;
|
||||||
|
switch (value)
|
||||||
|
{
|
||||||
|
case "natural":
|
||||||
|
retStyle = GeneratedImageStyle.Natural;
|
||||||
|
break;
|
||||||
|
case "vivid":
|
||||||
|
retStyle = GeneratedImageStyle.Vivid;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
retStyle = GeneratedImageStyle.Natural;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return retStyle;
|
||||||
|
}
|
||||||
|
|
||||||
|
private GeneratedImageFormat GetImageFormat(string format)
|
||||||
|
{
|
||||||
|
var value = !string.IsNullOrEmpty(format) ? format : "uri";
|
||||||
|
|
||||||
|
GeneratedImageFormat retFormat;
|
||||||
|
switch (value)
|
||||||
|
{
|
||||||
|
case "uri":
|
||||||
|
retFormat = GeneratedImageFormat.Uri;
|
||||||
|
break;
|
||||||
|
case "bytes":
|
||||||
|
retFormat = GeneratedImageFormat.Bytes;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
retFormat = GeneratedImageFormat.Uri;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return retFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int GetImageCount(string count)
|
||||||
|
{
|
||||||
|
if (!int.TryParse(count, out var retCount))
|
||||||
|
{
|
||||||
|
return DEFAULT_IMAGE_COUNT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return retCount > 0 && retCount <= IMAGE_COUNT_LIMIT ? retCount : DEFAULT_IMAGE_COUNT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
using OpenAI;
|
||||||
|
using System.ClientModel;
|
||||||
|
|
||||||
|
namespace BotSharp.Plugin.OpenAI.Providers;
|
||||||
|
|
||||||
|
public class ProviderHelper
|
||||||
|
{
|
||||||
|
public static OpenAIClient GetClient(string provider, string model, IServiceProvider services)
|
||||||
|
{
|
||||||
|
var settingsService = services.GetRequiredService<ILlmProviderService>();
|
||||||
|
var settings = settingsService.GetSetting(provider, model);
|
||||||
|
var client = new OpenAIClient(new ApiKeyCredential(settings.ApiKey));
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<RoleDialogModel> GetChatSamples(List<string> lines)
|
||||||
|
{
|
||||||
|
var samples = new List<RoleDialogModel>();
|
||||||
|
|
||||||
|
for (int i = 0; i < lines.Count; i++)
|
||||||
|
{
|
||||||
|
var line = lines[i];
|
||||||
|
if (string.IsNullOrEmpty(line.Trim()))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var role = line.Substring(0, line.IndexOf(' ') - 1).Trim();
|
||||||
|
var content = line.Substring(line.IndexOf(' ') + 1).Trim();
|
||||||
|
|
||||||
|
// comments
|
||||||
|
if (role == "##")
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
samples.Add(new RoleDialogModel(role, content));
|
||||||
|
}
|
||||||
|
|
||||||
|
return samples;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,145 @@
|
||||||
|
using BotSharp.Abstraction.MLTasks.Settings;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Net.Mime;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace BotSharp.Plugin.OpenAI.Providers.Text;
|
||||||
|
|
||||||
|
public class TextCompletionProvider : ITextCompletion
|
||||||
|
{
|
||||||
|
private readonly IServiceProvider _services;
|
||||||
|
private readonly ILogger<TextCompletionProvider> _logger;
|
||||||
|
private readonly OpenAiSettings _settings;
|
||||||
|
protected string _model;
|
||||||
|
|
||||||
|
protected readonly JsonSerializerOptions _jsonOptions = new JsonSerializerOptions
|
||||||
|
{
|
||||||
|
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||||
|
PropertyNameCaseInsensitive = true,
|
||||||
|
WriteIndented = true,
|
||||||
|
AllowTrailingCommas = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
public virtual string Provider => "openai";
|
||||||
|
|
||||||
|
public TextCompletionProvider(
|
||||||
|
OpenAiSettings settings,
|
||||||
|
ILogger<TextCompletionProvider> logger,
|
||||||
|
IServiceProvider services)
|
||||||
|
{
|
||||||
|
_services = services;
|
||||||
|
_logger = logger;
|
||||||
|
_settings = settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string> GetCompletion(string text, string agentId, string messageId)
|
||||||
|
{
|
||||||
|
var contentHooks = _services.GetServices<IContentGeneratingHook>().ToList();
|
||||||
|
|
||||||
|
// Before chat completion hook
|
||||||
|
var agent = new Agent()
|
||||||
|
{
|
||||||
|
Id = agentId,
|
||||||
|
};
|
||||||
|
var message = new RoleDialogModel(AgentRole.User, text)
|
||||||
|
{
|
||||||
|
CurrentAgentId = agentId,
|
||||||
|
MessageId = messageId
|
||||||
|
};
|
||||||
|
|
||||||
|
Task.WaitAll(contentHooks.Select(hook =>
|
||||||
|
hook.BeforeGenerating(agent,
|
||||||
|
new List<RoleDialogModel>
|
||||||
|
{
|
||||||
|
message
|
||||||
|
})).ToArray());
|
||||||
|
|
||||||
|
var state = _services.GetRequiredService<IConversationStateService>();
|
||||||
|
var temperature = float.Parse(state.GetState("temperature", "0.0"));
|
||||||
|
|
||||||
|
var settingsService = _services.GetRequiredService<ILlmProviderService>();
|
||||||
|
var modelSetting = settingsService.GetSetting(Provider, _model);
|
||||||
|
var apiUrl = BuildApiUrl(modelSetting);
|
||||||
|
var apiKey = modelSetting.ApiKey;
|
||||||
|
var response = await GetTextCompletion(apiUrl, apiKey, text, temperature);
|
||||||
|
|
||||||
|
// OpenAI
|
||||||
|
var completion = "";
|
||||||
|
foreach (var t in response.Choices)
|
||||||
|
{
|
||||||
|
completion += t?.Text ?? string.Empty;
|
||||||
|
};
|
||||||
|
|
||||||
|
// After chat completion hook
|
||||||
|
var responseMessage = new RoleDialogModel(AgentRole.Assistant, completion)
|
||||||
|
{
|
||||||
|
CurrentAgentId = agentId,
|
||||||
|
MessageId = messageId
|
||||||
|
};
|
||||||
|
Task.WaitAll(contentHooks.Select(hook =>
|
||||||
|
hook.AfterGenerated(responseMessage, new TokenStatsModel
|
||||||
|
{
|
||||||
|
Prompt = text,
|
||||||
|
Provider = Provider,
|
||||||
|
Model = _model,
|
||||||
|
PromptCount = response.Usage?.PromptTokens ?? default,
|
||||||
|
CompletionCount = response.Usage?.CompletionTokens ?? default
|
||||||
|
})).ToArray());
|
||||||
|
|
||||||
|
return completion.Trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetModelName(string model)
|
||||||
|
{
|
||||||
|
_model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<TextCompletionResponse> GetTextCompletion(string apiUrl, string apiKey, string prompt, float temperature, int maxTokens = 256)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var http = _services.GetRequiredService<IHttpClientFactory>();
|
||||||
|
using var httpClient = http.CreateClient();
|
||||||
|
AddHeader(httpClient, apiKey);
|
||||||
|
|
||||||
|
var request = new TextCompletionRequest
|
||||||
|
{
|
||||||
|
Model = _model,
|
||||||
|
Prompt = prompt,
|
||||||
|
MaxTokens = maxTokens,
|
||||||
|
Temperature = temperature
|
||||||
|
};
|
||||||
|
var data = JsonSerializer.Serialize(request, _jsonOptions);
|
||||||
|
var httpRequest = new HttpRequestMessage
|
||||||
|
{
|
||||||
|
Method = HttpMethod.Post,
|
||||||
|
RequestUri = new Uri(apiUrl),
|
||||||
|
Content = new StringContent(data, Encoding.UTF8, MediaTypeNames.Application.Json)
|
||||||
|
};
|
||||||
|
|
||||||
|
var httpResponse = await httpClient.SendAsync(httpRequest);
|
||||||
|
httpResponse.EnsureSuccessStatusCode();
|
||||||
|
var responseStr = await httpResponse.Content.ReadAsStringAsync();
|
||||||
|
var response = JsonSerializer.Deserialize<TextCompletionResponse>(responseStr, _jsonOptions);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError($"Error when {Provider}-{_model} generating text... {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string BuildApiUrl(LlmModelSetting modelSetting)
|
||||||
|
{
|
||||||
|
var endpoint = modelSetting.Endpoint.EndsWith("/") ?
|
||||||
|
modelSetting.Endpoint.Substring(0, modelSetting.Endpoint.Length - 1) : modelSetting.Endpoint;
|
||||||
|
return endpoint ?? string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddHeader(HttpClient httpClient, string apiKey)
|
||||||
|
{
|
||||||
|
httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {apiKey}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
namespace BotSharp.Plugin.OpenAI.Settings;
|
||||||
|
|
||||||
|
public class OpenAiSettings
|
||||||
|
{
|
||||||
|
}
|
||||||
19
src/Plugins/BotSharp.Plugin.OpenAI/Using.cs
Normal file
19
src/Plugins/BotSharp.Plugin.OpenAI/Using.cs
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
global using System;
|
||||||
|
global using System.Collections.Generic;
|
||||||
|
global using System.Linq;
|
||||||
|
global using System.IO;
|
||||||
|
global using System.Threading.Tasks;
|
||||||
|
global using Microsoft.Extensions.DependencyInjection;
|
||||||
|
global using Microsoft.Extensions.Logging;
|
||||||
|
global using BotSharp.Abstraction.Agents.Enums;
|
||||||
|
global using BotSharp.Abstraction.Agents.Models;
|
||||||
|
global using BotSharp.Abstraction.Conversations;
|
||||||
|
global using BotSharp.Abstraction.Conversations.Models;
|
||||||
|
global using BotSharp.Abstraction.Loggers;
|
||||||
|
global using BotSharp.Abstraction.MLTasks;
|
||||||
|
global using BotSharp.Abstraction.Agents;
|
||||||
|
global using BotSharp.Abstraction.Files;
|
||||||
|
global using BotSharp.Abstraction.Files.Models;
|
||||||
|
global using BotSharp.Abstraction.Utilities;
|
||||||
|
global using BotSharp.Plugin.OpenAI.Models;
|
||||||
|
global using BotSharp.Plugin.OpenAI.Settings;
|
||||||
|
|
@ -29,6 +29,7 @@
|
||||||
<ProjectReference Include="..\BotSharp.ServiceDefaults\BotSharp.ServiceDefaults.csproj" />
|
<ProjectReference Include="..\BotSharp.ServiceDefaults\BotSharp.ServiceDefaults.csproj" />
|
||||||
<ProjectReference Include="..\Plugins\BotSharp.Plugin.Dashboard\BotSharp.Plugin.Dashboard.csproj" />
|
<ProjectReference Include="..\Plugins\BotSharp.Plugin.Dashboard\BotSharp.Plugin.Dashboard.csproj" />
|
||||||
<ProjectReference Include="..\Plugins\BotSharp.Plugin.MetaGLM\BotSharp.Plugin.MetaGLM.csproj" />
|
<ProjectReference Include="..\Plugins\BotSharp.Plugin.MetaGLM\BotSharp.Plugin.MetaGLM.csproj" />
|
||||||
|
<ProjectReference Include="..\Plugins\BotSharp.Plugin.OpenAI\BotSharp.Plugin.OpenAI.csproj" />
|
||||||
<ProjectReference Include="..\Plugins\BotSharp.Plugin.SparkDesk\BotSharp.Plugin.SparkDesk.csproj" />
|
<ProjectReference Include="..\Plugins\BotSharp.Plugin.SparkDesk\BotSharp.Plugin.SparkDesk.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -279,6 +279,7 @@
|
||||||
"BotSharp.Logger",
|
"BotSharp.Logger",
|
||||||
"BotSharp.Plugin.MongoStorage",
|
"BotSharp.Plugin.MongoStorage",
|
||||||
"BotSharp.Plugin.Dashboard",
|
"BotSharp.Plugin.Dashboard",
|
||||||
|
"BotSharp.Plugin.OpenAI",
|
||||||
"BotSharp.Plugin.AzureOpenAI",
|
"BotSharp.Plugin.AzureOpenAI",
|
||||||
"BotSharp.Plugin.AnthropicAI",
|
"BotSharp.Plugin.AnthropicAI",
|
||||||
"BotSharp.Plugin.GoogleAI",
|
"BotSharp.Plugin.GoogleAI",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue