diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/BuiltInAgentId.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/BuiltInAgentId.cs
new file mode 100644
index 000000000..98aaf4541
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/BuiltInAgentId.cs
@@ -0,0 +1,8 @@
+namespace BotSharp.Abstraction.Agents.Enums;
+
+public class BuiltInAgentId
+{
+ public const string AIAssistant = "01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a";
+ public const string Chatbot = "01e2fc5c-2c89-4ec7-8470-7688608b496c";
+ public const string HumanSupport = "01dcc3e5-0af7-49e6-ad7a-a760bd12dc4b";
+}
diff --git a/src/Infrastructure/BotSharp.Abstraction/BotSharp.Abstraction.csproj b/src/Infrastructure/BotSharp.Abstraction/BotSharp.Abstraction.csproj
index 65424adb4..b03aa12b8 100644
--- a/src/Infrastructure/BotSharp.Abstraction/BotSharp.Abstraction.csproj
+++ b/src/Infrastructure/BotSharp.Abstraction/BotSharp.Abstraction.csproj
@@ -10,6 +10,12 @@
$(SolutionDir)packages
+
+
+
+
+
+
True
diff --git a/src/Infrastructure/BotSharp.Abstraction/Browsing/Models/BrowserActionArgs.cs b/src/Infrastructure/BotSharp.Abstraction/Browsing/Models/BrowserActionArgs.cs
new file mode 100644
index 000000000..1a6920c82
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Abstraction/Browsing/Models/BrowserActionArgs.cs
@@ -0,0 +1,6 @@
+namespace BotSharp.Abstraction.Browsing.Models;
+
+public class BrowserActionArgs
+{
+
+}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Browsing/Models/BrowserActionResult.cs b/src/Infrastructure/BotSharp.Abstraction/Browsing/Models/BrowserActionResult.cs
index b3576b90c..63c592b77 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Browsing/Models/BrowserActionResult.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Browsing/Models/BrowserActionResult.cs
@@ -8,6 +8,7 @@ public class BrowserActionResult
public string Selector { get; set; }
public string Body { get; set; }
public bool IsHighlighted { get; set; }
+ public DateTime? ExecutedAt { get; set; } = DateTime.UtcNow;
public override string ToString()
{
diff --git a/src/Infrastructure/BotSharp.Abstraction/Browsing/Models/ElementLocatingArgs.cs b/src/Infrastructure/BotSharp.Abstraction/Browsing/Models/ElementLocatingArgs.cs
index 3b96c7604..9dd5334ad 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Browsing/Models/ElementLocatingArgs.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Browsing/Models/ElementLocatingArgs.cs
@@ -31,4 +31,5 @@ public class ElementLocatingArgs
/// Draw outline around the element
///
public bool Highlight { get; set; }
+ public string HighlightColor { get; set; } = "red";
}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Browsing/Models/PageActionArgs.cs b/src/Infrastructure/BotSharp.Abstraction/Browsing/Models/PageActionArgs.cs
index 99591b1e3..f583febba 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Browsing/Models/PageActionArgs.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Browsing/Models/PageActionArgs.cs
@@ -11,4 +11,11 @@ public class PageActionArgs
public string Url { get; set; } = null!;
public bool OpenNewTab { get; set; } = false;
+
+ ///
+ /// On page data fetched
+ ///
+ public DataFetched? OnDataFetched { get; set; }
}
+
+public delegate void DataFetched(string url, string data);
diff --git a/src/Infrastructure/BotSharp.Abstraction/Utilities/Pagination.cs b/src/Infrastructure/BotSharp.Abstraction/Utilities/Pagination.cs
index 9ada5f639..ad4f2e3fc 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Utilities/Pagination.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Utilities/Pagination.cs
@@ -37,6 +37,8 @@ public int Offset
{
get { return (Page - 1) * Size; }
}
+
+ public bool ReturnTotal { get; set; } = true;
}
public class PagedItems
diff --git a/src/Infrastructure/BotSharp.Core/Agents/AgentPlugin.cs b/src/Infrastructure/BotSharp.Core/Agents/AgentPlugin.cs
index fa572e67f..43bd9c7f4 100644
--- a/src/Infrastructure/BotSharp.Core/Agents/AgentPlugin.cs
+++ b/src/Infrastructure/BotSharp.Core/Agents/AgentPlugin.cs
@@ -17,9 +17,9 @@ public class AgentPlugin : IBotSharpPlugin
public string[] AgentIds => new string[]
{
- "01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a",
- "01e2fc5c-2c89-4ec7-8470-7688608b496c",
- "01dcc3e5-0af7-49e6-ad7a-a760bd12dc4b"
+ BuiltInAgentId.AIAssistant,
+ BuiltInAgentId.Chatbot,
+ BuiltInAgentId.HumanSupport
};
public object GetNewSettingsInstance() =>
diff --git a/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj b/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj
index 7bdd84645..1ca8b9439 100644
--- a/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj
+++ b/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj
@@ -160,8 +160,7 @@
-
-
+
diff --git a/src/Infrastructure/BotSharp.Core/Using.cs b/src/Infrastructure/BotSharp.Core/Using.cs
index af7bc560d..709285e2c 100644
--- a/src/Infrastructure/BotSharp.Core/Using.cs
+++ b/src/Infrastructure/BotSharp.Core/Using.cs
@@ -36,4 +36,3 @@
global using BotSharp.Core.Infrastructures;
global using BotSharp.Core.Users.Services;
global using Aspects.Cache;
-global using Console = Colorful.Console;
\ No newline at end of file
diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/TranslationController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/TranslationController.cs
new file mode 100644
index 000000000..ac7686a1c
--- /dev/null
+++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/TranslationController.cs
@@ -0,0 +1,30 @@
+using BotSharp.Abstraction.Agents.Models;
+using BotSharp.Abstraction.Translation;
+using BotSharp.OpenAPI.ViewModels.Translations;
+
+namespace BotSharp.OpenAPI.Controllers;
+
+[Authorize]
+[ApiController]
+public class TranslationController : ControllerBase
+{
+ private readonly IServiceProvider _services;
+
+ public TranslationController(IServiceProvider services)
+ {
+ _services = services;
+ }
+
+ [HttpPost("/translate")]
+ public async Task Translate([FromBody] TranslationRequestModel model)
+ {
+ var agentService = _services.GetRequiredService();
+ var agent = await agentService.LoadAgent(BuiltInAgentId.AIAssistant);
+ var translator = _services.GetRequiredService();
+ var text = await translator.Translate(agent, Guid.NewGuid().ToString(), model.Text, language: model.ToLang);
+ return new TranslationResponseModel
+ {
+ Text = text
+ };
+ }
+}
diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Translations/TranslationRequestModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Translations/TranslationRequestModel.cs
new file mode 100644
index 000000000..588dedfcf
--- /dev/null
+++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Translations/TranslationRequestModel.cs
@@ -0,0 +1,9 @@
+using BotSharp.Abstraction.Infrastructures.Enums;
+
+namespace BotSharp.OpenAPI.ViewModels.Translations;
+
+public class TranslationRequestModel
+{
+ public string Text { get; set; } = null!;
+ public string ToLang { get; set; } = LanguageType.CHINESE;
+}
diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Translations/TranslationResponseModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Translations/TranslationResponseModel.cs
new file mode 100644
index 000000000..0c547d2bf
--- /dev/null
+++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Translations/TranslationResponseModel.cs
@@ -0,0 +1,11 @@
+using System.Text.Json.Serialization;
+
+namespace BotSharp.OpenAPI.ViewModels.Translations;
+
+public class TranslationResponseModel
+{
+ public string Text { get; set; } = null!;
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public string FromLang { get; set; } = null!;
+}
diff --git a/src/Plugins/BotSharp.Plugin.SqlDriver/Using.cs b/src/Plugins/BotSharp.Plugin.SqlDriver/Using.cs
index 31780fb49..75d7f8ed9 100644
--- a/src/Plugins/BotSharp.Plugin.SqlDriver/Using.cs
+++ b/src/Plugins/BotSharp.Plugin.SqlDriver/Using.cs
@@ -21,4 +21,3 @@
global using BotSharp.Plugin.SqlDriver.Services;
global using BotSharp.Plugin.SqlHero.Settings;
global using System.Drawing;
-global using Console = Colorful.Console;
\ No newline at end of file
diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightInstance.cs b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightInstance.cs
index 3f7d4d3a4..69e94f139 100644
--- a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightInstance.cs
+++ b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightInstance.cs
@@ -1,3 +1,4 @@
+using Microsoft.Playwright;
using System.IO;
namespace BotSharp.Plugin.WebDriver.Drivers.PlaywrightDriver;
@@ -6,31 +7,41 @@ public class PlaywrightInstance : IDisposable
{
IPlaywright _playwright;
Dictionary _contexts = new Dictionary();
+ Dictionary> _pages = new Dictionary>();
+
+ ///
+ /// ContextId and BrowserContext
+ ///
public Dictionary Contexts => _contexts;
- public IPage GetPage(string id)
+ ///
+ /// ContextId and Pages
+ ///
+ public Dictionary> Pages => _pages;
+
+ public IPage GetPage(string id, string? pattern = null)
{
InitInstance(id).Wait();
return _contexts[id].Pages.LastOrDefault();
}
- public async Task InitInstance(string id)
+ public async Task InitInstance(string ctxId)
{
if (_playwright == null)
{
_playwright = await Playwright.CreateAsync();
}
- return await InitContext(id);
+ return await InitContext(ctxId);
}
- public async Task InitContext(string id)
+ public async Task InitContext(string ctxId)
{
- if (_contexts.ContainsKey(id))
- return _contexts[id];
+ if (_contexts.ContainsKey(ctxId))
+ return _contexts[ctxId];
- string tempFolderPath = $"{Path.GetTempPath()}\\playwright\\{id}";
+ string tempFolderPath = $"{Path.GetTempPath()}\\playwright\\{ctxId}";
- _contexts[id] = await _playwright.Chromium.LaunchPersistentContextAsync(tempFolderPath, new BrowserTypeLaunchPersistentContextOptions
+ _contexts[ctxId] = await _playwright.Chromium.LaunchPersistentContextAsync(tempFolderPath, new BrowserTypeLaunchPersistentContextOptions
{
#if DEBUG
Headless = false,
@@ -42,63 +53,110 @@ public async Task InitContext(string id)
[
"--enable-automation",
],
- Args =
+ Args =
[
"--disable-infobars",
"--test-type"
// "--start-maximized"
]
});
+ _pages[ctxId] = new List();
- _contexts[id].Page += async (sender, e) =>
+ _contexts[ctxId].Page += async (sender, page) =>
{
- e.Close += async (sender, e) =>
+ _pages[ctxId].Add(page);
+ page.Close += async (sender, e) =>
{
+ _pages[ctxId].Remove(e);
Serilog.Log.Information($"Page is closed: {e.Url}");
};
- Serilog.Log.Information($"New page is created: {e.Url}");
- await e.SetViewportSizeAsync(1280, 800);
+ Serilog.Log.Information($"New page is created: {page.Url}");
+ if (!page.IsClosed)
+ {
+ await page.SetViewportSizeAsync(1600, 900);
+ }
+
+ /*page.Response += async (sender, e) =>
+ {
+ Serilog.Log.Information($"Response: {e.Url}");
+ if (e.Headers.ContainsKey("content-type") && e.Headers["content-type"].Contains("application/json"))
+ {
+ var json = await e.JsonAsync();
+ Serilog.Log.Information(json.ToString());
+ }
+ };*/
};
- _contexts[id].Close += async (sender, e) =>
+ _contexts[ctxId].Close += async (sender, e) =>
{
Serilog.Log.Warning($"Playwright browser context is closed");
- _contexts.Remove(id);
+ _pages.Remove(ctxId);
+ _contexts.Remove(ctxId);
};
- return _contexts[id];
+ return _contexts[ctxId];
}
- public async Task NewPage(string id)
+ public async Task NewPage(string ctxId, DataFetched? fetched)
{
- await InitContext(id);
- return await _contexts[id].NewPageAsync();
+ await InitContext(ctxId);
+ var page = await _contexts[ctxId].NewPageAsync();
+
+ if (fetched != null)
+ {
+ page.Response += async (sender, e) =>
+ {
+ if (e.Headers.ContainsKey("content-type") &&
+ e.Headers["content-type"].Contains("application/json") &&
+ e.Request.ResourceType == "fetch")
+ {
+ Serilog.Log.Information($"Response: {e.Url}");
+ var json = await e.JsonAsync();
+ fetched(e.Url.ToLower(), JsonSerializer.Serialize(json));
+ }
+ };
+ }
+
+ return page;
}
- public async Task Wait(string id)
+ ///
+ /// Wait page and network until timeout in seconds
+ ///
+ ///
+ /// seconds
+ ///
+ public async Task Wait(string ctxId, int timeout = 60)
{
- if (_contexts.ContainsKey(id))
+ foreach (var page in _pages[ctxId])
{
- var page = _contexts[id].Pages.Last();
await page.WaitForLoadStateAsync(LoadState.DOMContentLoaded);
- await page.WaitForLoadStateAsync(LoadState.NetworkIdle);
+ await page.WaitForLoadStateAsync(LoadState.NetworkIdle, new PageWaitForLoadStateOptions
+ {
+ Timeout = 1000 * timeout
+ });
}
await Task.Delay(100);
}
- public async Task Close(string id)
+ public async Task Close(string ctxId)
{
- if (_contexts.ContainsKey(id))
+ if (_contexts.ContainsKey(ctxId))
{
- await _contexts[id].CloseAsync();
+ await _contexts[ctxId].CloseAsync();
}
}
- public async Task CloseCurrentPage(string id)
+ public async Task CloseCurrentPage(string ctxId)
{
- if (_contexts.ContainsKey(id))
+ var pages = _pages[ctxId].ToArray();
+ for (var i = 0; i < pages.Length; i++)
{
- await GetPage(id).CloseAsync();
+ var page = _pages[ctxId].FirstOrDefault();
+ if (page != null)
+ {
+ await page.CloseAsync();
+ }
}
}
diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.GoToPage.cs b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.GoToPage.cs
index 4e505997d..4fb916600 100644
--- a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.GoToPage.cs
+++ b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.GoToPage.cs
@@ -1,3 +1,5 @@
+using System.Linq;
+
namespace BotSharp.Plugin.WebDriver.Drivers.PlaywrightDriver;
public partial class PlaywrightWebDriver
@@ -9,7 +11,7 @@ public async Task GoToPage(MessageInfo message, PageActionA
try
{
// Check if the page is already open
- if (!args.OpenNewTab && context.Pages.Count > 0)
+ /*if (!args.OpenNewTab && context.Pages.Count > 0)
{
foreach (var p in context.Pages)
{
@@ -18,14 +20,15 @@ public async Task GoToPage(MessageInfo message, PageActionA
// Disable this due to performance issue, some page is too large
// result.Body = await p.ContentAsync();
result.IsSuccess = true;
- await p.BringToFrontAsync();
+ // await p.BringToFrontAsync();
return result;
}
}
- }
+ }*/
- var page = args.OpenNewTab ? await _instance.NewPage(message.ContextId) :
+ var page = args.OpenNewTab ? await _instance.NewPage(message.ContextId, fetched: args.OnDataFetched) :
_instance.GetPage(message.ContextId);
+
var response = await page.GotoAsync(args.Url);
await page.WaitForLoadStateAsync(LoadState.DOMContentLoaded);
await page.WaitForLoadStateAsync(LoadState.NetworkIdle);
@@ -50,4 +53,14 @@ public async Task GoToPage(MessageInfo message, PageActionA
return result;
}
+
+ private void Page_Response1(object sender, IResponse e)
+ {
+ throw new NotImplementedException();
+ }
+
+ private void Page_Response(object sender, IResponse e)
+ {
+ throw new NotImplementedException();
+ }
}
diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.LocateElement.cs b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.LocateElement.cs
index c5f7d48cc..4bbd84aca 100644
--- a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.LocateElement.cs
+++ b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.LocateElement.cs
@@ -1,4 +1,4 @@
-using System.Xml.Linq;
+using System.Web;
namespace BotSharp.Plugin.WebDriver.Drivers.PlaywrightDriver;
@@ -88,7 +88,8 @@ public async Task LocateElement(MessageInfo message, Elemen
}*/
var html = await locator.InnerHTMLAsync();
- result.Body = html;
+ // fix if html has &
+ result.Body = HttpUtility.HtmlDecode(html);
result.IsSuccess = true;
}
else if (count > 1)
@@ -129,7 +130,7 @@ public async Task LocateElement(MessageInfo message, Elemen
await page.EvaluateAsync($@"
(element) => {{
- element.style.outline = '2px solid red';
+ element.style.outline = '2px solid {location.HighlightColor}';
}}", handle);
result.IsHighlighted = true;