CloseCurrentPage

This commit is contained in:
Haiping Chen 2024-06-10 10:51:14 -05:00
parent ae4b3f4237
commit bad93b971b
17 changed files with 161 additions and 100 deletions

View file

@ -5,4 +5,6 @@ public enum BroswerActionEnum
Click = 1,
InputText = 2,
Typing = 3,
Hover = 4,
Scroll = 5,
}

View file

@ -4,9 +4,9 @@ namespace BotSharp.Abstraction.Browsing;
public interface IWebBrowser
{
Task<BrowserActionResult> LaunchBrowser(MessageInfo message, string? url);
Task<BrowserActionResult> LaunchBrowser(MessageInfo message);
Task<BrowserActionResult> ScreenshotAsync(MessageInfo message, string path);
Task<BrowserActionResult> ScrollPageAsync(BrowserActionParams actionParams);
Task<BrowserActionResult> ScrollPage(MessageInfo message, PageActionArgs args);
Task<BrowserActionResult> ActionOnElement(MessageInfo message, ElementLocatingArgs location, ElementActionArgs action);
Task<BrowserActionResult> LocateElement(MessageInfo message, ElementLocatingArgs location);
@ -19,11 +19,11 @@ public interface IWebBrowser
Task<BrowserActionResult> ChangeListValue(BrowserActionParams actionParams);
Task<BrowserActionResult> CheckRadioButton(BrowserActionParams actionParams);
Task<BrowserActionResult> ChangeCheckbox(BrowserActionParams actionParams);
Task<BrowserActionResult> GoToPage(MessageInfo message, string url, bool openNewTab = false);
Task<BrowserActionResult> GoToPage(MessageInfo message, PageActionArgs args);
Task<string> ExtractData(BrowserActionParams actionParams);
Task<T> EvaluateScript<T>(string contextId, string script);
Task CloseBrowser(string contextId);
Task CloseCurrentPage(string contextId);
Task<BrowserActionResult> CloseCurrentPage(MessageInfo message);
Task<BrowserActionResult> SendHttpRequest(MessageInfo message, HttpRequestParams actionParams);
Task<BrowserActionResult> GetAttributeValue(MessageInfo message, ElementLocatingArgs location);
}

View file

@ -0,0 +1,14 @@
using BotSharp.Abstraction.Browsing.Enums;
namespace BotSharp.Abstraction.Browsing.Models;
public class PageActionArgs
{
public BroswerActionEnum Action { get; set; }
public string? Content { get; set; }
public string? Direction { get; set; }
public string Url { get; set; } = null!;
public bool OpenNewTab { get; set; } = false;
}

View file

@ -3,7 +3,7 @@
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<Nullable>enable</Nullable>
<LangVersion>$(LangVersion)</LangVersion>
<LangVersion>12.0</LangVersion>
<VersionPrefix>$(BotSharpVersion)</VersionPrefix>
<GeneratePackageOnBuild>$(GeneratePackageOnBuild)</GeneratePackageOnBuild>
<GenerateDocumentationFile>$(GenerateDocumentationFile)</GenerateDocumentationFile>
@ -19,6 +19,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.Playwright" Version="1.44.0" />
<PackageReference Include="Selenium.WebDriver" Version="4.21.0" />
<PackageReference Include="HtmlAgilityPack" Version="1.11.61" />
</ItemGroup>
<ItemGroup>

View file

@ -38,16 +38,16 @@ public class PlaywrightInstance : IDisposable
Headless = true,
#endif
Channel = "chrome",
IgnoreDefaultArgs = new[]
{
IgnoreDefaultArgs =
[
"--enable-automation",
},
Args = new[]
{
],
Args =
[
"--disable-infobars",
"--no-sandbox",
"--test-type"
// "--start-maximized"
}
]
});
_contexts[id].Page += async (sender, e) =>

View file

@ -2,8 +2,14 @@ namespace BotSharp.Plugin.WebDriver.Drivers.PlaywrightDriver;
public partial class PlaywrightWebDriver
{
public async Task CloseCurrentPage(string contextId)
public async Task<BrowserActionResult> CloseCurrentPage(MessageInfo message)
{
await _instance.CloseCurrentPage(contextId);
await _instance.CloseCurrentPage(message.ContextId);
var result = new BrowserActionResult
{
IsSuccess = true
};
return result;
}
}

View file

@ -42,5 +42,9 @@ public partial class PlaywrightWebDriver
await locator.PressAsync(action.PressKey);
}
}
else if (action.Action == BroswerActionEnum.Hover)
{
await locator.HoverAsync();
}
}
}

View file

