From afeaa167385506f1e5ddf576d46ccee75e9020b1 Mon Sep 17 00:00:00 2001 From: Haiping Chen Date: Fri, 17 Oct 2025 13:58:38 -0500 Subject: [PATCH] Remove legacy Google PaLM --- .../BotSharp.Plugin.GoogleAI.csproj | 1 - .../GoogleAiPlugin.cs | 8 +- ...nProvider.cs => ChatCompletionProvider.cs} | 11 +- .../Chat/PalmChatCompletionProvider.cs | 156 ------------------ .../Image/ImageCompletionProvider.cs | 58 +++++++ .../Providers/ProviderHelper.cs | 10 -- .../Text/PalmTextCompletionProvider.cs | 65 -------- ...nProvider.cs => TextCompletionProvider.cs} | 11 +- 8 files changed, 70 insertions(+), 250 deletions(-) rename src/Plugins/BotSharp.Plugin.GoogleAI/Providers/Chat/{GeminiChatCompletionProvider.cs => ChatCompletionProvider.cs} (98%) delete mode 100644 src/Plugins/BotSharp.Plugin.GoogleAI/Providers/Chat/PalmChatCompletionProvider.cs create mode 100644 src/Plugins/BotSharp.Plugin.GoogleAI/Providers/Image/ImageCompletionProvider.cs delete mode 100644 src/Plugins/BotSharp.Plugin.GoogleAI/Providers/Text/PalmTextCompletionProvider.cs rename src/Plugins/BotSharp.Plugin.GoogleAI/Providers/Text/{GeminiTextCompletionProvider.cs => TextCompletionProvider.cs} (88%) diff --git a/src/Plugins/BotSharp.Plugin.GoogleAI/BotSharp.Plugin.GoogleAI.csproj b/src/Plugins/BotSharp.Plugin.GoogleAI/BotSharp.Plugin.GoogleAI.csproj index ac68607c..0e0f5784 100644 --- a/src/Plugins/BotSharp.Plugin.GoogleAI/BotSharp.Plugin.GoogleAI.csproj +++ b/src/Plugins/BotSharp.Plugin.GoogleAI/BotSharp.Plugin.GoogleAI.csproj @@ -17,7 +17,6 @@ - diff --git a/src/Plugins/BotSharp.Plugin.GoogleAI/GoogleAiPlugin.cs b/src/Plugins/BotSharp.Plugin.GoogleAI/GoogleAiPlugin.cs index 7b311886..3382f350 100644 --- a/src/Plugins/BotSharp.Plugin.GoogleAI/GoogleAiPlugin.cs +++ b/src/Plugins/BotSharp.Plugin.GoogleAI/GoogleAiPlugin.cs @@ -10,7 +10,7 @@ public class GoogleAiPlugin : IBotSharpPlugin { public string Id => "962ff441-2b40-4db4-b530-49efb1688a75"; public string Name => "Google AI"; - public string Description => "Making AI helpful for everyone (PaLM 2, Gemini)"; + public string Description => "Making AI helpful for everyone"; public string IconUrl => "https://vectorseek.com/wp-content/uploads/2021/12/Google-AI-Logo-Vector.png"; public void RegisterDI(IServiceCollection services, IConfiguration config) { @@ -20,10 +20,8 @@ public class GoogleAiPlugin : IBotSharpPlugin return settingService.Bind("GoogleAi"); }); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); + services.AddScoped(); + services.AddScoped(); services.AddScoped(); services.AddScoped(); } diff --git a/src/Plugins/BotSharp.Plugin.GoogleAI/Providers/Chat/GeminiChatCompletionProvider.cs b/src/Plugins/BotSharp.Plugin.GoogleAI/Providers/Chat/ChatCompletionProvider.cs similarity index 98% rename from src/Plugins/BotSharp.Plugin.GoogleAI/Providers/Chat/GeminiChatCompletionProvider.cs rename to src/Plugins/BotSharp.Plugin.GoogleAI/Providers/Chat/ChatCompletionProvider.cs index 60e0ef02..d224fb12 100644 --- a/src/Plugins/BotSharp.Plugin.GoogleAI/Providers/Chat/GeminiChatCompletionProvider.cs +++ b/src/Plugins/BotSharp.Plugin.GoogleAI/Providers/Chat/ChatCompletionProvider.cs @@ -5,14 +5,13 @@ using BotSharp.Abstraction.Hooks; using GenerativeAI; using GenerativeAI.Core; using GenerativeAI.Types; -using Google.Ai.Generativelanguage.V1Beta2; namespace BotSharp.Plugin.GoogleAi.Providers.Chat; -public class GeminiChatCompletionProvider : IChatCompletion +public class ChatCompletionProvider : IChatCompletion { private readonly IServiceProvider _services; - private readonly ILogger _logger; + private readonly ILogger _logger; private List renderedInstructions = []; private string _model; @@ -21,10 +20,10 @@ public class GeminiChatCompletionProvider : IChatCompletion public string Model => _model; private GoogleAiSettings _settings; - public GeminiChatCompletionProvider( + public ChatCompletionProvider( IServiceProvider services, GoogleAiSettings googleSettings, - ILogger logger) + ILogger logger) { _settings = googleSettings; _services = services; @@ -104,7 +103,7 @@ public class GeminiChatCompletionProvider : IChatCompletion var (prompt, messages) = PrepareOptions(chatClient, agent, conversations); var response = await chatClient.GenerateContentAsync(messages); - + var candidate = response.Candidates?.First(); var part = candidate?.Content?.Parts?.FirstOrDefault(); var text = part?.Text ?? string.Empty; diff --git a/src/Plugins/BotSharp.Plugin.GoogleAI/Providers/Chat/PalmChatCompletionProvider.cs b/src/Plugins/BotSharp.Plugin.GoogleAI/Providers/Chat/PalmChatCompletionProvider.cs deleted file mode 100644 index bec65e17..00000000 --- a/src/Plugins/BotSharp.Plugin.GoogleAI/Providers/Chat/PalmChatCompletionProvider.cs +++ /dev/null @@ -1,156 +0,0 @@ -using BotSharp.Abstraction.Routing; -using LLMSharp.Google.Palm; -using LLMSharp.Google.Palm.DiscussService; -using BotSharp.Abstraction.Hooks; - -namespace BotSharp.Plugin.GoogleAi.Providers.Chat; - -[Obsolete] -public class PalmChatCompletionProvider : IChatCompletion -{ - private readonly IServiceProvider _services; - private readonly ILogger _logger; - private List renderedInstructions = []; - - private string _model; - - public string Provider => "google-palm"; - public string Model => _model; - - public PalmChatCompletionProvider( - IServiceProvider services, - ILogger logger) - { - _services = services; - _logger = logger; - } - - public async Task GetChatCompletions(Agent agent, List conversations) - { - var contentHooks = _services.GetHooks(agent.Id); - - // Before chat completion hook - foreach (var hook in contentHooks) - { - await hook.BeforeGenerating(agent, conversations); - } - - var client = ProviderHelper.GetPalmClient(Provider, _model, _services); - var (prompt, messages, hasFunctions) = PrepareOptions(agent, conversations); - - RoleDialogModel msg; - - if (hasFunctions) - { - // use text completion - // var response = client.GenerateTextAsync(prompt, null).Result; - var response = await client.ChatAsync(new PalmChatCompletionRequest - { - Context = prompt, - Messages = messages, - Temperature = 0.1f - }); - - var message = response.Candidates.First(); - - // check if returns function calling - var llmResponse = message.Content.JsonContent(); - - msg = new RoleDialogModel(llmResponse.Role, llmResponse.Content) - { - CurrentAgentId = agent.Id, - FunctionName = llmResponse.FunctionName, - FunctionArgs = JsonSerializer.Serialize(llmResponse.Args), - RenderedInstruction = string.Join("\r\n", renderedInstructions) - }; - } - else - { - var response = await client.ChatAsync(messages, context: prompt, examples: null, options: null); - - var message = response.Candidates.First(); - - // check if returns function calling - var llmResponse = message.Content.JsonContent(); - - msg = new RoleDialogModel(llmResponse.Role, llmResponse.Content ?? message.Content) - { - CurrentAgentId = agent.Id, - RenderedInstruction = string.Join("\r\n", renderedInstructions) - }; - } - - // After chat completion hook - foreach (var hook in contentHooks) - { - await hook.AfterGenerated(msg, new TokenStatsModel - { - Prompt = prompt, - Provider = Provider, - Model = _model - }); - } - - return msg; - } - - private (string, List, bool) PrepareOptions(Agent agent, List conversations) - { - var agentService = _services.GetRequiredService(); - var routing = _services.GetRequiredService(); - var router = routing.Router; - - // Prepare instruction and functions - var renderData = agentService.CollectRenderData(agent); - var (prompt, functions) = agentService.PrepareInstructionAndFunctions(agent, renderData); - if (!string.IsNullOrWhiteSpace(prompt)) - { - renderedInstructions.Add(prompt); - } - - var messages = conversations.Select(c => new PalmChatMessage(c.LlmContent, c.Role == AgentRole.User ? "user" : "AI")) - .ToList(); - - if (!functions.IsNullOrEmpty()) - { - prompt += "\r\n\r\n[Functions] defined in JSON Schema:\r\n"; - prompt += JsonSerializer.Serialize(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.LlmContent}\r\n" : - $"{dialog.Role}: {dialog.LlmContent}\r\n"; - } - - prompt += "\r\n\r\n" + router.Templates.FirstOrDefault(x => x.Name == "response_with_function").Content; - - return (prompt, new List - { - new PalmChatMessage("Which function should be used for the next step based on latest user or function response, output your response in JSON:", AgentRole.User), - }, true); - } - - return (prompt, messages, false); - } - - public Task GetChatCompletionsAsync(Agent agent, List conversations, Func onMessageReceived, Func onFunctionExecuting) - { - throw new NotImplementedException(); - } - - public Task GetChatCompletionsStreamingAsync(Agent agent, List conversations) - { - throw new NotImplementedException(); - } - - public void SetModelName(string model) - { - _model = model; - } -} diff --git a/src/Plugins/BotSharp.Plugin.GoogleAI/Providers/Image/ImageCompletionProvider.cs b/src/Plugins/BotSharp.Plugin.GoogleAI/Providers/Image/ImageCompletionProvider.cs new file mode 100644 index 00000000..1ddd71f5 --- /dev/null +++ b/src/Plugins/BotSharp.Plugin.GoogleAI/Providers/Image/ImageCompletionProvider.cs @@ -0,0 +1,58 @@ +using System.IO; + +namespace BotSharp.Plugin.GoogleAI.Providers.Image; + +public partial class ImageCompletionProvider : IImageCompletion +{ + protected readonly GoogleAiSettings _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 => "google-ai"; + public string Model => _model; + + public ImageCompletionProvider( + GoogleAiSettings settings, + ILogger logger, + IServiceProvider services) + { + _settings = settings; + _services = services; + _logger = logger; + } + + public void SetModelName(string model) + { + _model = model; + } + + public Task GetImageGeneration(Agent agent, RoleDialogModel message) + { + throw new NotImplementedException(); + } + + public Task GetImageVariation(Agent agent, RoleDialogModel message, Stream image, string imageFileName) + { + throw new NotImplementedException(); + } + + public Task GetImageEdits(Agent agent, RoleDialogModel message, Stream image, string imageFileName) + { + throw new NotImplementedException(); + } + + public Task GetImageEdits(Agent agent, RoleDialogModel message, Stream image, string imageFileName, Stream mask, string maskFileName) + { + throw new NotImplementedException(); + } + + public Task GetImageComposition(Agent agent, RoleDialogModel message, Stream[] images, string[] imageFileNames) + { + throw new NotImplementedException(); + } +} diff --git a/src/Plugins/BotSharp.Plugin.GoogleAI/Providers/ProviderHelper.cs b/src/Plugins/BotSharp.Plugin.GoogleAI/Providers/ProviderHelper.cs index 7b6c25ea..1f907c2b 100644 --- a/src/Plugins/BotSharp.Plugin.GoogleAI/Providers/ProviderHelper.cs +++ b/src/Plugins/BotSharp.Plugin.GoogleAI/Providers/ProviderHelper.cs @@ -1,5 +1,3 @@ -using LLMSharp.Google.Palm; - namespace BotSharp.Plugin.GoogleAi.Providers; public static class ProviderHelper @@ -19,12 +17,4 @@ public static class ProviderHelper return new GenerativeAI.GoogleAi(aiSettings.Gemini.ApiKey); } } - - public static GooglePalmClient GetPalmClient(string provider, string model, IServiceProvider services) - { - var settingsService = services.GetRequiredService(); - var settings = settingsService.GetSetting(provider, model); - var client = new GooglePalmClient(settings.ApiKey); - return client; - } } diff --git a/src/Plugins/BotSharp.Plugin.GoogleAI/Providers/Text/PalmTextCompletionProvider.cs b/src/Plugins/BotSharp.Plugin.GoogleAI/Providers/Text/PalmTextCompletionProvider.cs deleted file mode 100644 index 14d3ebab..00000000 --- a/src/Plugins/BotSharp.Plugin.GoogleAI/Providers/Text/PalmTextCompletionProvider.cs +++ /dev/null @@ -1,65 +0,0 @@ -using BotSharp.Abstraction.Hooks; - -namespace BotSharp.Plugin.GoogleAi.Providers.Text; - -[Obsolete] -public class PalmTextCompletionProvider : ITextCompletion -{ - private readonly IServiceProvider _services; - private readonly ILogger _logger; - private readonly ITokenStatistics _tokenStatistics; - - private string _model; - - public string Provider => "google-palm"; - public string Model => _model; - - public PalmTextCompletionProvider( - IServiceProvider services, - ILogger logger, - ITokenStatistics tokenStatistics) - { - _services = services; - _logger = logger; - _tokenStatistics = tokenStatistics; - } - - public async Task GetCompletion(string text, string agentId, string messageId) - { - var contentHooks = _services.GetHooks(agentId); - - // Before completion hook - var agent = new Agent() { Id = agentId }; - var userMessage = new RoleDialogModel(AgentRole.User, text) { MessageId = messageId }; - - foreach (var hook in contentHooks) - { - await hook.BeforeGenerating(agent, new List { userMessage }); - } - - var client = ProviderHelper.GetPalmClient(Provider, _model, _services); - _tokenStatistics.StartTimer(); - var response = await client.GenerateTextAsync(text, null); - _tokenStatistics.StopTimer(); - - var message = response.Candidates.First(); - var completion = message.Output.Trim(); - - // After completion hook - foreach (var hook in contentHooks) - { - await hook.AfterGenerated(new RoleDialogModel(AgentRole.Assistant, completion), new TokenStatsModel - { - Prompt = text, - Provider = Provider - }); - } - - return completion; - } - - public void SetModelName(string model) - { - _model = model; - } -} diff --git a/src/Plugins/BotSharp.Plugin.GoogleAI/Providers/Text/GeminiTextCompletionProvider.cs b/src/Plugins/BotSharp.Plugin.GoogleAI/Providers/Text/TextCompletionProvider.cs similarity index 88% rename from src/Plugins/BotSharp.Plugin.GoogleAI/Providers/Text/GeminiTextCompletionProvider.cs rename to src/Plugins/BotSharp.Plugin.GoogleAI/Providers/Text/TextCompletionProvider.cs index abc12c3e..6a838d2f 100644 --- a/src/Plugins/BotSharp.Plugin.GoogleAI/Providers/Text/GeminiTextCompletionProvider.cs +++ b/src/Plugins/BotSharp.Plugin.GoogleAI/Providers/Text/TextCompletionProvider.cs @@ -1,16 +1,13 @@ -using BotSharp.Abstraction.Agents.Enums; -using BotSharp.Abstraction.Conversations; using BotSharp.Abstraction.Hooks; -using BotSharp.Abstraction.Loggers; using GenerativeAI; using GenerativeAI.Core; namespace BotSharp.Plugin.GoogleAi.Providers.Text; -public class GeminiTextCompletionProvider : ITextCompletion +public class TextCompletionProvider : ITextCompletion { private readonly IServiceProvider _services; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly ITokenStatistics _tokenStatistics; private string _model; @@ -18,10 +15,10 @@ public class GeminiTextCompletionProvider : ITextCompletion public string Model => _model; private GoogleAiSettings _settings; - public GeminiTextCompletionProvider( + public TextCompletionProvider( IServiceProvider services, GoogleAiSettings googleSettings, - ILogger logger, + ILogger logger, ITokenStatistics tokenStatistics) { _settings = googleSettings;