diff --git a/src/Infrastructure/BotSharp.Abstraction/Browsing/IWebBrowser.cs b/src/Infrastructure/BotSharp.Abstraction/Browsing/IWebBrowser.cs index 3b4dcfde..376c7cac 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Browsing/IWebBrowser.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Browsing/IWebBrowser.cs @@ -24,4 +24,5 @@ public interface IWebBrowser Task EvaluateScript(string conversationId, string script); Task CloseBrowser(string conversationId); Task SendHttpRequest(BrowserActionParams actionParams); + Task GetAttributeValue(MessageInfo message, ElementLocatingArgs location, BrowserActionResult result); } diff --git a/src/Infrastructure/BotSharp.Abstraction/Google/Models/GoogleVideoResult.cs b/src/Infrastructure/BotSharp.Abstraction/Google/Models/GoogleVideoResult.cs new file mode 100644 index 00000000..442290aa --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/Google/Models/GoogleVideoResult.cs @@ -0,0 +1,44 @@ +namespace BotSharp.Abstraction.Google.Models; + +public class GoogleVideoResult +{ + public string Kind { get; set; } + public IList Items { get; set; } = new List(); +} + +public class VideoItem +{ + public string Kind { get; set; } + [JsonPropertyName("etag")] + public string Etag { get; set; } + public VideoItemId Id { get; set; } + public VideoSnippet Snippet { get; set; } +} + +public class VideoItemId +{ + public string Kind { get; set; } + public string VideoId { get; set; } +} + +public class VideoSnippet +{ + public string Title { get; set; } + public string Description { get; set; } + public string ChannelTitle { get; set; } + public VideoThumbnails Thumbnails { get; set; } +} + +public class VideoThumbnails +{ + public ThumbnailData Default { get; set; } + public ThumbnailData Medium { get; set; } + public ThumbnailData High { get; set; } +} + +public class ThumbnailData +{ + public string Url { get; set; } + public decimal Width { get; set; } + public decimal Height { get; set; } +} \ No newline at end of file diff --git a/src/Infrastructure/BotSharp.Abstraction/Google/Settings/GoogleApiSettings.cs b/src/Infrastructure/BotSharp.Abstraction/Google/Settings/GoogleApiSettings.cs index d43ec58b..be7ef6a2 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Google/Settings/GoogleApiSettings.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Google/Settings/GoogleApiSettings.cs @@ -3,7 +3,20 @@ namespace BotSharp.Abstraction.Google.Settings; public class GoogleApiSettings { public string ApiKey { get; set; } + public MapSettings Map { get; set; } + public YoutubeSettings Youtube { get; set; } +} + + +public class MapSettings +{ public string Endpoint { get; set; } - public string Language { get; set; } public string Components { get; set; } } + +public class YoutubeSettings +{ + public string Endpoint { get; set; } + public string Part { get; set; } + public string RegionCode { get; set; } +} \ No newline at end of file diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/AddressController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/AddressController.cs deleted file mode 100644 index 755b8232..00000000 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/AddressController.cs +++ /dev/null @@ -1,50 +0,0 @@ -using BotSharp.Abstraction.Google.Models; -using BotSharp.Abstraction.Google.Settings; -using BotSharp.Abstraction.Options; - -namespace BotSharp.OpenAPI.Controllers; - -[Authorize] -[ApiController] -public class AddressController : ControllerBase -{ - private readonly IServiceProvider _services; - private readonly BotSharpOptions _options; - private readonly IHttpClientFactory _httpClientFactory; - private readonly ILogger _logger; - - public AddressController(IServiceProvider services, - IHttpClientFactory httpClientFactory, - BotSharpOptions options) - { - _services = services; - _options = options; - _httpClientFactory = httpClientFactory; - } - - [HttpGet("/address/options")] - public async Task GetAddressOptions([FromQuery] string address) - { - var result = new GoogleAddressResult(); - - try - { - var settings = _services.GetRequiredService(); - using var client = _httpClientFactory.CreateClient(); - var url = $"{settings.Endpoint}?key={settings.ApiKey}&" + - $"components={settings.Components}&" + - $"language={settings.Language}&" + - $"address={address}"; - - var response = await client.GetAsync(url); - var responseStr = await response.Content.ReadAsStringAsync(); - result = JsonSerializer.Deserialize(responseStr, _options.JsonSerializerOptions); - } - catch (Exception ex) - { - _logger.LogError($"Error when calling google geocoding api... ${ex.Message}"); - } - - return result; - } -} diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/GoogleController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/GoogleController.cs new file mode 100644 index 00000000..13faeb2d --- /dev/null +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/GoogleController.cs @@ -0,0 +1,82 @@ +using BotSharp.Abstraction.Google.Models; +using BotSharp.Abstraction.Google.Settings; +using BotSharp.Abstraction.Options; + +namespace BotSharp.OpenAPI.Controllers; + +[Authorize] +[ApiController] +public class GoogleController : ControllerBase +{ + private readonly IServiceProvider _services; + private readonly BotSharpOptions _options; + private readonly IHttpClientFactory _httpClientFactory; + private readonly ILogger _logger; + + public GoogleController(IServiceProvider services, + IHttpClientFactory httpClientFactory, + BotSharpOptions options) + { + _services = services; + _options = options; + _httpClientFactory = httpClientFactory; + } + + [HttpGet("/address/options")] + public async Task GetAddressOptions([FromQuery] string address, [FromQuery] string language = "en") + { + var result = new GoogleAddressResult(); + + try + { + var settings = _services.GetRequiredService(); + using var client = _httpClientFactory.CreateClient(); + var url = $"{settings.Map.Endpoint}?key={settings.ApiKey}&" + + $"components={settings.Map.Components}&" + + $"language={language}&" + + $"address={address}"; + + var response = await client.GetAsync(url); + var responseStr = await response.Content.ReadAsStringAsync(); + result = JsonSerializer.Deserialize(responseStr, _options.JsonSerializerOptions); + } + catch (Exception ex) + { + _logger.LogError($"Error when calling google geocoding api... ${ex.Message}"); + } + + return result; + } + + [HttpGet("/video/options")] + public async Task GetVideoOptions([FromQuery] string query, [FromQuery] int? maxResults, [FromQuery] string language = "en") + { + var result = new GoogleVideoResult(); + + try + { + var settings = _services.GetRequiredService(); + using var client = _httpClientFactory.CreateClient(); + var url = $"{settings.Youtube.Endpoint}?key={settings.ApiKey}&" + + $"part={settings.Youtube.Part}&" + + $"relevanceLanguage={language}&" + + $"regionCode={settings.Youtube.RegionCode}&" + + $"q={query}"; + + if (maxResults.HasValue && maxResults > 0) + { + url += $"&maxResults={maxResults}"; + } + + var response = await client.GetAsync(url); + var responseStr = await response.Content.ReadAsStringAsync(); + result = JsonSerializer.Deserialize(responseStr, _options.JsonSerializerOptions); + } + catch (Exception ex) + { + _logger.LogError($"Error when calling google youtube search api... ${ex.Message}"); + } + + return result; + } +} diff --git a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.GetAttributeValue.cs b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.GetAttributeValue.cs new file mode 100644 index 00000000..8b87c2c8 --- /dev/null +++ b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.GetAttributeValue.cs @@ -0,0 +1,18 @@ +namespace BotSharp.Plugin.WebDriver.Drivers.PlaywrightDriver; + +public partial class PlaywrightWebDriver +{ + public async Task GetAttributeValue(MessageInfo message, ElementLocatingArgs location, BrowserActionResult result) + { + var page = _instance.GetPage(message.ConversationId); + ILocator locator = page.Locator(result.Selector); + var value = string.Empty; + + if (!string.IsNullOrEmpty(location?.AttributeName)) + { + value = await locator.GetAttributeAsync(location.AttributeName); + } + + return value ?? string.Empty; + } +} 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 fd46c879..9ec68d20 100644 --- a/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.LocateElement.cs +++ b/src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.LocateElement.cs @@ -45,7 +45,7 @@ public partial class PlaywrightWebDriver } } - if (location.Index > 0) + if (location.Index >= 0) { locator = locator.Nth(location.Index); count = await locator.CountAsync(); diff --git a/src/WebStarter/appsettings.json b/src/WebStarter/appsettings.json index ed24f1db..356279b3 100644 --- a/src/WebStarter/appsettings.json +++ b/src/WebStarter/appsettings.json @@ -216,10 +216,16 @@ }, "GoogleApi": { - "Endpoint": "https://maps.googleapis.com/maps/api/geocode/json", "ApiKey": "", - "Components": "country=US|country=CA", - "Language": "en" + "Map": { + "Endpoint": "https://maps.googleapis.com/maps/api/geocode/json", + "Components": "country=US|country=CA", + }, + "Youtube": { + "Endpoint": "https://www.googleapis.com/youtube/v3/search", + "RegionCode": "US", + "Part": "id,snippet" + } }, "PluginLoader": {