BotSharp/src/Plugins/BotSharp.Plugin.GoogleAI/Providers/ChatCompletionProvider.cs

145 lines
4.8 KiB
C#
Raw Normal View History

2023-10-28 20:59:26 +00:00
using BotSharp.Abstraction.Agents;
2023-10-08 20:46:42 +00:00
using BotSharp.Abstraction.Agents.Enums;
using BotSharp.Abstraction.Conversations;
2023-11-29 23:23:14 +00:00
using BotSharp.Abstraction.Loggers;
2023-11-30 02:56:23 +00:00
using BotSharp.Abstraction.Functions.Models;
using BotSharp.Abstraction.Routing;
2023-10-08 20:46:42 +00:00
using BotSharp.Plugin.GoogleAI.Settings;
using LLMSharp.Google.Palm;
using Microsoft.Extensions.Logging;
2023-11-30 02:56:23 +00:00
using System.Diagnostics.Metrics;
using static System.Net.Mime.MediaTypeNames;
2023-10-08 20:46:42 +00:00
namespace BotSharp.Plugin.GoogleAI.Providers;
public class ChatCompletionProvider : IChatCompletion
{
public string Provider => "google-ai";
private readonly IServiceProvider _services;
private readonly GoogleAiSettings _settings;
private readonly ILogger _logger;
private string _model;
public ChatCompletionProvider(IServiceProvider services,
GoogleAiSettings settings,
2023-10-16 20:07:07 +00:00
ILogger<ChatCompletionProvider> logger)
2023-10-08 20:46:42 +00:00
{
_services = services;
_settings = settings;
_logger = logger;
}
public RoleDialogModel GetChatCompletions(Agent agent, List<RoleDialogModel> conversations)
{
2023-10-16 20:07:07 +00:00
var hooks = _services.GetServices<IContentGeneratingHook>().ToList();
// Before chat completion hook
Task.WaitAll(hooks.Select(hook =>
hook.BeforeGenerating(agent, conversations)).ToArray());
2023-10-08 20:46:42 +00:00
var client = new GooglePalmClient(apiKey: _settings.PaLM.ApiKey);
2023-10-09 22:28:17 +00:00
2023-11-30 02:56:23 +00:00
var (prompt, messages) = PrepareOptions(agent, conversations);
RoleDialogModel msg;
if (messages == null)
{
// use text completion
var response = client.GenerateTextAsync(prompt, null).Result;
var message = response.Candidates.First();
2023-10-08 20:46:42 +00:00
2023-11-30 02:56:23 +00:00
// check if returns function calling
var llmResponse = message.Output.JsonContent<FunctionCallingResponse>();
msg = new RoleDialogModel(llmResponse.Role, llmResponse.Content)
{
CurrentAgentId = agent.Id,
FunctionName = llmResponse.FunctionName,
FunctionArgs = JsonSerializer.Serialize(llmResponse.Args)
};
}
else
2023-10-08 20:46:42 +00:00
{
2023-11-30 02:56:23 +00:00
var response = client.ChatAsync(messages, context: prompt, examples: null, options: null).Result;
var message = response.Candidates.First();
// check if returns function calling
var llmResponse = message.Content.JsonContent<FunctionCallingResponse>();
msg = new RoleDialogModel(llmResponse.Role, llmResponse.Content ?? message.Content)
{
CurrentAgentId = agent.Id
};
}
2023-10-08 20:46:42 +00:00
2023-10-16 20:07:07 +00:00
// After chat completion hook
Task.WaitAll(hooks.Select(hook =>
hook.AfterGenerated(msg, new TokenStatsModel
{
Model = _model
})).ToArray());
2023-10-08 20:46:42 +00:00
return msg;
}
2023-11-30 02:56:23 +00:00
private (string, List<PalmChatMessage>) PrepareOptions(Agent agent, List<RoleDialogModel> conversations)
{
var prompt = "";
var agentService = _services.GetRequiredService<IAgentService>();
if (!string.IsNullOrEmpty(agent.Instruction))
{
prompt += agentService.RenderedInstruction(agent);
}
var routing = _services.GetRequiredService<IRoutingService>();
var router = routing.Router;
if (agent.Functions != null && agent.Functions.Count > 0)
{
prompt += "\r\n\r\n[Functions] defined in JSON Schema:\r\n";
prompt += JsonSerializer.Serialize(agent.Functions, new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = true
});
prompt += "\r\n\r\n[Conversations]\r\n";
foreach (var dialog in conversations)
{
prompt += dialog.Role == AgentRole.Function ?
$"{dialog.Role}: {dialog.FunctionName} => {dialog.Content}\r\n" :
$"{dialog.Role}: {dialog.Content}\r\n";
}
prompt += "\r\n\r\n" + router.Templates.FirstOrDefault(x => x.Name == "response_with_function").Content;
return (prompt, null);
}
var messages = conversations.Select(c => new PalmChatMessage(c.Content, c.Role == AgentRole.User ? "user" : "AI"))
.ToList();
return (prompt, messages);
}
2023-10-08 20:46:42 +00:00
public Task<bool> GetChatCompletionsAsync(Agent agent, List<RoleDialogModel> conversations, Func<RoleDialogModel, Task> onMessageReceived, Func<RoleDialogModel, Task> onFunctionExecuting)
{
throw new NotImplementedException();
}
public Task<bool> GetChatCompletionsStreamingAsync(Agent agent, List<RoleDialogModel> conversations, Func<RoleDialogModel, Task> onMessageReceived)
{
throw new NotImplementedException();
}
public void SetModelName(string model)
{
_model = model;
}
}