mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2025-09-11 17:58:26 -04:00
NadekoBot Patronage system, Search commands improvements + fixes
This commit is contained in:
@@ -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; }
|
||||
}
|
@@ -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;
|
||||
}
|
30
src/NadekoBot/Modules/Searches/Search/Searx/SearxInfobox.cs
Normal file
30
src/NadekoBot/Modules/Searches/Search/Searx/SearxInfobox.cs
Normal 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>();
|
||||
// }
|
@@ -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; }
|
||||
}
|
@@ -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();
|
||||
}
|
@@ -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; }
|
||||
}
|
@@ -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;
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
15
src/NadekoBot/Modules/Searches/Search/Searx/SearxUrlData.cs
Normal file
15
src/NadekoBot/Modules/Searches/Search/Searx/SearxUrlData.cs
Normal 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; }
|
||||
}
|
Reference in New Issue
Block a user