@ -2,20 +2,21 @@ namespace BotSharp.Plugin.WebDriver.Drivers.PlaywrightDriver;
public partial class PlaywrightWebDriver
{
public async Task<BrowserActionResult> GoToPage(MessageInfo message, string url, bool openNewTab = false)
public async Task<BrowserActionResult> GoToPage(MessageInfo message, PageActionArgs args)
{
var result = new BrowserActionResult();
var context = await _instance.InitInstance(message.ContextId);
try
{
// Check if the page is already open
if (!openNewTab && context.Pages.Count > 0)
if (!args.OpenNewTab && context.Pages.Count > 0)
{
foreach (var p in context.Pages)
{
if (p.Url == url)
if (p.Url == args.Url)
{
result.Body = await p.ContentAsync();
// Disable this due to performance issue, some page is too large
// result.Body = await p.ContentAsync();
result.IsSuccess = true;
await p.BringToFrontAsync();
return result;
@ -23,14 +24,11 @@ public partial class PlaywrightWebDriver
}
}
var page = openNewTab ? await _instance.NewPage(message.ContextId) :
var page = args.OpenNewTab ? await _instance.NewPage(message.ContextId) :
_instance.GetPage(message.ContextId);
var response = await page.GotoAsync(url);
var response = await page.GotoAsync(args.Url);
await page.WaitForLoadStateAsync(LoadState.DOMContentLoaded);
await page.WaitForLoadStateAsync(LoadState.NetworkIdle, new PageWaitForLoadStateOptions
{
Timeout = 1000 * 60 * 5
});
await page.WaitForLoadStateAsync(LoadState.NetworkIdle);
if (response.Status == 200)
{

View file

@ -2,44 +2,13 @@ namespace BotSharp.Plugin.WebDriver.Drivers.PlaywrightDriver;
public partial class PlaywrightWebDriver
{
public async Task<BrowserActionResult> LaunchBrowser(MessageInfo message, string? url)
public async Task<BrowserActionResult> LaunchBrowser(MessageInfo message)
{
var result = new BrowserActionResult()
{
IsSuccess = true
};
var context = await _instance.InitInstance(message.ContextId);
if (!string.IsNullOrEmpty(url))
var result = new BrowserActionResult
{
// Check if the page is already open
foreach (var p in context.Pages)
{
if (p.Url == url)
{
await p.BringToFrontAsync();
return result;
}
}
var page = await _instance.NewPage(message.ContextId);
try
{
var response = await page.GotoAsync(url, new PageGotoOptions
{
Timeout = 15 * 1000
});
await page.WaitForLoadStateAsync(LoadState.DOMContentLoaded);
result.IsSuccess = response.Status == 200;
}
catch (Exception ex)
{
result.Message = ex.Message;
result.StackTrace = ex.StackTrace;
_logger.LogError(ex.Message);
}
}
IsSuccess = context.Pages.Count > 0
};
return result;
}

View file

@ -2,21 +2,43 @@ namespace BotSharp.Plugin.WebDriver.Drivers.PlaywrightDriver;
public partial class PlaywrightWebDriver
{
public async Task<BrowserActionResult> ScrollPageAsync(BrowserActionParams actionParams)
public async Task<BrowserActionResult> ScrollPage(MessageInfo message, PageActionArgs args)
{
var result = new BrowserActionResult();
await _instance.Wait(actionParams.ContextId);
await _instance.Wait(message.ContextId);
var page = _instance.GetPage(actionParams.ContextId);
var page = _instance.GetPage(message.ContextId);
if(actionParams.Context.Direction == "down")
await page.EvaluateAsync("window.scrollBy(0, window.innerHeight - 200)");
else if (actionParams.Context.Direction == "up")
await page.EvaluateAsync("window.scrollBy(0, -window.innerHeight + 200)");
else if (actionParams.Context.Direction == "left")
await page.EvaluateAsync("window.scrollBy(-400, 0)");
else if (actionParams.Context.Direction == "right")
await page.EvaluateAsync("window.scrollBy(400, 0)");
if (args.Direction == "down")
{
// Get the total page height
int scrollY = await page.EvaluateAsync<int>("document.body.scrollHeight");
// Scroll to the bottom
await page.Mouse.WheelAsync(0, scrollY);
}
else if (args.Direction == "up")
{
// Get the total page height
int scrollY = await page.EvaluateAsync<int>("document.body.scrollHeight");
// Scroll to the bottom
await page.Mouse.WheelAsync(0, -scrollY);
}
else if (args.Direction == "left")
{
await page.EvaluateAsync(@"
var scrollingElement = (document.scrollingElement || document.body);
scrollingElement.scrollLeft = 0;
");
}
else if (args.Direction == "right")
{
await page.EvaluateAsync(@"
var scrollingElement = (document.scrollingElement || document.body);
scrollingElement.scrollLeft = scrollingElement.scrollWidth;
");
}
result.IsSuccess = true;
return result;

View file

@ -2,14 +2,14 @@ namespace BotSharp.Plugin.WebDriver.Drivers.SeleniumDriver;
public partial class SeleniumWebDriver
{
public async Task<BrowserActionResult> GoToPage(MessageInfo message, string url, bool openNewTab = false)
public async Task<BrowserActionResult> GoToPage(MessageInfo message, PageActionArgs args)
{
var result = new BrowserActionResult();
try
{
var page = openNewTab ? await _instance.NewPage(message.ContextId) :
var page = args.OpenNewTab ? await _instance.NewPage(message.ContextId) :
_instance.GetPage(message.ContextId);
page.GoToUrl(url);
page.GoToUrl(args.Url);
await _instance.Wait(message.ContextId);
result.Body = _instance.GetPageContent(message.ContextId);

View file

@ -2,32 +2,13 @@ namespace BotSharp.Plugin.WebDriver.Drivers.SeleniumDriver;
public partial class SeleniumWebDriver
{
public async Task<BrowserActionResult> LaunchBrowser(MessageInfo message, string? url)
public async Task<BrowserActionResult> LaunchBrowser(MessageInfo message)
{
var context = await _instance.InitInstance(message.ContextId);
var result = new BrowserActionResult()
{
IsSuccess = true
};
var context = await _instance.InitInstance(message.ContextId);
if (!string.IsNullOrEmpty(url))
{
// Check if the page is already open
var page = await _instance.NewPage(message.ContextId);
try
{
page.GoToUrl(url);
result.IsSuccess = true;
}
catch (Exception ex)
{
result.Message = ex.Message;
result.StackTrace = ex.StackTrace;
_logger.LogError(ex.Message);
}
}
return result;
}
}

View file

@ -52,7 +52,7 @@ public partial class SeleniumWebDriver : IWebBrowser
throw new NotImplementedException();
}
public Task CloseCurrentPage(string contextId)
public Task<BrowserActionResult> CloseCurrentPage(MessageInfo message)
{
throw new NotImplementedException();
}
@ -77,7 +77,7 @@ public partial class SeleniumWebDriver : IWebBrowser
throw new NotImplementedException();
}
public Task<BrowserActionResult> ScrollPageAsync(BrowserActionParams actionParams)
public Task<BrowserActionResult> ScrollPage(MessageInfo message, PageActionArgs args)
{
throw new NotImplementedException();
}

View file

@ -31,7 +31,10 @@ public class GoToPageFn : IFunctionCallback
AgentId = message.CurrentAgentId,
ContextId = convService.ConversationId,
MessageId = message.MessageId
}, url);
}, new PageActionArgs
{
Url = url
});
message.Content = result.IsSuccess ? $"Page {url} is open." : $"Page {url} open failed. {result.Message}";
var path = webDriverService.GetScreenshotFilePath(message.MessageId);

View file

@ -1,3 +1,5 @@
using SQLitePCL;
namespace BotSharp.Plugin.WebDriver.Functions;
public class OpenBrowserFn : IFunctionCallback
@ -23,12 +25,17 @@ public class OpenBrowserFn : IFunctionCallback
var url = webDriverService.ReplaceToken(args.Url);
url = url.Replace("https://https://", "https://");
var result = await _browser.LaunchBrowser(new MessageInfo
var msgInfo = new MessageInfo
{
AgentId = message.CurrentAgentId,
ContextId = convService.ConversationId,
MessageId = message.MessageId
}, url);
};
var result = await _browser.LaunchBrowser(msgInfo);
result = await _browser.GoToPage(msgInfo, new PageActionArgs
{
Url = url
});
if (result.IsSuccess)
{

View file

@ -22,7 +22,17 @@ public class ScrollPageFn : IFunctionCallback
var agentService = _services.GetRequiredService<IAgentService>();
var agent = await agentService.LoadAgent(message.CurrentAgentId);
message.Data = await _browser.ScrollPageAsync(new BrowserActionParams(agent, args, convService.ConversationId, message.MessageId));
message.Data = await _browser.ScrollPage(new MessageInfo
{
AgentId = agent.Id,
ContextId = convService.ConversationId,
MessageId = message.MessageId
}, new PageActionArgs
{
Action = BroswerActionEnum.Scroll,
Direction = args.Direction,
});
message.Content = "Scrolled. You can scroll more if needed.";
var webDriverService = _services.GetRequiredService<WebDriverService>();

View file

@ -0,0 +1,44 @@
using HtmlAgilityPack;
using System.Net.Http;
namespace BotSharp.Plugin.WebDriver;
public static class WebPageHelper
{
public static string RemoveElements(string html, string selector)
{
var htmlDoc = new HtmlDocument();
htmlDoc.LoadHtml(html);
var nodesToRemove = htmlDoc.DocumentNode.SelectNodes(selector);
if (nodesToRemove != null)
{
foreach (var node in nodesToRemove)
{
node.Remove();
}
}
return htmlDoc.DocumentNode.OuterHtml;
}
public static string RemoveAttribute(string html, string attrName)
{
var htmlDoc = new HtmlDocument();
htmlDoc.LoadHtml(html);
// Select all elements with a style attribute
var nodesWithStyle = htmlDoc.DocumentNode.SelectNodes($"//*[@{attrName}]");
if (nodesWithStyle != null)
{
foreach (var node in nodesWithStyle)
{
node.Attributes.Remove(attrName);
}
}
return htmlDoc.DocumentNode.OuterHtml;
}
}