Skip to content

Commit 9c620b1

Browse files
authored
Merge pull request #512 from Qtoss-AI/master
WebDriver improvements.
2 parents c544ddd + 773b7a9 commit 9c620b1

File tree

17 files changed

+193
-43
lines changed

17 files changed

+193
-43
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace BotSharp.Abstraction.Agents.Enums;
2+
3+
public class BuiltInAgentId
4+
{
5+
public const string AIAssistant = "01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a";
6+
public const string Chatbot = "01e2fc5c-2c89-4ec7-8470-7688608b496c";
7+
public const string HumanSupport = "01dcc3e5-0af7-49e6-ad7a-a760bd12dc4b";
8+
}

src/Infrastructure/BotSharp.Abstraction/BotSharp.Abstraction.csproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@
1010
<OutputPath>$(SolutionDir)packages</OutputPath>
1111
</PropertyGroup>
1212

13+
<ItemGroup>
14+
<Compile Remove="packages\**" />
15+
<EmbeddedResource Remove="packages\**" />
16+
<None Remove="packages\**" />
17+
</ItemGroup>
18+
1319
<ItemGroup>
1420
<None Include="..\..\..\arts\Icon.png">
1521
<Pack>True</Pack>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
namespace BotSharp.Abstraction.Browsing.Models;
2+
3+
public class BrowserActionArgs
4+
{
5+
6+
}

src/Infrastructure/BotSharp.Abstraction/Browsing/Models/BrowserActionResult.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ public class BrowserActionResult
88
public string Selector { get; set; }
99
public string Body { get; set; }
1010
public bool IsHighlighted { get; set; }
11+
public DateTime? ExecutedAt { get; set; } = DateTime.UtcNow;
1112

1213
public override string ToString()
1314
{

src/Infrastructure/BotSharp.Abstraction/Browsing/Models/ElementLocatingArgs.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,5 @@ public class ElementLocatingArgs
3131
/// Draw outline around the element
3232
/// </summary>
3333
public bool Highlight { get; set; }
34+
public string HighlightColor { get; set; } = "red";
3435
}

src/Infrastructure/BotSharp.Abstraction/Browsing/Models/PageActionArgs.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,11 @@ public class PageActionArgs
1111

1212
public string Url { get; set; } = null!;
1313
public bool OpenNewTab { get; set; } = false;
14+
15+
/// <summary>
16+
/// On page data fetched
17+
/// </summary>
18+
public DataFetched? OnDataFetched { get; set; }
1419
}
20+
21+
public delegate void DataFetched(string url, string data);

src/Infrastructure/BotSharp.Abstraction/Utilities/Pagination.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ public int Offset
3737
{
3838
get { return (Page - 1) * Size; }
3939
}
40+
41+
public bool ReturnTotal { get; set; } = true;
4042
}
4143

4244
public class PagedItems<T>

src/Infrastructure/BotSharp.Core/Agents/AgentPlugin.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ public class AgentPlugin : IBotSharpPlugin
1717

1818
public string[] AgentIds => new string[]
1919
{
20-
"01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a",
21-
"01e2fc5c-2c89-4ec7-8470-7688608b496c",
22-
"01dcc3e5-0af7-49e6-ad7a-a760bd12dc4b"
20+
BuiltInAgentId.AIAssistant,
21+
BuiltInAgentId.Chatbot,
22+
BuiltInAgentId.HumanSupport
2323
};
2424

2525
public object GetNewSettingsInstance() =>

src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,7 @@
176176

177177
<ItemGroup>
178178
<PackageReference Include="Aspects.Cache" Version="2.0.4" />
179-
<PackageReference Include="Colorful.Console" Version="1.2.15" />
180-
<PackageReference Include="EntityFrameworkCore.BootKit" Version="8.3.1" />
179+
<PackageReference Include="EntityFrameworkCore.BootKit" Version="8.4.2" />
181180
<PackageReference Include="Fluid.Core" Version="2.8.0" />
182181
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.2.0" />
183182
<PackageReference Include="Nanoid" Version="3.0.0" />

