This commit is contained in:
Haiping Chen 2024-01-10 08:18:59 -06:00
parent e7e092cadc
commit 24319f5213
15 changed files with 258 additions and 41 deletions

View file

@ -43,11 +43,13 @@ It's written in C# running on .Net Core that is full cross-platform framework, t
```sh ```sh
PS D:\> git clone https://github.com/SciSharp/BotSharp-UI PS D:\> git clone https://github.com/SciSharp/BotSharp-UI
PS D:\> cd BotSharp-UI PS D:\> cd BotSharp-UI
PS D:\> npm install --force PS D:\> npm install
PS D:\> npm run dev PS D:\> npm run dev
``` ```
Access http://localhost:5015/ Access http://localhost:5015/
[Online Demo with UI](https://botsharp.azurewebsites.net/)
<img src="./docs/static/screenshots/agent-builder-agents.png" height="450px"/> <img src="./docs/static/screenshots/agent-builder-agents.png" height="450px"/>

View file

@ -29,6 +29,8 @@
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" />
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" /> <PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
<PackageReference Include="System.Text.Json" Version="8.0.0" /> <PackageReference Include="System.Text.Json" Version="8.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="5.0.1" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View file

@ -20,6 +20,7 @@
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.25" /> <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.25" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="6.0.26" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View file

@ -1,26 +1,55 @@
using BotSharp.Abstraction.Messaging.JsonConverters; using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
namespace BotSharp.OpenAPI; namespace BotSharp.OpenAPI;
public static class BotSharpOpenApiExtensions public static class BotSharpOpenApiExtensions
{ {
public static IServiceCollection AddBotSharpOpenAPI(this IServiceCollection services, IConfiguration config) /// <summary>
/// Use Swagger/OpenAPI
/// </summary>
/// <param name="services"></param>
/// <param name="config"></param>
/// <returns></returns>
public static IApplicationBuilder UseBotSharpOpenAPI(this IApplicationBuilder app, bool isDevelopment = false)
{ {
// Add services to the container. if (app == null)
services.AddControllers() {
.AddJsonOptions(options => throw new ArgumentNullException(nameof(app));
}
app.UseSwagger();
if (isDevelopment)
{
app.UseSwaggerUI();
}
return app;
}
/// <summary>
/// Host BotSharp UI built in adapter-static
/// </summary>
/// <param name="app"></param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
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()); config.UseProxyToSpaDevelopmentServer("http://localhost:5015");
options.JsonSerializerOptions.Converters.Add(new TemplateMessageJsonConverter()); }
}); });
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle return app;
services.AddEndpointsApiExplorer();
services.AddSwaggerGen();
services.AddHttpContextAccessor();
return services;
} }
} }

View file

@ -1,3 +1,4 @@
using BotSharp.Abstraction.Loggers;
using BotSharp.Plugin.ChatHub.Hooks; using BotSharp.Plugin.ChatHub.Hooks;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
@ -16,5 +17,6 @@ public class ChatHubPlugin : IBotSharpPlugin
{ {
// Register hooks // Register hooks
services.AddScoped<IConversationHook, ChatHubConversationHook>(); services.AddScoped<IConversationHook, ChatHubConversationHook>();
services.AddScoped<IContentGeneratingHook, StreamingLogHook>();
} }
} }

View file

@ -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
{
/// <summary>
/// Add Swagger/OpenAPI
/// </summary>
/// <param name="services"></param>
/// <param name="config"></param>
/// <returns></returns>
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;
}
/// <summary>
/// Host BotSharp UI built in adapter-static
/// </summary>
/// <param name="app"></param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
public static IApplicationBuilder UseChatHub(this IApplicationBuilder app)
{
if (app == null)
{
throw new ArgumentNullException(nameof(app));
}
app.UseMiddleware<WebSocketsMiddleware>();
return app;
}
}

View file

@ -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<SignalRHub> _chatHub;
public StreamingLogHook(
ConversationSetting convSettings,
IServiceProvider serivces,
IHubContext<SignalRHub> chatHub)
{
_convSettings = convSettings;
_services = serivces;
_chatHub = chatHub;
}
public async Task BeforeGenerating(Agent agent, List<RoleDialogModel> conversations)
{
if (!_convSettings.ShowVerboseLog) return;
var user = _services.GetRequiredService<IUserIdentity>();
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<IAgentService>();
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<IUserIdentity>();
await _chatHub.Clients.User(user.Id).SendAsync("OnContentLogGenerated", tokenStats.Prompt);
await _chatHub.Clients.User(user.Id).SendAsync("OnContentLogGenerated", log);
}
}

View file

@ -49,4 +49,9 @@ public class SignalRHub : Hub
await base.OnConnectedAsync(); await base.OnConnectedAsync();
} }
public Task PushEventLog(string message)
{
return Task.CompletedTask;
}
} }

View file

@ -1,5 +1,4 @@
using BotSharp.Abstraction.Functions; using BotSharp.Abstraction.Functions;
using BotSharp.Abstraction.Routing.Models;
using BotSharp.Plugin.KnowledgeBase.LlmContexts; using BotSharp.Plugin.KnowledgeBase.LlmContexts;
namespace BotSharp.Plugin.KnowledgeBase.Functions; namespace BotSharp.Plugin.KnowledgeBase.Functions;

