TextCompletion of google-ai

This commit is contained in:
Haiping Chen 2023-10-09 17:28:17 -05:00
parent caf60693a4
commit c9822dd7ee
11 changed files with 178 additions and 95 deletions

View file

@ -2,7 +2,7 @@
<PropertyGroup>
<LangVersion>10.0</LangVersion>
<OutputPath>..\..\..\packages</OutputPath>
<BotSharpVersion>0.15.1</BotSharpVersion>
<BotSharpVersion>0.16.0</BotSharpVersion>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup>
</Project>

View file

@ -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;

View file

@ -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);

View file

@ -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<ITextCompletion>();
var state = services.GetRequiredService<IConversationStateService>();
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<ILogger<CompletionProvider>>();
logger.LogError($"Can't resolve completion provider by {provider}");
}
completer.SetModelName(model);
return completer;
}
}

View file

@ -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<IConversationStateService>();
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>
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<RoleDialogModel>
{
new RoleDialogModel(AgentRole.User, content)
});
}
var args = new FunctionCallFromLlm();
try

View file

@ -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<RoleDialogModel> GetChatSamples(string sampleText)
{
var samples = new List<RoleDialogModel>();
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<RoleDialogModel> 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<RoleDialogModel, Task> onMessageReceived,
Func<RoleDialogModel, Task> 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));

View file

@ -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<RoleDialogModel> GetChatSamples(string sampleText)
{
var samples = new List<RoleDialogModel>();
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;
}
}

View file

@ -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<TextCompletionProvider> logger)
public TextCompletionProvider(IServiceProvider services,
AzureOpenAiSettings settings,
ILogger<TextCompletionProvider> logger,
ITokenStatistics tokenStatistics)
{
_services = services;
_settings = settings;
_logger = logger;
_tokenStatistics = tokenStatistics;
}
public async Task<string> 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<IConversationStateService>();
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;
}
}

View file

@ -29,10 +29,9 @@ public class ChatCompletionProvider : IChatCompletion
public RoleDialogModel GetChatCompletions(Agent agent, List<RoleDialogModel> conversations)
{
var client = new GooglePalmClient(apiKey: _settings.PaLM.ApiKey);
List<PalmChatMessage> 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();

View file

@ -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<string> GetCompletion(string text)
public TextCompletionProvider(IServiceProvider services,
GoogleAiSettings settings,
ILogger<TextCompletionProvider> logger,
ITokenStatistics tokenStatistics)
{
throw new NotImplementedException();
_services = services;
_settings = settings;
_logger = logger;
_tokenStatistics = tokenStatistics;
}
public async Task<string> 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)

View file

@ -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"