Add id to plugin.

This commit is contained in:
Haiping Chen 2024-01-12 16:20:22 -06:00
parent a42653375d
commit dadb0b49e0
33 changed files with 253 additions and 83 deletions

View file

@ -6,6 +6,10 @@ namespace BotSharp.Abstraction.Plugins;
public interface IBotSharpPlugin
{
/// <summary>
/// Plugin id (guid)
/// </summary>
string Id { get; }
string Name => "";
string Description => "";
string IconUrl => "https://avatars.githubusercontent.com/u/44989469?s=200&v=4";

View file

@ -0,0 +1,7 @@
namespace BotSharp.Abstraction.Plugins.Models;
public class PluginConfig
{
public List<string> EnabledPlugins { get; set; }
= new List<string>();
}

View file

@ -12,5 +12,7 @@ public class PluginDef
[JsonPropertyName("with_agent")]
public bool WithAgent { get; set; }
public bool Enabled { get; set; }
public PluginMenuDef[] Menus { get; set; }
}

View file

@ -1,3 +1,4 @@
using BotSharp.Abstraction.Plugins.Models;
using BotSharp.Abstraction.Repositories.Filters;
using BotSharp.Abstraction.Repositories.Models;
using BotSharp.Abstraction.Users.Models;
@ -9,6 +10,11 @@ public interface IBotSharpRepository
int Transaction<TTableInterface>(Action action);
void Add<TTableInterface>(object entity);
#region Plugin
PluginConfig GetPluginConfig();
void SavePluginConfig(PluginConfig config);
#endregion
#region User
User? GetUserByEmail(string email);
User? GetUserById(string id);

View file

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
@ -51,6 +51,7 @@
<None Remove="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\next_step_prompt.liquid" />
<None Remove="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\response_with_function.liquid" />
<None Remove="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\welcome.liquid" />
<None Remove="data\plugins\config.json" />
</ItemGroup>
<ItemGroup>
@ -72,6 +73,9 @@
<Content Include="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\welcome.liquid">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="data\plugins\config.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>

View file

@ -5,6 +5,7 @@ using System.Drawing;
using System.IO;
using System.Reflection;
using System.Xml;
using BotSharp.Abstraction.Repositories;
namespace BotSharp.Core.Plugins;
@ -50,7 +51,7 @@ public class PluginLoader
_modules.Add(module);
_plugins.Add(new PluginDef
{
Id = module.GetType().FullName,
Id = module.Id,
Name = name,
Description = module.Description,
Assembly = assemblyName,
@ -76,11 +77,45 @@ public class PluginLoader
});
}
public List<PluginDef> GetPlugins()
public List<PluginDef> GetPlugins(IServiceProvider services)
{
// Apply user configurations
var db = services.GetRequiredService<IBotSharpRepository>();
var config = db.GetPluginConfig();
foreach (var plugin in _plugins)
{
plugin.Enabled = config.EnabledPlugins.Contains(plugin.Id);
}
return _plugins;
}
public PluginDef UpdatePluginStatus(IServiceProvider services, string id, bool enable)
{
var plugin = _plugins.First(x => x.Id == id);
plugin.Enabled = enable;
// save to config
var db = services.GetRequiredService<IBotSharpRepository>();
var config = db.GetPluginConfig();
if (enable)
{
if (!config.EnabledPlugins.Exists(x => x == id))
{
config.EnabledPlugins.Add(id);
db.SavePluginConfig(config);
}
}
else
{
if (config.EnabledPlugins.Exists(x => x == id))
{
config.EnabledPlugins.Remove(id);
db.SavePluginConfig(config);
}
}
return plugin;
}
public string GetSummaryComment(Type member)
{
string summary = string.Empty;

View file

@ -1,4 +1,5 @@
using BotSharp.Abstraction.Agents.Models;
using BotSharp.Abstraction.Plugins.Models;
using BotSharp.Abstraction.Repositories;
using BotSharp.Abstraction.Repositories.Filters;
using BotSharp.Abstraction.Repositories.Models;
@ -17,7 +18,6 @@ public class BotSharpDbContext : Database, IBotSharpRepository
public IQueryable<Conversation> Conversations => throw new NotImplementedException();
public int Transaction<TTableInterface>(Action action)
{
DatabaseFacade database = base.GetMaster(typeof(TTableInterface)).Database;
@ -67,6 +67,10 @@ public class BotSharpDbContext : Database, IBotSharpRepository
}
}
#region Plugin
public PluginConfig GetPluginConfig() => throw new NotImplementedException();
public void SavePluginConfig(PluginConfig config) => throw new NotImplementedException();
#endregion
#region Agent
public Agent GetAgent(string agentId)