src/Infrastructure/BotSharp.Core/Using.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,3 @@
3636
global using BotSharp.Core.Infrastructures;
3737
global using BotSharp.Core.Users.Services;
3838
global using Aspects.Cache;
39-
global using Console = Colorful.Console;
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
using BotSharp.Abstraction.Agents.Models;
2+
using BotSharp.Abstraction.Translation;
3+
using BotSharp.OpenAPI.ViewModels.Translations;
4+
5+
namespace BotSharp.OpenAPI.Controllers;
6+
7+
[Authorize]
8+
[ApiController]
9+
public class TranslationController : ControllerBase
10+
{
11+
private readonly IServiceProvider _services;
12+
13+
public TranslationController(IServiceProvider services)
14+
{
15+
_services = services;
16+
}
17+
18+
[HttpPost("/translate")]
19+
public async Task<TranslationResponseModel> Translate([FromBody] TranslationRequestModel model)
20+
{
21+
var agentService = _services.GetRequiredService<IAgentService>();
22+
var agent = await agentService.LoadAgent(BuiltInAgentId.AIAssistant);
23+
var translator = _services.GetRequiredService<ITranslationService>();
24+
var text = await translator.Translate(agent, Guid.NewGuid().ToString(), model.Text, language: model.ToLang);
25+
return new TranslationResponseModel
26+
{
27+
Text = text
28+
};
29+
}
30+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using BotSharp.Abstraction.Infrastructures.Enums;
2+
3+
namespace BotSharp.OpenAPI.ViewModels.Translations;
4+
5+
public class TranslationRequestModel
6+
{
7+
public string Text { get; set; } = null!;
8+
public string ToLang { get; set; } = LanguageType.CHINESE;
9+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using System.Text.Json.Serialization;
2+
3+
namespace BotSharp.OpenAPI.ViewModels.Translations;
4+
5+
public class TranslationResponseModel
6+
{
7+
public string Text { get; set; } = null!;
8+
9+
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
10+
public string FromLang { get; set; } = null!;
11+
}

src/Plugins/BotSharp.Plugin.SqlDriver/Using.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,3 @@
2121
global using BotSharp.Plugin.SqlDriver.Services;
2222
global using BotSharp.Plugin.SqlHero.Settings;
2323
global using System.Drawing;
24-
global using Console = Colorful.Console;

src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightInstance.cs

Lines changed: 87 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using Microsoft.Playwright;
12
using System.IO;
23

34
namespace BotSharp.Plugin.WebDriver.Drivers.PlaywrightDriver;
@@ -6,31 +7,41 @@ public class PlaywrightInstance : IDisposable
67
{
78
IPlaywright _playwright;
89
Dictionary<string, IBrowserContext> _contexts = new Dictionary<string, IBrowserContext>();
10+
Dictionary<string, List<IPage>> _pages = new Dictionary<string, List<IPage>>();
11+
12+
/// <summary>
13+
/// ContextId and BrowserContext
14+
/// </summary>
915
public Dictionary<string, IBrowserContext> Contexts => _contexts;
1016

11-
public IPage GetPage(string id)
17+
/// <summary>
18+
/// ContextId and Pages
19+
/// </summary>
20+
public Dictionary<string, List<IPage>> Pages => _pages;
21+
22+
public IPage GetPage(string id, string? pattern = null)
1223
{
1324
InitInstance(id).Wait();
1425
return _contexts[id].Pages.LastOrDefault();
1526
}
1627

17-
public async Task<IBrowserContext> InitInstance(string id)
28+
public async Task<IBrowserContext> InitInstance(string ctxId)
1829
{
1930
if (_playwright == null)
2031
{
2132
_playwright = await Playwright.CreateAsync();
2233
}
23-
return await InitContext(id);
34+
return await InitContext(ctxId);
2435
}
2536

26-
public async Task<IBrowserContext> InitContext(string id)
37+
public async Task<IBrowserContext> InitContext(string ctxId)
2738
{
28-
if (_contexts.ContainsKey(id))
29-
return _contexts[id];
39+
if (_contexts.ContainsKey(ctxId))
40+
return _contexts[ctxId];
3041

31-
string tempFolderPath = $"{Path.GetTempPath()}\\playwright\\{id}";
42+
string tempFolderPath = $"{Path.GetTempPath()}\\playwright\\{ctxId}";
3243

33-
_contexts[id] = await _playwright.Chromium.LaunchPersistentContextAsync(tempFolderPath, new BrowserTypeLaunchPersistentContextOptions
44+
_contexts[ctxId] = await _playwright.Chromium.LaunchPersistentContextAsync(tempFolderPath, new BrowserTypeLaunchPersistentContextOptions
3445
{
3546
#if DEBUG
3647
Headless = false,
@@ -42,63 +53,110 @@ public async Task<IBrowserContext> InitContext(string id)
4253
[
4354
"--enable-automation",
4455
],
45-
Args =
56+
Args =
4657
[
4758
"--disable-infobars",
4859
"--test-type"
4960
// "--start-maximized"
5061
]
5162
});
63+
_pages[ctxId] = new List<IPage>();
5264

53-
_contexts[id].Page += async (sender, e) =>
65+
_contexts[ctxId].Page += async (sender, page) =>
5466
{
55-
e.Close += async (sender, e) =>
67+
_pages[ctxId].Add(page);
68+
page.Close += async (sender, e) =>
5669
{
70+
_pages[ctxId].Remove(e);
5771
Serilog.Log.Information($"Page is closed: {e.Url}");
5872
};
59-
Serilog.Log.Information($"New page is created: {e.Url}");
60-
await e.SetViewportSizeAsync(1280, 800);
73+
Serilog.Log.Information($"New page is created: {page.Url}");
74+
if (!page.IsClosed)
75+
{
76+
await page.SetViewportSizeAsync(1600, 900);
77+
}
78+
79+
/*page.Response += async (sender, e) =>
80+
{
81+
Serilog.Log.Information($"Response: {e.Url}");
82+
if (e.Headers.ContainsKey("content-type") && e.Headers["content-type"].Contains("application/json"))
83+
{
84+
var json = await e.JsonAsync();
85+
Serilog.Log.Information(json.ToString());
86+
}
87+
};*/
6188
};
6289

63-
_contexts[id].Close += async (sender, e) =>
90+
_contexts[ctxId].Close += async (sender, e) =>
6491
{
6592
Serilog.Log.Warning($"Playwright browser context is closed");
66-
_contexts.Remove(id);
93+
_pages.Remove(ctxId);
94+
_contexts.Remove(ctxId);
6795
};
6896

69-
return _contexts[id];
97+
return _contexts[ctxId];
7098
}
7199

72-
public async Task<IPage> NewPage(string id)
100+
public async Task<IPage> NewPage(string ctxId, DataFetched? fetched)
73101
{
74-
await InitContext(id);
75-
return await _contexts[id].NewPageAsync();
102+
await InitContext(ctxId);
103+
var page = await _contexts[ctxId].NewPageAsync();
104+
105+
if (fetched != null)
106+
{
107+
page.Response += async (sender, e) =>
108+
{
109+
if (e.Headers.ContainsKey("content-type") &&
110+
e.Headers["content-type"].Contains("application/json") &&
111+
e.Request.ResourceType == "fetch")
112+
{
113+
Serilog.Log.Information($"Response: {e.Url}");
114+
var json = await e.JsonAsync();
115+
fetched(e.Url.ToLower(), JsonSerializer.Serialize(json));
116+
}
117+
};
118+
}
119+
120+
return page;
76121
}
77122

78-
public async Task Wait(string id)
123+
/// <summary>
124+
/// Wait page and network until timeout in seconds
125+
/// </summary>
126+
/// <param name="ctxId"></param>
127+
/// <param name="timeout">seconds</param>
128+
/// <returns></returns>
129+
public async Task Wait(string ctxId, int timeout = 60)
79130
{
80-
if (_contexts.ContainsKey(id))
131+
foreach (var page in _pages[ctxId])
81132
{
82-
var page = _contexts[id].Pages.Last();
83133
await page.WaitForLoadStateAsync(LoadState.DOMContentLoaded);
84-
await page.WaitForLoadStateAsync(LoadState.NetworkIdle);
134+
await page.WaitForLoadStateAsync(LoadState.NetworkIdle, new PageWaitForLoadStateOptions
135+
{
136+
Timeout = 1000 * timeout
137+
});
85138
}
86139
await Task.Delay(100);
87140
}
88141

89-
public async Task Close(string id)
142+
public async Task Close(string ctxId)
90143
{
91-
if (_contexts.ContainsKey(id))
144+
if (_contexts.ContainsKey(ctxId))
92145
{
93-
await _contexts[id].CloseAsync();
146+
await _contexts[ctxId].CloseAsync();
94147
}
95148
}
96149

97-
public async Task CloseCurrentPage(string id)
150+
public async Task CloseCurrentPage(string ctxId)
98151
{
99-
if (_contexts.ContainsKey(id))
152+
var pages = _pages[ctxId].ToArray();
153+
for (var i = 0; i < pages.Length; i++)
100154
{
101-
await GetPage(id).CloseAsync();
155+
var page = _pages[ctxId].FirstOrDefault();
156+
if (page != null)
157+
{
158+
await page.CloseAsync();
159+
}
102160
}
103161
}
104162

src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.GoToPage.cs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using System.Linq;
2+
13
namespace BotSharp.Plugin.WebDriver.Drivers.PlaywrightDriver;
24

35
public partial class PlaywrightWebDriver
@@ -9,7 +11,7 @@ public async Task<BrowserActionResult> GoToPage(MessageInfo message, PageActionA
911
try
1012
{
1113
// Check if the page is already open
12-
if (!args.OpenNewTab && context.Pages.Count > 0)
14+
/*if (!args.OpenNewTab && context.Pages.Count > 0)
1315
{
1416
foreach (var p in context.Pages)
1517
{
@@ -18,14 +20,15 @@ public async Task<BrowserActionResult> GoToPage(MessageInfo message, PageActionA
1820
// Disable this due to performance issue, some page is too large
1921
// result.Body = await p.ContentAsync();
2022
result.IsSuccess = true;
21-
await p.BringToFrontAsync();
23+
// await p.BringToFrontAsync();
2224
return result;
2325
}
2426
}
25-
}
27+
}*/
2628

27-
var page = args.OpenNewTab ? await _instance.NewPage(message.ContextId) :
29+
var page = args.OpenNewTab ? await _instance.NewPage(message.ContextId, fetched: args.OnDataFetched) :
2830
_instance.GetPage(message.ContextId);
31+
2932
var response = await page.GotoAsync(args.Url);
3033
await page.WaitForLoadStateAsync(LoadState.DOMContentLoaded);
3134
await page.WaitForLoadStateAsync(LoadState.NetworkIdle);
@@ -50,4 +53,14 @@ public async Task<BrowserActionResult> GoToPage(MessageInfo message, PageActionA
5053

5154
return result;
5255
}
56+
57+
private void Page_Response1(object sender, IResponse e)
58+
{
59+
throw new NotImplementedException();
60+
}
61+
62+
private void Page_Response(object sender, IResponse e)
63+
{
64+
throw new NotImplementedException();
65+
}
5366
}

0 commit comments

Comments
 (0)