NadekoBot Patronage system, Search commands improvements + fixes

This commit is contained in:
Kwoth
2022-06-14 07:24:33 +00:00
parent 18b10b8c6f
commit 7b5145f116
165 changed files with 14920 additions and 1457 deletions

View File

@@ -0,0 +1,28 @@
using System.Globalization;
using System.Text.Json.Serialization;
namespace NadekoBot.Modules.Searches;
public sealed class SearxImageSearchResult : IImageSearchResult
{
public string SearchTime { get; set; } = null!;
public ISearchResultInformation Info
=> new SearxSearchResultInformation()
{
SearchTime = SearchTime,
TotalResults = NumberOfResults.ToString("N", CultureInfo.InvariantCulture)
};
public IReadOnlyCollection<IImageSearchResultEntry> Entries
=> Results;
[JsonPropertyName("results")]
public List<SearxImageSearchResultEntry> Results { get; set; } = new List<SearxImageSearchResultEntry>();
[JsonPropertyName("query")]
public string Query { get; set; } = null!;
[JsonPropertyName("number_of_results")]
public double NumberOfResults { get; set; }
}

View File

@@ -0,0 +1,14 @@
using System.Text.Json.Serialization;
namespace NadekoBot.Modules.Searches;
public sealed class SearxImageSearchResultEntry : IImageSearchResultEntry
{
public string Link
=> ImageSource.StartsWith("//")
? "https:" + ImageSource
: ImageSource;
[JsonPropertyName("img_src")]
public string ImageSource { get; set; } = string.Empty;
}

View File

@@ -0,0 +1,30 @@
// using System.Text.Json.Serialization;
//
// namespace NadekoBot.Modules.Searches;
//
// public sealed class SearxInfobox
// {
// [JsonPropertyName("infobox")]
// public string Infobox { get; set; }
//
// [JsonPropertyName("id")]
// public string Id { get; set; }
//
// [JsonPropertyName("content")]
// public string Content { get; set; }
//
// [JsonPropertyName("img_src")]
// public string ImgSrc { get; set; }
//
// [JsonPropertyName("urls")]
// public List<SearxUrlData> Urls { get; } = new List<SearxUrlData>();
//
// [JsonPropertyName("engine")]
// public string Engine { get; set; }
//
// [JsonPropertyName("engines")]
// public List<string> Engines { get; } = new List<string>();
//
// [JsonPropertyName("attributes")]
// public List<SearxSearchAttribute> Attributes { get; } = new List<SearxSearchAttribute>();
// }

View File

@@ -0,0 +1,15 @@
using System.Text.Json.Serialization;
namespace NadekoBot.Modules.Searches;
public sealed class SearxSearchAttribute
{
[JsonPropertyName("label")]
public string? Label { get; set; }
[JsonPropertyName("value")]
public string? Value { get; set; }
[JsonPropertyName("entity")]
public string? Entity { get; set; }
}

View File

@@ -0,0 +1,47 @@
using System.Globalization;
using System.Text.Json.Serialization;
namespace NadekoBot.Modules.Searches;
public sealed class SearxSearchResult : ISearchResult
{
[JsonPropertyName("query")]
public string Query { get; set; } = null!;
[JsonPropertyName("number_of_results")]
public double NumberOfResults { get; set; }
[JsonPropertyName("results")]
public List<SearxSearchResultEntry> Results { get; set; } = new List<SearxSearchResultEntry>();
[JsonPropertyName("answers")]
public List<string> Answers { get; set; } = new List<string>();
//
// [JsonPropertyName("corrections")]
// public List<object> Corrections { get; } = new List<object>();
// [JsonPropertyName("infoboxes")]
// public List<InfoboxModel> Infoboxes { get; } = new List<InfoboxModel>();
//
// [JsonPropertyName("suggestions")]
// public List<string> Suggestions { get; } = new List<string>();
// [JsonPropertyName("unresponsive_engines")]
// public List<object> UnresponsiveEngines { get; } = new List<object>();
public string SearchTime { get; set; } = null!;
public IReadOnlyCollection<ISearchResultEntry> Entries
=> Results;
public ISearchResultInformation Info
=> new SearxSearchResultInformation()
{
SearchTime = SearchTime,
TotalResults = NumberOfResults.ToString("N", CultureInfo.InvariantCulture)
};
public string? Answer
=> Answers.FirstOrDefault();
}

View File

