Fixed some crashes in response strings source generator, reorganized more submodules into their folders

This commit is contained in:
Kwoth
2022-01-02 03:49:54 +01:00
parent 9c590668df
commit 4b6af0e4ef
191 changed files with 120 additions and 80 deletions

View File

@@ -0,0 +1,143 @@
#nullable disable
using NadekoBot.Common.ModuleBehaviors;
using NadekoBot.Modules.Games.Common.ChatterBot;
using NadekoBot.Modules.Permissions.Common;
using NadekoBot.Modules.Permissions.Services;
namespace NadekoBot.Modules.Games.Services;
public class ChatterBotService : IEarlyBehavior
{
public ConcurrentDictionary<ulong, Lazy<IChatterBotSession>> ChatterBotGuilds { get; }
public int Priority
=> 1;
private readonly DiscordSocketClient _client;
private readonly PermissionService _perms;
private readonly CommandHandler _cmd;
private readonly IBotStrings _strings;
private readonly IBotCredentials _creds;
private readonly IEmbedBuilderService _eb;
private readonly IHttpClientFactory _httpFactory;
public ChatterBotService(
DiscordSocketClient client,
PermissionService perms,
Bot bot,
CommandHandler cmd,
IBotStrings strings,
IHttpClientFactory factory,
IBotCredentials creds,
IEmbedBuilderService eb)
{
_client = client;
_perms = perms;
_cmd = cmd;
_strings = strings;
_creds = creds;
_eb = eb;
_httpFactory = factory;
ChatterBotGuilds = new(bot.AllGuildConfigs.Where(gc => gc.CleverbotEnabled)
.ToDictionary(gc => gc.GuildId,
_ => new Lazy<IChatterBotSession>(() => CreateSession(), true)));
}
public IChatterBotSession CreateSession()
{
if (!string.IsNullOrWhiteSpace(_creds.CleverbotApiKey))
return new OfficialCleverbotSession(_creds.CleverbotApiKey, _httpFactory);
return new CleverbotIOSession("GAh3wUfzDCpDpdpT", "RStKgqn7tcO9blbrv4KbXM8NDlb7H37C", _httpFactory);
}
public string PrepareMessage(IUserMessage msg, out IChatterBotSession cleverbot)
{
var channel = msg.Channel as ITextChannel;
cleverbot = null;
if (channel is null)
return null;
if (!ChatterBotGuilds.TryGetValue(channel.Guild.Id, out var lazyCleverbot))
return null;
cleverbot = lazyCleverbot.Value;
var nadekoId = _client.CurrentUser.Id;
var normalMention = $"<@{nadekoId}> ";
var nickMention = $"<@!{nadekoId}> ";
string message;
if (msg.Content.StartsWith(normalMention, StringComparison.InvariantCulture))
message = msg.Content[normalMention.Length..].Trim();
else if (msg.Content.StartsWith(nickMention, StringComparison.InvariantCulture))
message = msg.Content[nickMention.Length..].Trim();
else
return null;
return message;
}
public async Task<bool> TryAsk(IChatterBotSession cleverbot, ITextChannel channel, string message)
{
await channel.TriggerTypingAsync();
var response = await cleverbot.Think(message);
try
{
await channel.SendConfirmAsync(_eb, response.SanitizeMentions(true));
}
catch
{
await channel.SendConfirmAsync(_eb, response.SanitizeMentions(true)); // try twice :\
}
return true;
}
public async Task<bool> RunBehavior(IGuild guild, IUserMessage usrMsg)
{
if (guild is not SocketGuild sg)
return false;
try
{
var message = PrepareMessage(usrMsg, out var cbs);
if (message is null || cbs is null)
return false;
var pc = _perms.GetCacheFor(guild.Id);
if (!pc.Permissions.CheckPermissions(usrMsg, "cleverbot", "Games".ToLowerInvariant(), out var index))
{
if (pc.Verbose)
{
var returnMsg = _strings.GetText(strs.perm_prevent(index + 1,
Format.Bold(pc.Permissions[index].GetCommand(_cmd.GetPrefix(sg), sg))));
try { await usrMsg.Channel.SendErrorAsync(_eb, returnMsg); }
catch { }
Log.Information(returnMsg);
}
return true;
}
var cleverbotExecuted = await TryAsk(cbs, (ITextChannel)usrMsg.Channel, message);
if (cleverbotExecuted)
{
Log.Information($@"CleverBot Executed
Server: {guild.Name} [{guild.Id}]
Channel: {usrMsg.Channel?.Name} [{usrMsg.Channel?.Id}]
UserId: {usrMsg.Author} [{usrMsg.Author.Id}]
Message: {usrMsg.Content}");
return true;
}
}
catch (Exception ex)
{
Log.Warning(ex, "Error in cleverbot");
}
return false;
}
}

View File

@@ -0,0 +1,48 @@
#nullable disable
using NadekoBot.Db;
using NadekoBot.Modules.Games.Services;
namespace NadekoBot.Modules.Games;
public partial class Games
{
[Group]
public partial class ChatterBotCommands : NadekoSubmodule<ChatterBotService>
{
private readonly DbService _db;
public ChatterBotCommands(DbService db)
=> _db = db;
[NoPublicBot]
[Cmd]
[RequireContext(ContextType.Guild)]
[UserPerm(GuildPerm.ManageMessages)]
public async partial Task Cleverbot()
{
var channel = (ITextChannel)ctx.Channel;
if (_service.ChatterBotGuilds.TryRemove(channel.Guild.Id, out _))
{
await using (var uow = _db.GetDbContext())
{
uow.GuildConfigs.SetCleverbotEnabled(ctx.Guild.Id, false);
await uow.SaveChangesAsync();
}
await ReplyConfirmLocalizedAsync(strs.cleverbot_disabled);
return;
}
_service.ChatterBotGuilds.TryAdd(channel.Guild.Id, new(() => _service.CreateSession(), true));
await using (var uow = _db.GetDbContext())
{
uow.GuildConfigs.SetCleverbotEnabled(ctx.Guild.Id, true);
await uow.SaveChangesAsync();
}
await ReplyConfirmLocalizedAsync(strs.cleverbot_enabled);
}
}
}

View File

@@ -0,0 +1,8 @@
#nullable disable
namespace NadekoBot.Modules.Games.Common.ChatterBot;
public class ChatterBotResponse
{
public string Convo_id { get; set; }
public string BotSay { get; set; }
}

View File

@@ -0,0 +1,34 @@
#nullable disable
using Newtonsoft.Json;
namespace NadekoBot.Modules.Games.Common.ChatterBot;
public class ChatterBotSession : IChatterBotSession
{
private static NadekoRandom Rng { get; } = new();
private string ApiEndpoint
=> "http://api.program-o.com/v2/chatbot/"
+ $"?bot_id={_botId}&"
+ "say={0}&"
+ $"convo_id=nadekobot_{_chatterBotId}&"
+ "format=json";
private readonly string _chatterBotId;
private readonly IHttpClientFactory _httpFactory;
private readonly int _botId = 6;
public ChatterBotSession(IHttpClientFactory httpFactory)
{
_chatterBotId = Rng.Next(0, 1000000).ToString().ToBase64();
_httpFactory = httpFactory;
}
public async Task<string> Think(string message)
{
using var http = _httpFactory.CreateClient();
var res = await http.GetStringAsync(string.Format(ApiEndpoint, message));
var cbr = JsonConvert.DeserializeObject<ChatterBotResponse>(res);
return cbr.BotSay.Replace("<br/>", "\n", StringComparison.InvariantCulture);
}
}

View File

@@ -0,0 +1,20 @@
#nullable disable
namespace NadekoBot.Modules.Games.Common.ChatterBot;
public class CleverbotResponse
{
public string Cs { get; set; }
public string Output { get; set; }
}
public class CleverbotIOCreateResponse
{
public string Status { get; set; }
public string Nick { get; set; }
}
public class CleverbotIOAskResponse
{
public string Status { get; set; }
public string Response { get; set; }
}

View File

@@ -0,0 +1,7 @@
#nullable disable
namespace NadekoBot.Modules.Games.Common.ChatterBot;
public interface IChatterBotSession
{
Task<string> Think(string input);
}

View File

@@ -0,0 +1,92 @@
#nullable disable
using Newtonsoft.Json;
namespace NadekoBot.Modules.Games.Common.ChatterBot;
public class OfficialCleverbotSession : IChatterBotSession
{
private string QueryString
=> $"https://www.cleverbot.com/getreply?key={_apiKey}" + "&wrapper=nadekobot" + "&input={0}" + "&cs={1}";
private readonly string _apiKey;
private readonly IHttpClientFactory _httpFactory;
private string _cs;
public OfficialCleverbotSession(string apiKey, IHttpClientFactory factory)
{
_apiKey = apiKey;
_httpFactory = factory;
}
public async Task<string> Think(string input)
{
using var http = _httpFactory.CreateClient();
var dataString = await http.GetStringAsync(string.Format(QueryString, input, _cs ?? ""));
try
{
var data = JsonConvert.DeserializeObject<CleverbotResponse>(dataString);
_cs = data?.Cs;
return data?.Output;
}
catch
{
Log.Warning("Unexpected cleverbot response received: ");
Log.Warning(dataString);
return null;
}
}
}
public class CleverbotIOSession : IChatterBotSession
{
private readonly string _key;
private readonly string _user;
private readonly IHttpClientFactory _httpFactory;
private readonly AsyncLazy<string> _nick;
private readonly string _createEndpoint = "https://cleverbot.io/1.0/create";
private readonly string _askEndpoint = "https://cleverbot.io/1.0/ask";
public CleverbotIOSession(string user, string key, IHttpClientFactory factory)
{
_key = key;
_user = user;
_httpFactory = factory;
_nick = new(GetNick);
}
private async Task<string> GetNick()
{
using var _http = _httpFactory.CreateClient();
using var msg = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("user", _user), new KeyValuePair<string, string>("key", _key)
});
using var data = await _http.PostAsync(_createEndpoint, msg);
var str = await data.Content.ReadAsStringAsync();
var obj = JsonConvert.DeserializeObject<CleverbotIOCreateResponse>(str);
if (obj.Status != "success")
throw new OperationCanceledException(obj.Status);
return obj.Nick;
}
public async Task<string> Think(string input)
{
using var _http = _httpFactory.CreateClient();
using var msg = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("user", _user), new KeyValuePair<string, string>("key", _key),
new KeyValuePair<string, string>("nick", await _nick), new KeyValuePair<string, string>("text", input)
});
using var data = await _http.PostAsync(_askEndpoint, msg);
var str = await data.Content.ReadAsStringAsync();
var obj = JsonConvert.DeserializeObject<CleverbotIOAskResponse>(str);
if (obj.Status != "success")
throw new OperationCanceledException(obj.Status);
return obj.Response;
}
}