diff --git a/Directory.Build.props b/Directory.Build.props
index b0bfb4ac..84bd21db 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -2,7 +2,7 @@
10.0
..\..\..\packages
- 0.15.1
+ 0.16.0
true
\ No newline at end of file
diff --git a/src/Infrastructure/BotSharp.Abstraction/Routing/Settings/RoutingSettings.cs b/src/Infrastructure/BotSharp.Abstraction/Routing/Settings/RoutingSettings.cs
index 81e52f92..38e62ced 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Routing/Settings/RoutingSettings.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Routing/Settings/RoutingSettings.cs
@@ -12,6 +12,7 @@ public class RoutingSettings
public string Description { get; set; } = string.Empty;
public bool EnableReasoning { get; set; } = false;
+ public bool UseTextCompletion { get; set; } = false;
public string Provider { get; set; } = string.Empty;
diff --git a/src/Infrastructure/BotSharp.Abstraction/Utilities/StringExtensions.cs b/src/Infrastructure/BotSharp.Abstraction/Utilities/StringExtensions.cs
index c51f59e6..90adac26 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Utilities/StringExtensions.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Utilities/StringExtensions.cs
@@ -18,21 +18,6 @@ public static class StringExtensions
return str;
}
- public static string CleanPhoneNumber(this string phoneNumber)
- {
- if (phoneNumber != null && !phoneNumber.All(char.IsDigit))
- {
- phoneNumber = Regex.Replace(phoneNumber, @"[^\d]", "");
- }
-
- if (phoneNumber != null && phoneNumber.Length > 10)
- {
- phoneNumber = phoneNumber.Substring(1);
- }
-
- return phoneNumber;
- }
-
public static string[] SplitByNewLine(this string input)
{
return input.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
diff --git a/src/Infrastructure/BotSharp.Core/Infrastructures/CompletionProvider.cs b/src/Infrastructure/BotSharp.Core/Infrastructures/CompletionProvider.cs
index 54b21928..34feb606 100644
--- a/src/Infrastructure/BotSharp.Core/Infrastructures/CompletionProvider.cs
+++ b/src/Infrastructure/BotSharp.Core/Infrastructures/CompletionProvider.cs
@@ -31,4 +31,32 @@ public class CompletionProvider
return completer;
}
+
+ public static ITextCompletion GetTextCompletion(IServiceProvider services, string? provider = null, string? model = null)
+ {
+ var completions = services.GetServices();
+
+ var state = services.GetRequiredService();
+
+ if (string.IsNullOrEmpty(provider))
+ {
+ provider = state.GetState("provider", "azure-openai");
+ }
+
+ if (string.IsNullOrEmpty(model))
+ {
+ model = state.GetState("model", "gpt-3.5-turbo");
+ }
+
+ var completer = completions.FirstOrDefault(x => x.Provider == provider);
+ if (completer == null)
+ {
+ var logger = services.GetRequiredService>();
+ logger.LogError($"Can't resolve completion provider by {provider}");
+ }
+
+ completer.SetModelName(model);
+
+ return completer;
+ }
}
diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.GetNextInstruction.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.GetNextInstruction.cs
index b381ec24..636d8cac 100644
--- a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.GetNextInstruction.cs
+++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.GetNextInstruction.cs
@@ -1,5 +1,4 @@
using BotSharp.Abstraction.Functions.Models;
-using BotSharp.Abstraction.Routing;
using BotSharp.Abstraction.Routing.Models;
using System.Drawing;
using System.Text.RegularExpressions;
@@ -19,16 +18,30 @@ public partial class RoutingService
var content = $"{prompt} Response must be in JSON format {responseFormat}";
var state = _services.GetRequiredService();
- var provider = state.GetState("provider", _settings.Provider);
- var model = state.GetState("model", _settings.Model);
- var chatCompletion = CompletionProvider.GetChatCompletion(_services,
- provider: provider,
- model: model);
+
- var response = chatCompletion.GetChatCompletions(_routerInstance.Router, new List
+ RoleDialogModel response = default;
+ if (_settings.UseTextCompletion)
+ {
+ var completion = CompletionProvider.GetTextCompletion(_services,
+ provider: _settings.Provider,
+ model: _settings.Model);
+
+ content = _routerInstance.Router.Instruction + "\r\n\r\n" + content + "\r\nResponse: ";
+ var text = await completion.GetCompletion(content);
+ response = new RoleDialogModel(AgentRole.Assistant, text);
+ }
+ else
+ {
+ var completion = CompletionProvider.GetChatCompletion(_services,
+ provider: _settings.Provider,
+ model: _settings.Model);
+
+ response = completion.GetChatCompletions(_routerInstance.Router, new List
{
new RoleDialogModel(AgentRole.User, content)
});
+ }
var args = new FunctionCallFromLlm();
try
diff --git a/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ChatCompletionProvider.cs b/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ChatCompletionProvider.cs
index d09abdc5..33b85a5c 100644
--- a/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ChatCompletionProvider.cs
+++ b/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ChatCompletionProvider.cs
@@ -37,59 +37,15 @@ public class ChatCompletionProvider : IChatCompletion
_tokenStatistics = tokenStatistics;
}
- protected virtual (OpenAIClient, string) GetClient()
- {
- if (_model == "gpt-4")
- {
- var client = new OpenAIClient(new Uri(_settings.GPT4.Endpoint), new AzureKeyCredential(_settings.GPT4.ApiKey));
- return (client, _settings.GPT4.DeploymentModel);
- }
- else
- {
- var client = new OpenAIClient(new Uri(_settings.Endpoint), new AzureKeyCredential(_settings.ApiKey));
- return (client, _settings.DeploymentModel.ChatCompletionModel);
- }
- }
-
- public List GetChatSamples(string sampleText)
- {
- var samples = new List();
- if (string.IsNullOrEmpty(sampleText))
- {
- return samples;
- }
-
- var lines = sampleText.Split('\n');
- for (int i = 0; i < lines.Length; 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;
- }
-
public RoleDialogModel GetChatCompletions(Agent agent, List conversations)
{
- var (client, deploymentModel) = GetClient();
+ var (client, deploymentModel) = ProviderHelper.GetClient(_model, _settings);
var chatCompletionsOptions = PrepareOptions(agent, conversations);
_tokenStatistics.StartTimer();
var response = client.GetChatCompletions(deploymentModel, chatCompletionsOptions);
_tokenStatistics.StopTimer();
+
var choice = response.Value.Choices[0];
var message = choice.Message;
@@ -104,7 +60,7 @@ public class ChatCompletionProvider : IChatCompletion
if (choice.FinishReason == CompletionsFinishReason.FunctionCall)
{
- _logger.LogInformation($"[{agent.Name}]: {message.FunctionCall.Name} => {message.FunctionCall.Arguments}");
+ _logger.LogInformation($"[{agent.Name}]: {message.FunctionCall.Name}({message.FunctionCall.Arguments})");
var funcContextIn = new RoleDialogModel(AgentRole.Function, message.Content)
{
@@ -137,7 +93,7 @@ public class ChatCompletionProvider : IChatCompletion
Func onMessageReceived,
Func onFunctionExecuting)
{
- var (client, deploymentModel) = GetClient();
+ var (client, deploymentModel) = ProviderHelper.GetClient(_model, _settings);
var chatCompletionsOptions = PrepareOptions(agent, conversations);
var response = await client.GetChatCompletionsAsync(deploymentModel, chatCompletionsOptions);
@@ -155,7 +111,7 @@ public class ChatCompletionProvider : IChatCompletion
if (choice.FinishReason == CompletionsFinishReason.FunctionCall)
{
- _logger.LogInformation($"[{agent.Name}]: {message.FunctionCall.Name} => {message.FunctionCall.Arguments}");
+ _logger.LogInformation($"[{agent.Name}]: {message.FunctionCall.Name}({message.FunctionCall.Arguments})");
var funcContextIn = new RoleDialogModel(AgentRole.Function, message.Content)
{
@@ -246,7 +202,7 @@ public class ChatCompletionProvider : IChatCompletion
chatCompletionsOptions.Messages.Add(new ChatMessage(ChatRole.System, agent.Knowledges));
}
- var samples = GetChatSamples(agent.Samples);
+ var samples = ProviderHelper.GetChatSamples(agent.Samples);
foreach (var message in samples)
{
chatCompletionsOptions.Messages.Add(new ChatMessage(message.Role, message.Content));
diff --git a/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ProviderHelper.cs b/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ProviderHelper.cs
new file mode 100644
index 00000000..b829330f
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ProviderHelper.cs
@@ -0,0 +1,56 @@
+using Azure.AI.OpenAI;
+using Azure;
+using System;
+using BotSharp.Plugin.AzureOpenAI.Settings;
+using BotSharp.Abstraction.Conversations.Models;
+using System.Collections.Generic;
+
+namespace BotSharp.Plugin.AzureOpenAI.Providers;
+
+public class ProviderHelper
+{
+ public static (OpenAIClient, string) GetClient(string model, AzureOpenAiSettings settings)
+ {
+ if (model == "gpt-4")
+ {
+ var client = new OpenAIClient(new Uri(settings.GPT4.Endpoint), new AzureKeyCredential(settings.GPT4.ApiKey));
+ return (client, settings.GPT4.DeploymentModel);
+ }
+ else
+ {
+ var client = new OpenAIClient(new Uri(settings.Endpoint), new AzureKeyCredential(settings.ApiKey));
+ return (client, settings.DeploymentModel.ChatCompletionModel);
+ }
+ }
+
+ public static List GetChatSamples(string sampleText)
+ {
+ var samples = new List();
+ if (string.IsNullOrEmpty(sampleText))
+ {
+ return samples;
+ }
+
+ var lines = sampleText.Split('\n');
+ for (int i = 0; i < lines.Length; 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;
+ }
+}
diff --git a/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/TextCompletionProvider.cs b/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/TextCompletionProvider.cs
index 820bb3af..a6b037ce 100644
--- a/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/TextCompletionProvider.cs
+++ b/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/TextCompletionProvider.cs
@@ -1,43 +1,68 @@
using Azure.AI.OpenAI;
-using Azure;
using BotSharp.Abstraction.MLTasks;
using System;
using System.Threading.Tasks;
using BotSharp.Plugin.AzureOpenAI.Settings;
using Microsoft.Extensions.Logging;
+using BotSharp.Abstraction.Conversations;
+using Microsoft.Extensions.DependencyInjection;
+using BotSharp.Abstraction.Conversations.Models;
namespace BotSharp.Plugin.AzureOpenAI.Providers;
public class TextCompletionProvider : ITextCompletion
{
+ private readonly IServiceProvider _services;
private readonly AzureOpenAiSettings _settings;
private readonly ILogger _logger;
- bool _useAzureOpenAI = true;
+ private readonly ITokenStatistics _tokenStatistics;
private string _model;
public string Provider => "azure-openai";
- public TextCompletionProvider(AzureOpenAiSettings settings, ILogger logger)
+ public TextCompletionProvider(IServiceProvider services,
+ AzureOpenAiSettings settings,
+ ILogger logger,
+ ITokenStatistics tokenStatistics)
{
+ _services = services;
_settings = settings;
_logger = logger;
+ _tokenStatistics = tokenStatistics;
}
public async Task GetCompletion(string text)
{
- var client = GetOpenAIClient();
+ var (client, _) = ProviderHelper.GetClient(_model, _settings);
+
var completionsOptions = new CompletionsOptions()
{
Prompts =
{
text
},
- Temperature = 0.7f,
MaxTokens = 256
};
+ var state = _services.GetRequiredService();
+ var temperature = float.Parse(state.GetState("temperature", "0.5"));
+ var samplingFactor = float.Parse(state.GetState("sampling_factor", "0.5"));
+ completionsOptions.Temperature = temperature;
+ completionsOptions.NucleusSamplingFactor = samplingFactor;
+
+ _tokenStatistics.StartTimer();
var response = await client.GetCompletionsAsync(
deploymentOrModelName: _settings.DeploymentModel.TextCompletionModel,
completionsOptions);
+ _tokenStatistics.StopTimer();
+
+ _tokenStatistics.AddToken(new TokenStatsModel
+ {
+ Model = _model,
+ PromptCount = response.Value.Usage.PromptTokens,
+ CompletionCount = response.Value.Usage.CompletionTokens,
+ PromptCost = 0.0015f,
+ CompletionCost = 0.002f
+ });
// OpenAI
var completion = "";
@@ -46,7 +71,7 @@ public class TextCompletionProvider : ITextCompletion
completion += t.Text;
};
- _logger.LogInformation(text + completion);
+ _logger.LogInformation(text);
return completion.Trim();
}
@@ -55,14 +80,4 @@ public class TextCompletionProvider : ITextCompletion
{
_model = model;
}
-
- private OpenAIClient GetOpenAIClient()
- {
- OpenAIClient client = _useAzureOpenAI
- ? new OpenAIClient(
- new Uri(_settings.Endpoint),
- new AzureKeyCredential(_settings.ApiKey))
- : new OpenAIClient("your-api-key-from-platform.openai.com");
- return client;
- }
}
diff --git a/src/Plugins/BotSharp.Plugin.GoogleAI/Providers/ChatCompletionProvider.cs b/src/Plugins/BotSharp.Plugin.GoogleAI/Providers/ChatCompletionProvider.cs
index 9e9dbd8b..abe1ca9c 100644
--- a/src/Plugins/BotSharp.Plugin.GoogleAI/Providers/ChatCompletionProvider.cs
+++ b/src/Plugins/BotSharp.Plugin.GoogleAI/Providers/ChatCompletionProvider.cs
@@ -29,10 +29,9 @@ public class ChatCompletionProvider : IChatCompletion
public RoleDialogModel GetChatCompletions(Agent agent, List conversations)
{
var client = new GooglePalmClient(apiKey: _settings.PaLM.ApiKey);
- List messages = new()
- {
- new(conversations.Last().Content, "user"),
- };
+ var messages = conversations.Select(c => new PalmChatMessage(c.Content, c.Role == AgentRole.User ? "user" : "AI"))
+ .ToList();
+
_tokenStatistics.StartTimer();
var response = client.ChatAsync(messages, agent.Instruction, null).Result;
_tokenStatistics.StopTimer();
diff --git a/src/Plugins/BotSharp.Plugin.GoogleAI/Providers/TextCompletionProvider.cs b/src/Plugins/BotSharp.Plugin.GoogleAI/Providers/TextCompletionProvider.cs
index 8063d5d5..fc854726 100644
--- a/src/Plugins/BotSharp.Plugin.GoogleAI/Providers/TextCompletionProvider.cs
+++ b/src/Plugins/BotSharp.Plugin.GoogleAI/Providers/TextCompletionProvider.cs
@@ -1,13 +1,42 @@
+using BotSharp.Abstraction.Conversations;
+using BotSharp.Plugin.GoogleAI.Settings;
+using LLMSharp.Google.Palm;
+using Microsoft.Extensions.Logging;
+
namespace BotSharp.Plugin.GoogleAI.Providers;
public class TextCompletionProvider : ITextCompletion
{
public string Provider => "google-ai";
+ private readonly IServiceProvider _services;
+ private readonly GoogleAiSettings _settings;
+ private readonly ILogger _logger;
+ private readonly ITokenStatistics _tokenStatistics;
private string _model;
- public Task GetCompletion(string text)
+ public TextCompletionProvider(IServiceProvider services,
+ GoogleAiSettings settings,
+ ILogger logger,
+ ITokenStatistics tokenStatistics)
{
- throw new NotImplementedException();
+ _services = services;
+ _settings = settings;
+ _logger = logger;
+ _tokenStatistics = tokenStatistics;
+ }
+
+ public async Task GetCompletion(string text)
+ {
+ var client = new GooglePalmClient(apiKey: _settings.PaLM.ApiKey);
+ _tokenStatistics.StartTimer();
+ var response = await client.GenerateTextAsync(text, null);
+ _tokenStatistics.StopTimer();
+
+ var message = response.Candidates.First();
+
+ _logger.LogInformation(text);
+
+ return message.Output.Trim();
}
public void SetModelName(string model)
diff --git a/src/WebStarter/appsettings.json b/src/WebStarter/appsettings.json
index 1ee508f7..1e6db61e 100644
--- a/src/WebStarter/appsettings.json
+++ b/src/WebStarter/appsettings.json
@@ -17,6 +17,7 @@
"RouterId": "01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a",
"RouterName": "PizzaBot",
"Description": "Pizza restaurant AI Bot",
+ "UseTextCompletion": false,
"EnableReasoning": false,
"Provider": "azure-openai",
"Model": "gpt-3.5-turbo"