View file

@ -0,0 +1,38 @@
using BotSharp.Abstraction.Plugins.Models;
using System.IO;
namespace BotSharp.Core.Repository;
public partial class FileRepository
{
public PluginConfig GetPluginConfig()
{
if (_pluginConfig != null)
{
return _pluginConfig;
}
var dir = Path.Combine(_dbSettings.FileRepository, "plugins");
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
var configFile = Path.Combine(dir, "config.json");
if (!File.Exists(configFile))
{
_pluginConfig = new PluginConfig();
return _pluginConfig;
}
var json = File.ReadAllText(configFile);
_pluginConfig = JsonSerializer.Deserialize<PluginConfig>(json, _options);
return _pluginConfig;
}
public void SavePluginConfig(PluginConfig config)
{
var configFile = Path.Combine(_dbSettings.FileRepository, "plugins", "config.json");
File.WriteAllText(configFile, JsonSerializer.Serialize(config, _options));
}
}

View file

@ -0,0 +1,82 @@
using BotSharp.Abstraction.Agents.Models;
using BotSharp.Abstraction.Users.Models;
using System.IO;
namespace BotSharp.Core.Repository;
public partial class FileRepository
{
public void Add<TTableInterface>(object entity)
{
if (entity is Agent agent)
{
_agents.Add(agent);
_changedTableNames.Add(nameof(Agent));
}
else if (entity is User user)
{
_users.Add(user);
_changedTableNames.Add(nameof(User));
}
else if (entity is UserAgent userAgent)
{
_userAgents.Add(userAgent);
_changedTableNames.Add(nameof(UserAgent));
}
}
private readonly List<string> _changedTableNames = new List<string>();
public int Transaction<TTableInterface>(Action action)
{
_changedTableNames.Clear();
action();
// Persist to disk
foreach (var table in _changedTableNames)
{
if (table == nameof(Agent))
{
foreach (var agent in _agents)
{
var dir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir, agent.Id);
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
var path = Path.Combine(dir, AGENT_FILE);
File.WriteAllText(path, JsonSerializer.Serialize(agent, _options));
}
}
else if (table == nameof(User))
{
foreach (var user in _users)
{
var dir = Path.Combine(_dbSettings.FileRepository, "users", user.Id);
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
var path = Path.Combine(dir, USER_FILE);
File.WriteAllText(path, JsonSerializer.Serialize(user, _options));
}
}
else if (table == nameof(UserAgent))
{
_userAgents.GroupBy(x => x.UserId)
.Select(x => x.Key).ToList()
.ForEach(uid =>
{
var agents = _userAgents.Where(x => x.UserId == uid).ToList();
if (agents.Any())
{
var dir = Path.Combine(_dbSettings.FileRepository, "users", uid);
var path = Path.Combine(dir, USER_AGENT_FILE);
File.WriteAllText(path, JsonSerializer.Serialize(agents, _options));
}
});
}
}
return _changedTableNames.Count;
}
}

View file