View file

@ -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<string>();
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($"<input name='{name}' type='{type}'>{text}</input>");
}
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($"<textarea name='{name}' type='{type}'>{text}</textarea>");
}
var driverService = _services.GetRequiredService<WebDriverService>();
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);
}
}
}

View file

@ -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<bool> Execute(RoleDialogModel message)
{
var args = JsonSerializer.Deserialize<BrowsingContextIn>(message.FunctionArgs);
var agentService = _services.GetRequiredService<IAgentService>();
var agent = await agentService.LoadAgent(message.CurrentAgentId);
await _driver.ChangeListValue(agent, args, message.MessageId);
message.Content = "Update successfully.";
return true;
}
}

View file

@ -13,6 +13,9 @@ public class BrowsingContextIn
[JsonPropertyName("input_text")] [JsonPropertyName("input_text")]
public string? InputText { get; set; } public string? InputText { get; set; }
[JsonPropertyName("update_value")]
public string? UpdateValue { get; set; }
[JsonPropertyName("password")] [JsonPropertyName("password")]
public string? Password { get; set; } public string? Password { get; set; }

View file

@ -11,13 +11,17 @@ using Serilog;
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
Log.Logger = new LoggerConfiguration() var loggerConfig = new LoggerConfiguration();
Log.Logger = loggerConfig
#if DEBUG
.MinimumLevel.Debug() .MinimumLevel.Debug()
#else
.MinimumLevel.Warning()
#endif
.WriteTo.Console() .WriteTo.Console()
.WriteTo.File("logs/log-.txt", rollingInterval: RollingInterval.Day) .WriteTo.File("logs/log-.txt", rollingInterval: RollingInterval.Day)
.CreateLogger(); .CreateLogger();
builder.Host.UseSerilog();
builder.Host.UseSerilog(Log.Logger);
builder.Services.AddScoped<IUserIdentity, UserIdentity>(); builder.Services.AddScoped<IUserIdentity, UserIdentity>();
// Add bearer authentication // Add bearer authentication
@ -48,7 +52,8 @@ builder.Services.AddBotSharpLogger(builder.Configuration);
builder.Services.AddCors(options => builder.Services.AddCors(options =>
{ {
options.AddPolicy("MyCorsPolicy", options.AddPolicy("MyCorsPolicy",
builder => builder.WithOrigins("http://localhost:5015", builder => builder.WithOrigins("http://localhost:5015",
"http://localhost:5500",
"https://botsharp.scisharpstack.org", "https://botsharp.scisharpstack.org",
"https://chat.scisharpstack.org") "https://chat.scisharpstack.org")
.AllowAnyMethod() .AllowAnyMethod()
@ -61,14 +66,8 @@ builder.Services.AddSignalR();
var app = builder.Build(); var app = builder.Build();
// Configure the HTTP request pipeline. // Configure the HTTP request pipeline.
app.UseSwagger();
if (app.Environment.IsDevelopment())
{
app.UseSwaggerUI();
}
app.MapHub<SignalRHub>("/chatHub"); app.MapHub<SignalRHub>("/chatHub");
app.UseMiddleware<WebSocketsMiddleware>(); app.UseChatHub();
app.UseAuthentication(); app.UseAuthentication();
app.UseAuthorization(); app.UseAuthorization();
@ -77,12 +76,9 @@ app.MapControllers();
// Use BotSharp // Use BotSharp
app.UseBotSharp(); app.UseBotSharp();
app.UseBotSharpOpenAPI();
app.UseBotSharpUI();
app.UseCors("MyCorsPolicy"); app.UseCors("MyCorsPolicy");
// Host BotSharp UI built in adapter-static
app.UseFileServer();
app.UseDefaultFiles();
app.UseStaticFiles();
app.Run(); app.Run();

View file

@ -29,18 +29,15 @@
<EmbeddedResource Remove="logs\**" /> <EmbeddedResource Remove="logs\**" />
<None Remove="logs\**" /> <None Remove="logs\**" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Serilog.Sinks.Console" Version="5.0.1" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="Serilog.Extensions.Hosting" Version="8.0.0" /> <PackageReference Include="Serilog.Extensions.Hosting" Version="8.0.0" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.5" /> <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.6" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\tests\BotSharp.Plugin.PizzaBot\BotSharp.Plugin.PizzaBot.csproj" /> <ProjectReference Include="..\..\tests\BotSharp.Plugin.PizzaBot\BotSharp.Plugin.PizzaBot.csproj" />
<ProjectReference Include="..\Plugins\BotSharp.Plugin.WebDriver\BotSharp.Plugin.WebDriver.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="$(SolutionName)==BotSharp"> <ItemGroup Condition="$(SolutionName)==BotSharp">

View file

@ -155,7 +155,8 @@
"BotSharp.Plugin.Qdrant", "BotSharp.Plugin.Qdrant",
"BotSharp.Plugin.ChatHub", "BotSharp.Plugin.ChatHub",
"BotSharp.Plugin.WeChat", "BotSharp.Plugin.WeChat",
"BotSharp.Plugin.PizzaBot" "BotSharp.Plugin.PizzaBot",
"BotSharp.Plugin.WebDriver"
] ]
} }
} }