Skip to content

Commit

Permalink
Merge pull request #411 from Qtoss-Alpha/master
Browse files Browse the repository at this point in the history
Optimize WebDriver with context id.
  • Loading branch information
Oceania2018 authored Apr 12, 2024
2 parents 887619d + db709b2 commit 1992a70
Show file tree
Hide file tree
Showing 27 changed files with 111 additions and 85 deletions.
13 changes: 7 additions & 6 deletions src/Infrastructure/BotSharp.Abstraction/Browsing/IWebBrowser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ namespace BotSharp.Abstraction.Browsing;

public interface IWebBrowser
{
Task<BrowserActionResult> LaunchBrowser(string conversationId, string? url);
Task<BrowserActionResult> ScreenshotAsync(string conversationId, string path);
Task<BrowserActionResult> LaunchBrowser(string contextId, string? url, bool openIfNotExist = true);
Task<BrowserActionResult> ScreenshotAsync(string contextId, string path);
Task<BrowserActionResult> ScrollPageAsync(BrowserActionParams actionParams);

Task<BrowserActionResult> ActionOnElement(MessageInfo message, ElementLocatingArgs location, ElementActionArgs action);
Expand All @@ -19,10 +19,11 @@ public interface IWebBrowser
Task<BrowserActionResult> ChangeListValue(BrowserActionParams actionParams);
Task<BrowserActionResult> CheckRadioButton(BrowserActionParams actionParams);
Task<BrowserActionResult> ChangeCheckbox(BrowserActionParams actionParams);
Task<BrowserActionResult> GoToPage(string conversationId, string url);
Task<BrowserActionResult> GoToPage(string contextId, string url, bool openNewTab = false);
Task<string> ExtractData(BrowserActionParams actionParams);
Task<T> EvaluateScript<T>(string conversationId, string script);
Task CloseBrowser(string conversationId);
Task<BrowserActionResult> SendHttpRequest(HttpRequestParams actionParams);
Task<T> EvaluateScript<T>(string contextId, string script);
Task CloseBrowser(string contextId);
Task CloseCurrentPage(string contextId);
Task<BrowserActionResult> SendHttpRequest(string contextId, HttpRequestParams actionParams);
Task<string> GetAttributeValue(MessageInfo message, ElementLocatingArgs location, BrowserActionResult result);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ public class BrowserActionParams
{
public Agent Agent { get; set; }
public BrowsingContextIn Context { get; set; }
public string ConversationId { get; set; }
public string ContextId { get; set; }
public string MessageId { get; set; }

public BrowserActionParams(Agent agent, BrowsingContextIn context, string conversationId, string messageId)
public BrowserActionParams(Agent agent, BrowsingContextIn context, string contextId, string messageId)
{
Agent = agent;
Context = context;
ConversationId = conversationId;
ContextId = contextId;
MessageId = messageId;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ namespace BotSharp.Abstraction.Browsing.Models;
public class MessageInfo
{
public string AgentId { get; set; }
public string ConversationId { get; set; }
public string ContextId { get; set; }
public string MessageId { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,30 @@ public class PlaywrightInstance : IDisposable
{
IPlaywright _playwright;
Dictionary<string, IBrowserContext> _contexts = new Dictionary<string, IBrowserContext>();
public Dictionary<string, IBrowserContext> Contexts => _contexts;

public IPage GetPage(string id)
{
InitInstance(id).Wait();
return _contexts[id].Pages.LastOrDefault();
}

public async Task InitInstance(string id)
public async Task<IBrowserContext> InitInstance(string id)
{
if (_playwright == null)
{
_playwright = await Playwright.CreateAsync();
}
await InitContext(id);
return await InitContext(id);
}

public async Task InitContext(string id)
public async Task<IBrowserContext> InitContext(string id)
{
if (_contexts.ContainsKey(id))
return;
#if DEBUG
string tempFolderPath = $"{Path.GetTempPath()}\\playwright";
#else
return _contexts[id];

string tempFolderPath = $"{Path.GetTempPath()}\\playwright\\{id}";
#endif

_contexts[id] = await _playwright.Chromium.LaunchPersistentContextAsync(tempFolderPath, new BrowserTypeLaunchPersistentContextOptions
{
#if DEBUG
Expand Down Expand Up @@ -65,6 +64,8 @@ public async Task InitContext(string id)
Serilog.Log.Warning($"Playwright browser context is closed");
_contexts.Remove(id);
};

return _contexts[id];
}

public async Task<IPage> NewPage(string id)
Expand Down Expand Up @@ -92,6 +93,14 @@ public async Task Close(string id)
}
}

public async Task CloseCurrentPage(string id)
{
if (_contexts.ContainsKey(id))
{
await GetPage(id).CloseAsync();
}
}

public void Dispose()
{
_contexts.Clear();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ public partial class PlaywrightWebDriver
{
public async Task<BrowserActionResult> ActionOnElement(MessageInfo message, ElementLocatingArgs location, ElementActionArgs action)
{
await _instance.Wait(message.ConversationId);
await _instance.Wait(message.ContextId);
var result = await LocateElement(message, location);
if (result.IsSuccess)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
using System.Text.RegularExpressions;

namespace BotSharp.Plugin.WebDriver.Drivers.PlaywrightDriver;

public partial class PlaywrightWebDriver
Expand All @@ -8,7 +6,7 @@ public async Task<BrowserActionResult> ChangeCheckbox(BrowserActionParams action
{
var result = new BrowserActionResult();

await _instance.Wait(actionParams.ConversationId);
await _instance.Wait(actionParams.ContextId);

// Retrieve the page raw html and infer the element path
var regexExpression = actionParams.Context.MatchRule.ToLower() switch
Expand All @@ -19,7 +17,7 @@ public async Task<BrowserActionResult> ChangeCheckbox(BrowserActionParams action
_ => $"^{actionParams.Context.ElementText}$"
};
var regex = new Regex(regexExpression, RegexOptions.IgnoreCase);
var elements = _instance.GetPage(actionParams.ConversationId).GetByText(regex);
var elements = _instance.GetPage(actionParams.ContextId).GetByText(regex);
var count = await elements.CountAsync();

var errorMessage = $"Can't locate element by keyword {actionParams.Context.ElementText}";
Expand Down Expand Up @@ -55,7 +53,7 @@ public async Task<BrowserActionResult> ChangeCheckbox(BrowserActionParams action
}
else
{
elements = _instance.GetPage(actionParams.ConversationId).Locator($"#{id}");
elements = _instance.GetPage(actionParams.ContextId).Locator($"#{id}");
}
count = await elements.CountAsync();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ public partial class PlaywrightWebDriver
public async Task<BrowserActionResult> ChangeListValue(BrowserActionParams actionParams)
{
var result = new BrowserActionResult();
await _instance.Wait(actionParams.ConversationId);
await _instance.Wait(actionParams.ContextId);

// Retrieve the page raw html and infer the element path
var body = await _instance.GetPage(actionParams.ConversationId).QuerySelectorAsync("body");
var body = await _instance.GetPage(actionParams.ContextId).QuerySelectorAsync("body");

var str = new List<string>();
var inputs = await body.QuerySelectorAllAsync("select");
Expand Down Expand Up @@ -61,7 +61,7 @@ public async Task<BrowserActionResult> ChangeListValue(BrowserActionParams actio
string.Join("", str),
actionParams.Context.ElementName,
actionParams.MessageId);
ILocator element = Locator(actionParams.ConversationId, htmlElementContextOut);
ILocator? element = Locator(actionParams.ContextId, htmlElementContextOut);

try
{
Expand All @@ -70,11 +70,11 @@ public async Task<BrowserActionResult> ChangeListValue(BrowserActionParams actio
if (!isVisible)
{
// Select the element you want to make visible (replace with your own selector)
var control = await _instance.GetPage(actionParams.ConversationId)
var control = await _instance.GetPage(actionParams.ContextId)
.QuerySelectorAsync($"#{htmlElementContextOut.ElementId}");

// Show the element by modifying its CSS styles
await _instance.GetPage(actionParams.ConversationId)
await _instance.GetPage(actionParams.ContextId)
.EvaluateAsync(@"(element) => {
element.style.display = 'block';
element.style.visibility = 'visible';
Expand All @@ -92,11 +92,11 @@ await element.SelectOptionAsync(new SelectOptionValue
if (!isVisible)
{
// Select the element you want to make visible (replace with your own selector)
var control = await _instance.GetPage(actionParams.ConversationId)
var control = await _instance.GetPage(actionParams.ContextId)
.QuerySelectorAsync($"#{htmlElementContextOut.ElementId}");

// Show the element by modifying its CSS styles
await _instance.GetPage(actionParams.ConversationId).EvaluateAsync(@"(element) => {
await _instance.GetPage(actionParams.ContextId).EvaluateAsync(@"(element) => {
element.style.display = 'none';
element.style.visibility = 'hidden';
}", control);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ public partial class PlaywrightWebDriver
public async Task<BrowserActionResult> CheckRadioButton(BrowserActionParams actionParams)
{
var result = new BrowserActionResult();
await _instance.Wait(actionParams.ConversationId);
await _instance.Wait(actionParams.ContextId);

// Retrieve the page raw html and infer the element path
var regexExpression = actionParams.Context.MatchRule.ToLower() switch
Expand All @@ -16,7 +16,7 @@ public async Task<BrowserActionResult> CheckRadioButton(BrowserActionParams acti
_ => $"^{actionParams.Context.ElementText}$"
};
var regex = new Regex(regexExpression, RegexOptions.IgnoreCase);
var elements = _instance.GetPage(actionParams.ConversationId).GetByText(regex);
var elements = _instance.GetPage(actionParams.ContextId).GetByText(regex);
var count = await elements.CountAsync();

var errorMessage = $"Can't locate element by keyword {actionParams.Context.ElementText}";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ public partial class PlaywrightWebDriver
public async Task<BrowserActionResult> ClickButton(BrowserActionParams actionParams)
{
var result = new BrowserActionResult();
await _instance.Wait(actionParams.ConversationId);
await _instance.Wait(actionParams.ContextId);

// Find by text exactly match
var elements = _instance.GetPage(actionParams.ConversationId)
var elements = _instance.GetPage(actionParams.ContextId)
.GetByRole(AriaRole.Button, new PageGetByRoleOptions
{
Name = actionParams.Context.ElementName
Expand All @@ -17,7 +17,7 @@ public async Task<BrowserActionResult> ClickButton(BrowserActionParams actionPar

if (count == 0)
{
elements = _instance.GetPage(actionParams.ConversationId)
elements = _instance.GetPage(actionParams.ContextId)
.GetByRole(AriaRole.Link, new PageGetByRoleOptions
{
Name = actionParams.Context.ElementName
Expand All @@ -27,7 +27,7 @@ public async Task<BrowserActionResult> ClickButton(BrowserActionParams actionPar

if (count == 0)
{
elements = _instance.GetPage(actionParams.ConversationId)
elements = _instance.GetPage(actionParams.ContextId)
.GetByText(actionParams.Context.ElementName);
count = await elements.CountAsync();
}
Expand All @@ -36,12 +36,12 @@ public async Task<BrowserActionResult> ClickButton(BrowserActionParams actionPar
{
// Infer element if not found
var driverService = _services.GetRequiredService<WebDriverService>();
var html = await FilteredButtonHtml(actionParams.ConversationId);
var html = await FilteredButtonHtml(actionParams.ContextId);
var htmlElementContextOut = await driverService.InferElement(actionParams.Agent,
html,
actionParams.Context.ElementName,
actionParams.MessageId);
elements = Locator(actionParams.ConversationId, htmlElementContextOut);
elements = Locator(actionParams.ContextId, htmlElementContextOut);

if (elements == null)
{
Expand All @@ -54,7 +54,7 @@ public async Task<BrowserActionResult> ClickButton(BrowserActionParams actionPar
try
{
await elements.ClickAsync();
await _instance.Wait(actionParams.ConversationId);
await _instance.Wait(actionParams.ContextId);

result.IsSuccess = true;
}
Expand All @@ -67,12 +67,12 @@ public async Task<BrowserActionResult> ClickButton(BrowserActionParams actionPar
return result;
}

private async Task<string> FilteredButtonHtml(string conversationId)
private async Task<string> FilteredButtonHtml(string contextId)
{
var driverService = _services.GetRequiredService<WebDriverService>();

// Retrieve the page raw html and infer the element path
var body = await _instance.GetPage(conversationId).QuerySelectorAsync("body");
var body = await _instance.GetPage(contextId).QuerySelectorAsync("body");

var str = new List<string>();
/*var anchors = await body.QuerySelectorAllAsync("a");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ public partial class PlaywrightWebDriver
public async Task<BrowserActionResult> ClickElement(BrowserActionParams actionParams)
{
var result = new BrowserActionResult();
await _instance.Wait(actionParams.ConversationId);
await _instance.Wait(actionParams.ContextId);

var page = _instance.GetPage(actionParams.ConversationId);
var page = _instance.GetPage(actionParams.ContextId);
ILocator locator = default;
int count = 0;

Expand Down Expand Up @@ -51,7 +51,7 @@ public async Task<BrowserActionResult> ClickElement(BrowserActionParams actionPa
await locator.ClickAsync();

// Triggered ajax
await _instance.Wait(actionParams.ConversationId);
await _instance.Wait(actionParams.ContextId);

result.IsSuccess = true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ namespace BotSharp.Plugin.WebDriver.Drivers.PlaywrightDriver;

public partial class PlaywrightWebDriver
{
public async Task CloseBrowser(string conversationId)
public async Task CloseBrowser(string contextId)
{
await _instance.Close(conversationId);
await _instance.Close(contextId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace BotSharp.Plugin.WebDriver.Drivers.PlaywrightDriver;

public partial class PlaywrightWebDriver
{
public async Task CloseCurrentPage(string contextId)
{
await _instance.CloseCurrentPage(contextId);
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
using BotSharp.Abstraction.Browsing.Enums;

namespace BotSharp.Plugin.WebDriver.Drivers.PlaywrightDriver;

public partial class PlaywrightWebDriver
{
public async Task DoAction(MessageInfo message, ElementActionArgs action, BrowserActionResult result)
{
var page = _instance.GetPage(message.ConversationId);
var page = _instance.GetPage(message.ContextId);
ILocator locator = page.Locator(result.Selector);

if (action.Action == BroswerActionEnum.Click)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ namespace BotSharp.Plugin.WebDriver.Drivers.PlaywrightDriver;

public partial class PlaywrightWebDriver
{
public async Task<T> EvaluateScript<T>(string conversationId, string script)
public async Task<T> EvaluateScript<T>(string contextId, string script)
{
await _instance.Wait(conversationId);
await _instance.Wait(contextId);

return await _instance.GetPage(conversationId).EvaluateAsync<T>(script);
return await _instance.GetPage(contextId).EvaluateAsync<T>(script);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ public partial class PlaywrightWebDriver
{
public async Task<string> ExtractData(BrowserActionParams actionParams)
{
await _instance.Wait(actionParams.ConversationId);
await _instance.Wait(actionParams.ContextId);

await Task.Delay(3000);

// Retrieve the page raw html and infer the element path
var body = await _instance.GetPage(actionParams.ConversationId).QuerySelectorAsync("body");
var body = await _instance.GetPage(actionParams.ContextId).QuerySelectorAsync("body");
var content = await body.InnerTextAsync();

var driverService = _services.GetRequiredService<WebDriverService>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ public partial class PlaywrightWebDriver
{
public async Task<string> GetAttributeValue(MessageInfo message, ElementLocatingArgs location, BrowserActionResult result)
{
var page = _instance.GetPage(message.ConversationId);
var page = _instance.GetPage(message.ContextId);
ILocator locator = page.Locator(result.Selector);
var value = string.Empty;

Expand Down
Loading

0 comments on commit 1992a70

Please sign in to comment.