@@ -0,0 +1,51 @@
using System.Text.Json.Serialization;
namespace NadekoBot.Modules.Searches;
public sealed class SearxSearchResultEntry : ISearchResultEntry
{
public string DisplayUrl
=> Url;
public string Description
=> Content.TrimTo(768)!;
[JsonPropertyName("url")]
public string Url { get; set; } = null!;
[JsonPropertyName("title")]
public string Title { get; set; } = null!;
[JsonPropertyName("content")]
public string? Content { get; set; }
// [JsonPropertyName("engine")]
// public string Engine { get; set; }
//
// [JsonPropertyName("parsed_url")]
// public List<string> ParsedUrl { get; } = new List<string>();
//
// [JsonPropertyName("template")]
// public string Template { get; set; }
//
// [JsonPropertyName("engines")]
// public List<string> Engines { get; } = new List<string>();
//
// [JsonPropertyName("positions")]
// public List<int> Positions { get; } = new List<int>();
//
// [JsonPropertyName("score")]
// public double Score { get; set; }
//
// [JsonPropertyName("category")]
// public string Category { get; set; }
//
// [JsonPropertyName("pretty_url")]
// public string PrettyUrl { get; set; }
//
// [JsonPropertyName("open_group")]
// public bool OpenGroup { get; set; }
//
// [JsonPropertyName("close_group")]
// public bool? CloseGroup { get; set; }
}

View File

@@ -0,0 +1,7 @@
namespace NadekoBot.Modules.Searches;
public sealed class SearxSearchResultInformation : ISearchResultInformation
{
public string TotalResults { get; init; } = string.Empty;
public string SearchTime { get; init; } = string.Empty;
}

View File

@@ -0,0 +1,76 @@
using MorseCode.ITask;
using System.Diagnostics;
using System.Globalization;
using System.Text.Json;
namespace NadekoBot.Modules.Searches;
public sealed class SearxSearchService : SearchServiceBase, INService
{
private readonly IHttpClientFactory _http;
private readonly SearchesConfigService _scs;
private static readonly Random _rng = new NadekoRandom();
public SearxSearchService(IHttpClientFactory http, SearchesConfigService scs)
=> (_http, _scs) = (http, scs);
private string GetRandomInstance()
{
var instances = _scs.Data.SearxInstances;
if (instances is null or { Count: 0 })
throw new InvalidOperationException("No searx instances specified in searches.yml");
return instances[_rng.Next(0, instances.Count)];
}
public override async ITask<SearxSearchResult> SearchAsync(string query)
{
ArgumentNullException.ThrowIfNull(query);
var instanceUrl = GetRandomInstance();
Log.Information("Using {Instance} instance for web search...", instanceUrl);
var sw = Stopwatch.StartNew();
using var http = _http.CreateClient();
await using var res = await http.GetStreamAsync($"{instanceUrl}"
+ $"?q={Uri.EscapeDataString(query)}"
+ $"&format=json"
+ $"&strict=2");
sw.Stop();
var dat = await JsonSerializer.DeserializeAsync<SearxSearchResult>(res);
if (dat is null)
return new SearxSearchResult();
dat.SearchTime = sw.Elapsed.TotalSeconds.ToString("N2", CultureInfo.InvariantCulture);
return dat;
}
public override async ITask<SearxImageSearchResult> SearchImagesAsync(string query)
{
ArgumentNullException.ThrowIfNull(query);
var instanceUrl = GetRandomInstance();
Log.Information("Using {Instance} instance for img search...", instanceUrl);
var sw = Stopwatch.StartNew();
using var http = _http.CreateClient();
await using var res = await http.GetStreamAsync($"{instanceUrl}"
+ $"?q={Uri.EscapeDataString(query)}"
+ $"&format=json"
+ $"&category_images=on"
+ $"&strict=2");
sw.Stop();
var dat = await JsonSerializer.DeserializeAsync<SearxImageSearchResult>(res);
if (dat is null)
return new SearxImageSearchResult();
dat.SearchTime = sw.Elapsed.TotalSeconds.ToString("N2", CultureInfo.InvariantCulture);
return dat;
}
}

View File

@@ -0,0 +1,15 @@
using System.Text.Json.Serialization;
namespace NadekoBot.Modules.Searches;
public sealed class SearxUrlData
{
[JsonPropertyName("title")]
public string Title { get; set; } = null!;
[JsonPropertyName("url")]
public string Url { get; set; } = null!;
[JsonPropertyName("official")]
public bool? Official { get; set; }
}