@ -10,10 +10,11 @@ using BotSharp.Abstraction.Repositories.Models;
using BotSharp.Abstraction.Routing.Settings;
using BotSharp.Abstraction.Evaluations.Settings;
using System.Text.Encodings.Web;
using BotSharp.Abstraction.Plugins.Models;
namespace BotSharp.Core.Repository;
public class FileRepository : IBotSharpRepository
public partial class FileRepository : IBotSharpRepository
{
private readonly IServiceProvider _services;
private readonly BotSharpDatabaseSettings _dbSettings;
@ -31,6 +32,7 @@ public class FileRepository : IBotSharpRepository
private const string DIALOG_FILE = "dialogs.txt";
private const string STATE_FILE = "state.json";
private const string EXECUTION_LOG_FILE = "execution.log";
private const string PLUGIN_CONFIG_FILE = "config.json";
public FileRepository(
IServiceProvider services,
@ -59,6 +61,7 @@ public class FileRepository : IBotSharpRepository
private List<Agent> _agents = new List<Agent>();
private List<UserAgent> _userAgents = new List<UserAgent>();
private List<Conversation> _conversations = new List<Conversation>();
private PluginConfig? _pluginConfig = null;
private IQueryable<User> Users
{
@ -150,81 +153,6 @@ public class FileRepository : IBotSharpRepository
}
}
public void Add<TTableInterface>(object entity)
{
if (entity is Agent agent)
{
_agents.Add(agent);
_changedTableNames.Add(nameof(Agent));
}
else if (entity is User user)
{
_users.Add(user);
_changedTableNames.Add(nameof(User));
}
else if (entity is UserAgent userAgent)
{
_userAgents.Add(userAgent);
_changedTableNames.Add(nameof(UserAgent));
}
}
List<string> _changedTableNames = new List<string>();
public int Transaction<TTableInterface>(Action action)
{
_changedTableNames.Clear();
action();
// Persist to disk
foreach (var table in _changedTableNames)
{
if (table == nameof(Agent))
{
foreach (var agent in _agents)
{
var dir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir, agent.Id);
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
var path = Path.Combine(dir, AGENT_FILE);
File.WriteAllText(path, JsonSerializer.Serialize(agent, _options));
}
}
else if (table == nameof(User))
{
foreach (var user in _users)
{
var dir = Path.Combine(_dbSettings.FileRepository, "users", user.Id);
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
var path = Path.Combine(dir, USER_FILE);
File.WriteAllText(path, JsonSerializer.Serialize(user, _options));
}
}
else if (table == nameof(UserAgent))
{
_userAgents.GroupBy(x => x.UserId)
.Select(x => x.Key).ToList()
.ForEach(uid =>
{
var agents = _userAgents.Where(x => x.UserId == uid).ToList();
if (agents.Any())
{
var dir = Path.Combine(_dbSettings.FileRepository, "users", uid);
var path = Path.Combine(dir, USER_AGENT_FILE);
File.WriteAllText(path, JsonSerializer.Serialize(agents, _options));
}
});
}
}
return _changedTableNames.Count;
}
#region Agent
public void UpdateAgent(Agent agent, AgentField field)
{

View file

@ -0,0 +1,9 @@
{
"Comment": "User can change this configuration dynamically and reflect updates to UI.",
"EnabledPlugins": [
"058094a7-4ad3-4284-b94d-ac1373cf63d8",
"65185362-392c-44fd-a023-95a198824436",
"5b18ca9b-82ed-494b-b121-e3499661edb0",
"6e52d42d-1e23-406b-8599-36af36c83209"
]
}

View file

@ -20,7 +20,7 @@ public class PluginController : ControllerBase
public List<PluginDef> GetPlugins()
{
var loader = _services.GetRequiredService<PluginLoader>();
return loader.GetPlugins();
return loader.GetPlugins(_services);
}
[HttpGet("/plugin/menu")]
@ -40,11 +40,29 @@ public class PluginController : ControllerBase
new PluginMenuDef("Settings", link: "/page/setting", icon: "bx bx-cog", weight: 32),
};
var loader = _services.GetRequiredService<PluginLoader>();
foreach (var plugin in loader.GetPlugins())
foreach (var plugin in loader.GetPlugins(_services))
{
if (!plugin.Enabled)
{
continue;
}
menus.AddRange(plugin.Menus);
}
menus = menus.OrderBy(x => x.Weight).ToList();
return menus;
}
[HttpPost("/plugin/{id}/enable")]
public PluginDef EnablePlugin([FromRoute] string id)
{
var loader = _services.GetRequiredService<PluginLoader>();
return loader.UpdatePluginStatus(_services, id, true);
}
[HttpPost("/plugin/{id}/disable")]
public PluginDef DisablePluginStats([FromRoute] string id)
{
var loader = _services.GetRequiredService<PluginLoader>();
return loader.UpdatePluginStatus(_services, id, false);
}
}

View file

