diff --git a/README.md b/README.md
index 4c1e238f..12541290 100644
--- a/README.md
+++ b/README.md
@@ -43,11 +43,13 @@ It's written in C# running on .Net Core that is full cross-platform framework, t
```sh
PS D:\> git clone https://github.com/SciSharp/BotSharp-UI
PS D:\> cd BotSharp-UI
-PS D:\> npm install --force
+PS D:\> npm install
PS D:\> npm run dev
```
-Access http://localhost:5015/
+Access http://localhost:5015/
+
+[Online Demo with UI](https://botsharp.azurewebsites.net/)
diff --git a/src/Infrastructure/BotSharp.Abstraction/BotSharp.Abstraction.csproj b/src/Infrastructure/BotSharp.Abstraction/BotSharp.Abstraction.csproj
index fa407847..37fee33c 100644
--- a/src/Infrastructure/BotSharp.Abstraction/BotSharp.Abstraction.csproj
+++ b/src/Infrastructure/BotSharp.Abstraction/BotSharp.Abstraction.csproj
@@ -29,6 +29,8 @@
+
+
diff --git a/src/Infrastructure/BotSharp.OpenAPI/BotSharp.OpenAPI.csproj b/src/Infrastructure/BotSharp.OpenAPI/BotSharp.OpenAPI.csproj
index a5166571..36adcf88 100644
--- a/src/Infrastructure/BotSharp.OpenAPI/BotSharp.OpenAPI.csproj
+++ b/src/Infrastructure/BotSharp.OpenAPI/BotSharp.OpenAPI.csproj
@@ -20,6 +20,7 @@
+
diff --git a/src/Infrastructure/BotSharp.OpenAPI/BotSharpOpenApiExtensions.cs b/src/Infrastructure/BotSharp.OpenAPI/BotSharpOpenApiExtensions.cs
index 89b9555f..44194444 100644
--- a/src/Infrastructure/BotSharp.OpenAPI/BotSharpOpenApiExtensions.cs
+++ b/src/Infrastructure/BotSharp.OpenAPI/BotSharpOpenApiExtensions.cs
@@ -1,26 +1,55 @@
-using BotSharp.Abstraction.Messaging.JsonConverters;
-using Microsoft.Extensions.Configuration;
+using Microsoft.AspNetCore.Builder;
namespace BotSharp.OpenAPI;
public static class BotSharpOpenApiExtensions
{
- public static IServiceCollection AddBotSharpOpenAPI(this IServiceCollection services, IConfiguration config)
+ ///
+ /// Use Swagger/OpenAPI
+ ///
+ ///
+ ///
+ ///
+ public static IApplicationBuilder UseBotSharpOpenAPI(this IApplicationBuilder app, bool isDevelopment = false)
{
- // Add services to the container.
- services.AddControllers()
- .AddJsonOptions(options =>
+ if (app == null)
+ {
+ throw new ArgumentNullException(nameof(app));
+ }
+
+ app.UseSwagger();
+ if (isDevelopment)
+ {
+ app.UseSwaggerUI();
+ }
+
+ return app;
+ }
+
+ ///
+ /// Host BotSharp UI built in adapter-static
+ ///
+ ///
+ ///
+ ///
+ public static IApplicationBuilder UseBotSharpUI(this IApplicationBuilder app, bool isDevelopment = false)
+ {
+ if (app == null)
+ {
+ throw new ArgumentNullException(nameof(app));
+ }
+
+ // app.UseFileServer();
+ app.UseDefaultFiles();
+ app.UseStaticFiles();
+ app.UseSpa(config =>
+ {
+ if (isDevelopment)
{
- options.JsonSerializerOptions.Converters.Add(new RichContentJsonConverter());
- options.JsonSerializerOptions.Converters.Add(new TemplateMessageJsonConverter());
- });
+ config.UseProxyToSpaDevelopmentServer("http://localhost:5015");
+ }
+ });
- // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
- services.AddEndpointsApiExplorer();
- services.AddSwaggerGen();
-
- services.AddHttpContextAccessor();
-
- return services;
+ return app;
}
}
diff --git a/src/Plugins/BotSharp.Plugin.ChatHub/ChatHubPlugin.cs b/src/Plugins/BotSharp.Plugin.ChatHub/ChatHubPlugin.cs
index b085bef7..23e7e6d0 100644
--- a/src/Plugins/BotSharp.Plugin.ChatHub/ChatHubPlugin.cs
+++ b/src/Plugins/BotSharp.Plugin.ChatHub/ChatHubPlugin.cs
@@ -1,3 +1,4 @@
+using BotSharp.Abstraction.Loggers;
using BotSharp.Plugin.ChatHub.Hooks;
using Microsoft.Extensions.Configuration;
@@ -16,5 +17,6 @@ public class ChatHubPlugin : IBotSharpPlugin
{
// Register hooks
services.AddScoped();
+ services.AddScoped();
}
}
diff --git a/src/Plugins/BotSharp.Plugin.ChatHub/ChatHubServiceExtensions.cs b/src/Plugins/BotSharp.Plugin.ChatHub/ChatHubServiceExtensions.cs
new file mode 100644
index 00000000..c67685e5
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.ChatHub/ChatHubServiceExtensions.cs
@@ -0,0 +1,51 @@
+using BotSharp.Abstraction.Messaging.JsonConverters;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.Extensions.Configuration;
+
+namespace BotSharp.Plugin.ChatHub;
+
+public static class ChatHubServiceExtensions
+{
+ ///
+ /// Add Swagger/OpenAPI
+ ///
+ ///
+ ///
+ ///
+ public static IServiceCollection AddBotSharpOpenAPI(this IServiceCollection services, IConfiguration config)
+ {
+ // Add services to the container.
+ services.AddControllers()
+ .AddJsonOptions(options =>
+ {
+ options.JsonSerializerOptions.Converters.Add(new RichContentJsonConverter());
+ options.JsonSerializerOptions.Converters.Add(new TemplateMessageJsonConverter());
+ });
+
+ // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
+ services.AddEndpointsApiExplorer();
+ services.AddSwaggerGen();
+
+ services.AddHttpContextAccessor();
+
+ return services;
+ }
+
+ ///
+ /// Host BotSharp UI built in adapter-static
+ ///
+ ///
+ ///
+ ///
+ public static IApplicationBuilder UseChatHub(this IApplicationBuilder app)
+ {
+ if (app == null)
+ {
+ throw new ArgumentNullException(nameof(app));
+ }
+
+ app.UseMiddleware();
+
+ return app;
+ }
+}
diff --git a/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/StreamingLogHook.cs b/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/StreamingLogHook.cs
new file mode 100644
index 00000000..d521badc
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/StreamingLogHook.cs
@@ -0,0 +1,49 @@
+using BotSharp.Abstraction.Agents.Models;
+using BotSharp.Abstraction.Loggers;
+using BotSharp.Abstraction.Users.Models;
+using Microsoft.AspNetCore.SignalR;
+
+namespace BotSharp.Plugin.ChatHub.Hooks;
+
+public class StreamingLogHook : IContentGeneratingHook
+{
+ private readonly ConversationSetting _convSettings;
+ private readonly IServiceProvider _services;
+ private readonly IHubContext _chatHub;
+
+ public StreamingLogHook(
+ ConversationSetting convSettings,
+ IServiceProvider serivces,
+ IHubContext chatHub)
+ {
+ _convSettings = convSettings;
+ _services = serivces;
+ _chatHub = chatHub;
+ }
+
+ public async Task BeforeGenerating(Agent agent, List conversations)
+ {
+ if (!_convSettings.ShowVerboseLog) return;
+
+ var user = _services.GetRequiredService();
+ var dialog = conversations.Last();
+ var log = $"{dialog.Role}: {dialog.Content} [msg_id: {dialog.MessageId}] ==>";
+ await _chatHub.Clients.User(user.Id).SendAsync("OnContentLogGenerated", log);
+ }
+
+ public async Task AfterGenerated(RoleDialogModel message, TokenStatsModel tokenStats)
+ {
+ if (!_convSettings.ShowVerboseLog) return;
+
+ var agentService = _services.GetRequiredService();
+ var agent = await agentService.LoadAgent(message.CurrentAgentId);
+
+ var log = message.Role == AgentRole.Function ?
+ $"[{agent?.Name}]: {message.FunctionName}({message.FunctionArgs})" :
+ $"[{agent?.Name}]: {message.Content}" + $" <== [msg_id: {message.MessageId}]";
+
+ var user = _services.GetRequiredService();
+ await _chatHub.Clients.User(user.Id).SendAsync("OnContentLogGenerated", tokenStats.Prompt);
+ await _chatHub.Clients.User(user.Id).SendAsync("OnContentLogGenerated", log);
+ }
+}
diff --git a/src/Plugins/BotSharp.Plugin.ChatHub/SignalRHub.cs b/src/Plugins/BotSharp.Plugin.ChatHub/SignalRHub.cs
index 0593b94f..f11bbc82 100644
--- a/src/Plugins/BotSharp.Plugin.ChatHub/SignalRHub.cs
+++ b/src/Plugins/BotSharp.Plugin.ChatHub/SignalRHub.cs
@@ -49,4 +49,9 @@ public class SignalRHub : Hub
await base.OnConnectedAsync();
}
+
+ public Task PushEventLog(string message)
+ {
+ return Task.CompletedTask;
+ }
}
diff --git a/src/Plugins/BotSharp.Plugin.KnowledgeBase/Functions/SearchKnowledgesFn.cs b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Functions/SearchKnowledgesFn.cs
index 5d94f9cb..f2bad9bf 100644
--- a/src/Plugins/BotSharp.Plugin.KnowledgeBase/Functions/SearchKnowledgesFn.cs
+++ b/src/Plugins/BotSharp.Plugin.KnowledgeBase/Functions/SearchKnowledgesFn.cs
@@ -1,5 +1,4 @@
using BotSharp.Abstraction.Functions;
-using BotSharp.Abstraction.Routing.Models;
using BotSharp.Plugin.KnowledgeBase.LlmContexts;
namespace BotSharp.Plugin.KnowledgeBase.Functions;
diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.ChangeListValue.cs b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.ChangeListValue.cs
new file mode 100644
index 00000000..2c08a0ad
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.ChangeListValue.cs
@@ -0,0 +1,49 @@
+using BotSharp.Plugin.WebDriver.Services;
+
+namespace BotSharp.Plugin.WebDriver.Drivers.PlaywrightDriver;
+
+public partial class PlaywrightWebDriver
+{
+ public async Task ChangeListValue(Agent agent, BrowsingContextIn context, string messageId)
+ {
+ // Retrieve the page raw html and infer the element path
+ var body = await _instance.Page.QuerySelectorAsync("body");
+
+ var str = new List();
+ var inputs = await body.QuerySelectorAllAsync("input");
+ foreach (var input in inputs)
+ {
+ var text = await input.TextContentAsync();
+ var name = await input.GetAttributeAsync("name");
+ var type = await input.GetAttributeAsync("type");
+ str.Add($"{text}");
+ }
+
+ inputs = await body.QuerySelectorAllAsync("textarea");
+ foreach (var input in inputs)
+ {
+ var text = await input.TextContentAsync();
+ var name = await input.GetAttributeAsync("name");
+ var type = await input.GetAttributeAsync("type");
+ str.Add($"");
+ }
+
+ var driverService = _services.GetRequiredService();
+ var htmlElementContextOut = await driverService.LocateElement(agent, string.Join("", str), context.ElementName, messageId);
+
+ if (htmlElementContextOut.Index < 0)
+ {
+ throw new Exception($"Can't locate the web element {context.ElementName}.");
+ }
+
+ var element = _instance.Page.Locator(htmlElementContextOut.TagName).Nth(htmlElementContextOut.Index);
+ try
+ {
+ await element.FillAsync(context.InputText);
+ }
+ catch (Exception ex)
+ {
+ throw new Exception(ex.Message);
+ }
+ }
+}
diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Functions/ChangeListValueFn.cs b/src/Plugins/BotSharp.Plugin.WebDriver/Functions/ChangeListValueFn.cs
new file mode 100644
index 00000000..4431e1e3
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.WebDriver/Functions/ChangeListValueFn.cs
@@ -0,0 +1,31 @@
+using BotSharp.Abstraction.Agents;
+using BotSharp.Plugin.WebDriver.Drivers.PlaywrightDriver;
+
+namespace BotSharp.Plugin.WebDriver.Functions;
+
+public class ChangeListValueFn : IFunctionCallback
+{
+ public string Name => "change_list_value";
+
+ private readonly IServiceProvider _services;
+ private readonly PlaywrightWebDriver _driver;
+
+ public ChangeListValueFn(IServiceProvider services,
+ PlaywrightWebDriver driver)
+ {
+ _services = services;
+ _driver = driver;
+ }
+
+ public async Task Execute(RoleDialogModel message)
+ {
+ var args = JsonSerializer.Deserialize(message.FunctionArgs);
+
+ var agentService = _services.GetRequiredService();
+ var agent = await agentService.LoadAgent(message.CurrentAgentId);
+ await _driver.ChangeListValue(agent, args, message.MessageId);
+
+ message.Content = "Update successfully.";
+ return true;
+ }
+}
diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/LlmContexts/BrowsingContextIn.cs b/src/Plugins/BotSharp.Plugin.WebDriver/LlmContexts/BrowsingContextIn.cs
index e914c9db..73c2753b 100644
--- a/src/Plugins/BotSharp.Plugin.WebDriver/LlmContexts/BrowsingContextIn.cs
+++ b/src/Plugins/BotSharp.Plugin.WebDriver/LlmContexts/BrowsingContextIn.cs
@@ -13,6 +13,9 @@ public class BrowsingContextIn
[JsonPropertyName("input_text")]
public string? InputText { get; set; }
+ [JsonPropertyName("update_value")]
+ public string? UpdateValue { get; set; }
+
[JsonPropertyName("password")]
public string? Password { get; set; }
diff --git a/src/WebStarter/Program.cs b/src/WebStarter/Program.cs
index 9dd744c7..71850488 100644
--- a/src/WebStarter/Program.cs
+++ b/src/WebStarter/Program.cs
@@ -11,13 +11,17 @@ using Serilog;
var builder = WebApplication.CreateBuilder(args);
-Log.Logger = new LoggerConfiguration()
+var loggerConfig = new LoggerConfiguration();
+Log.Logger = loggerConfig
+#if DEBUG
.MinimumLevel.Debug()
+#else
+ .MinimumLevel.Warning()
+#endif
.WriteTo.Console()
.WriteTo.File("logs/log-.txt", rollingInterval: RollingInterval.Day)
.CreateLogger();
-
-builder.Host.UseSerilog(Log.Logger);
+builder.Host.UseSerilog();
builder.Services.AddScoped();
// Add bearer authentication
@@ -48,7 +52,8 @@ builder.Services.AddBotSharpLogger(builder.Configuration);
builder.Services.AddCors(options =>
{
options.AddPolicy("MyCorsPolicy",
- builder => builder.WithOrigins("http://localhost:5015",
+ builder => builder.WithOrigins("http://localhost:5015",
+ "http://localhost:5500",
"https://botsharp.scisharpstack.org",
"https://chat.scisharpstack.org")
.AllowAnyMethod()
@@ -61,14 +66,8 @@ builder.Services.AddSignalR();
var app = builder.Build();
// Configure the HTTP request pipeline.
-app.UseSwagger();
-if (app.Environment.IsDevelopment())
-{
- app.UseSwaggerUI();
-}
-
app.MapHub("/chatHub");
-app.UseMiddleware();
+app.UseChatHub();
app.UseAuthentication();
app.UseAuthorization();
@@ -77,12 +76,9 @@ app.MapControllers();
// Use BotSharp
app.UseBotSharp();
+app.UseBotSharpOpenAPI();
+app.UseBotSharpUI();
app.UseCors("MyCorsPolicy");
-// Host BotSharp UI built in adapter-static
-app.UseFileServer();
-app.UseDefaultFiles();
-app.UseStaticFiles();
-
app.Run();
diff --git a/src/WebStarter/WebStarter.csproj b/src/WebStarter/WebStarter.csproj
index 3eb14e31..ccc84dea 100644
--- a/src/WebStarter/WebStarter.csproj
+++ b/src/WebStarter/WebStarter.csproj
@@ -29,18 +29,15 @@
-
-
-
-
-
+
+
diff --git a/src/WebStarter/appsettings.json b/src/WebStarter/appsettings.json
index d15ac9bd..2cb7389a 100644
--- a/src/WebStarter/appsettings.json
+++ b/src/WebStarter/appsettings.json
@@ -155,7 +155,8 @@
"BotSharp.Plugin.Qdrant",
"BotSharp.Plugin.ChatHub",
"BotSharp.Plugin.WeChat",
- "BotSharp.Plugin.PizzaBot"
+ "BotSharp.Plugin.PizzaBot",
+ "BotSharp.Plugin.WebDriver"
]
}
}