@ -1,6 +1,5 @@
using BotSharp.Abstraction.MLTasks;
using BotSharp.Abstraction.Plugins;
using BotSharp.Abstraction.Utilities;
using BotSharp.Plugin.AzureOpenAI.Providers;
using BotSharp.Plugin.AzureOpenAI.Settings;
using Microsoft.Extensions.Configuration;
@ -14,6 +13,7 @@ namespace BotSharp.Platform.AzureAi;
/// </summary>
public class AzureOpenAiPlugin : IBotSharpPlugin
{
public string Id => "65185362-392c-44fd-a023-95a198824436";
public string Name => "Azure OpenAI";
public string Description => "Azure OpenAI Service (ChatGPT 3.5 Turbo / 4.0)";
public string IconUrl => "https://nanfor.com/cdn/shop/files/cursos-propios-Azure-openAI.jpg?v=1692877741";

View file

@ -9,6 +9,7 @@ namespace BotSharp.Plugin.ChatHub;
/// </summary>
public class ChatHubPlugin : IBotSharpPlugin
{
public string Id => "6e52d42d-1e23-406b-8599-36af36c83209";
public string Name => "Chat Hub";
public string Description => "A communication channel connects agents and users in real-time.";
public string IconUrl => "https://media.zeemly.com/media/product/chatrandom.png";

View file

@ -6,6 +6,7 @@ namespace BotSharp.Plugin.GoogleAI;
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 IconUrl => "https://vectorseek.com/wp-content/uploads/2021/12/Google-AI-Logo-Vector.png";

View file

@ -4,6 +4,7 @@ namespace BotSharp.Plugin.HttpHandler;
public class HttpHandlerPlugin : IBotSharpPlugin
{
public string Id => "2c1eb1c4-16e5-4c65-8ee4-032324c26b81";
public string Name => "HTTP Handler";
public string Description => "Empower agent to handle HTTP request in RESTful API or GraphQL";
public string IconUrl => "https://lirp.cdn-website.com/6f8d6d8a/dms3rep/multi/opt/API_Icon-640w.png";

View file

@ -8,6 +8,7 @@ namespace BotSharp.Plugin.HuggingFace;
public class HuggingFacePlugin : IBotSharpPlugin
{
public string Id => "4495c3d6-49bd-464e-92fb-c99049854cb7";
public string Name => "Hugging Face";
public string Description => "The Home of Machine Learning - Create, discover and collaborate on ML better.";
public string IconUrl => "https://upload.wikimedia.org/wikipedia/he/e/ee/Hugging_Face_logo.png";

View file

@ -5,6 +5,7 @@ namespace BotSharp.Plugin.KnowledgeBase;
public class KnowledgeBasePlugin : IBotSharpPlugin
{
public string Id => "f1625e9f-8de5-467b-b230-556364d8b117";
public string Name => "Knowledge Base";
public string Description => "Embedding private data and feed them into LLM in the conversation.";
public string IconUrl => "https://cdn-icons-png.flaticon.com/512/9592/9592995.png";

View file

@ -4,6 +4,7 @@ namespace BotSharp.Plugin.KnowledgeBase.MemVecDb;
public class MemVecDbPlugin : IBotSharpPlugin
{
public string Id => "5ae38f52-4fa4-4f7c-8582-0a00d1f9a412";
public string Name => "Memory Vector DB";
public string Description => "Store text embedding, search similar text from memory.";
public void RegisterDI(IServiceCollection services, IConfiguration config)

View file

@ -5,6 +5,7 @@ namespace BotSharp.Plugins.LLamaSharp;
public class LLamaSharpPlugin : IBotSharpPlugin
{
public string Id => "3999f668-9fbf-4a91-bd4d-df5b7dfcd90e";
public string Name => "LLamaSharp";
public string Description => "The C#/.NET binding of llama.cpp. Run local LLaMA/GPT model easily and fast in C#!";
public string IconUrl => "https://raw.githubusercontent.com/SciSharp/LLamaSharp/master/Assets/LLamaSharpLogo.png";

View file

@ -11,6 +11,7 @@ namespace BotSharp.Plugin.MetaAI;
public class MetaAiPlugin : IBotSharpPlugin
{
public string Id => "5b18ca9b-82ed-494b-b121-e3499661edb0";
public string Name => "Meta AI";
public string Description => "Innovating with the freedom to explore, discover and apply AI at scale.";
public string IconUrl => "https://static.xx.fbcdn.net/rsrc.php/yJ/r/C1E_YZIckM5.svg";

View file

@ -7,6 +7,7 @@ namespace BotSharp.Plugin.MetaMessenger;
/// </summary>
public class MetaMessengerPlugin : IBotSharpPlugin
{
public string Id => "3694d49c-ddc4-43ea-b019-4d3b373ad570";
public string Name => "Meta Messenger";
public string Description => "Messaging service that allows users to connect with others and share content.";
public string IconUrl => "https://static.xx.fbcdn.net/rsrc.php/yJ/r/C1E_YZIckM5.svg";

View file

@ -7,6 +7,7 @@ namespace BotSharp.Plugin.MongoStorage;
/// </summary>
public class MongoStoragePlugin : IBotSharpPlugin
{
public string Id => "058094a7-4ad3-4284-b94d-ac1373cf63d8";
public string Name => "MongoDB Storage";
public string Description => "MongoDB as the repository, store data in document.";
public string IconUrl => "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRrFrT-_0VYV4PraApwSUmsf4pBGWgvLTaLZGUd7942FxjErsA5iaL4n5Q7CplOmVtwEQ&usqp=CAU";

View file

@ -2,6 +2,7 @@ using BotSharp.Abstraction.Agents.Models;
using BotSharp.Abstraction.Conversations.Models;
using BotSharp.Abstraction.Evaluations.Settings;
using BotSharp.Abstraction.Functions.Models;
using BotSharp.Abstraction.Plugins.Models;
using BotSharp.Abstraction.Repositories.Filters;
using BotSharp.Abstraction.Repositories.Models;
using BotSharp.Abstraction.Routing.Models;
@ -175,6 +176,18 @@ public class MongoRepository : IBotSharpRepository
return _changedTableNames.Count;
}
#region Plugin
public PluginConfig GetPluginConfig()
{
return new PluginConfig();
}
public void SavePluginConfig(PluginConfig config)
{
}
#endregion
#region Agent
public void UpdateAgent(Agent agent, AgentField field)
{
@ -971,5 +984,6 @@ public class MongoRepository : IBotSharpRepository
_dc.LlmCompletionLogs.UpdateOne(filter, update, _options);
}
#endregion
}

View file

@ -10,6 +10,7 @@ namespace BotSharp.Plugin.PaddleOCR;
public class PaddleSharpPlugin : IBotSharpPlugin
{
public string Id => "89746428-e2a1-415d-a9da-5eeaee8bb358";
public string Name => "PaddlePaddle";
public string Description => "An Open-Source Deep Learning Platform Originated from Industrial Practice";
public string IconUrl => "https://miro.medium.com/v2/resize:fit:549/1*oZeecXkOoTzEYp-btIKwxw.jpeg";

View file

@ -7,6 +7,7 @@ namespace BotSharp.Plugin.Qdrant;
public class QdrantPlugin : IBotSharpPlugin
{
public string Id => "9e087f80-0f50-45bf-a87a-c1099af8f18e";
public string Name => "Qdrant";
public string Description => "Vector Database - Make the most of your Unstructured Data";
public string IconUrl => "https://qdrant.tech/images/logo_with_text.png";

View file

@ -10,6 +10,7 @@ namespace BotSharp.Plugin.RoutingSpeeder;
public class RoutingSpeederPlugin : IBotSharpPlugin
{
public string Id => "e7dff028-462d-47d2-85aa-dc56a6d362ee";
public void RegisterDI(IServiceCollection services, IConfiguration config)
{
var settings = new RouterSpeederSettings();

View file

@ -11,6 +11,7 @@ namespace BotSharp.Plugin.SemanticKernel
/// </summary>
public class SemanticKernelPlugin : IBotSharpPlugin
{
public string Id => "849e5ab9-276f-4cf1-8041-c089fe1a1aeb";
/// <inheritdoc/>
public string Name => "Semantic Kernel";

View file

@ -7,6 +7,7 @@ namespace BotSharp.Plugin.TelegramBots
{
public class TelegramBotsPlugin : IBotSharpPlugin
{
public string Id => "6cc8c2f0-0958-4ace-adec-1df609ec9e00";
public string Name => "Telegram Bots";
public string Description => "Bots are small applications that run entirely within the Telegram app.";

View file

@ -4,6 +4,7 @@ namespace BotSharp.Plugin.Twilio;
public class TwilioPlugin : IBotSharpPlugin
{
public string Id => "943ffd4d-ac8b-44aa-8a1c-38c9279c1b65";
public string Name => "Twilio";
public string Description => "Communication APIs for SMS, Voice, Video & Authentication";

View file

@ -18,6 +18,7 @@ namespace BotSharp.Plugin.WeChat;
public class WeChatPlugin : IBotSharpAppPlugin
{
public string Id => "f5e5113b-c1de-4d69-b4b1-9bc6efed7253";
public string Name => "Tecent Wechat";
public string Description => "Free messaging and calling app, support voice,photo,video and text messages.";
public string IconUrl => "https://i.pinimg.com/originals/66/c9/44/66c94415043811725165e59b371a0aa2.png";

View file

@ -6,6 +6,7 @@ namespace BotSharp.Plugin.Playwrights;
public class WebDriverPlugin : IBotSharpPlugin
{
public string Id => "f0e26bc3-cfde-4b63-845c-c9c542abea44";
public string Name => "Web Driver";
public string Description => "Empower agent to manipulate web browser in automation tools.";
public string IconUrl => "https://cdn-icons-png.flaticon.com/512/8576/8576378.png";

View file

@ -5,6 +5,7 @@ namespace BotSharp.Plugin.PizzaBot;
public class PizzaBotPlugin : IBotSharpPlugin
{
public string Id => "1c8270eb-de63-4ca0-8903-654d83ce5ece";
public string Name => "Pizza AI Assistant";
public string Description => "An example of an enterprise-grade AI Chatbot.";
public string IconUrl => "https://cdn-icons-png.flaticon.com/512/6978/6978255.png";