mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2025-09-11 01:38:27 -04:00
Added GPT-3 as an alternative to cleverbot in .config games
and data/games.yml
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
#nullable disable
|
||||
using NadekoBot.Common.ModuleBehaviors;
|
||||
using NadekoBot.Db.Models;
|
||||
using NadekoBot.Modules.Games.Common;
|
||||
using NadekoBot.Modules.Games.Common.ChatterBot;
|
||||
using NadekoBot.Modules.Permissions;
|
||||
using NadekoBot.Modules.Permissions.Common;
|
||||
@@ -27,6 +28,7 @@ public class ChatterBotService : IExecOnMessage
|
||||
private readonly IHttpClientFactory _httpFactory;
|
||||
private readonly IPatronageService _ps;
|
||||
private readonly CmdCdService _ccs;
|
||||
private readonly GamesConfigService _gcs;
|
||||
|
||||
public ChatterBotService(
|
||||
DiscordSocketClient client,
|
||||
@@ -38,7 +40,8 @@ public class ChatterBotService : IExecOnMessage
|
||||
IBotCredentials creds,
|
||||
IEmbedBuilderService eb,
|
||||
IPatronageService ps,
|
||||
CmdCdService cmdCdService)
|
||||
CmdCdService cmdCdService,
|
||||
GamesConfigService gcs)
|
||||
{
|
||||
_client = client;
|
||||
_perms = perms;
|
||||
@@ -49,6 +52,7 @@ public class ChatterBotService : IExecOnMessage
|
||||
_httpFactory = factory;
|
||||
_ps = ps;
|
||||
_ccs = cmdCdService;
|
||||
_gcs = gcs;
|
||||
|
||||
_flKey = new FeatureLimitKey()
|
||||
{
|
||||
@@ -64,11 +68,26 @@ public class ChatterBotService : IExecOnMessage
|
||||
|
||||
public IChatterBotSession CreateSession()
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(_creds.CleverbotApiKey))
|
||||
return new OfficialCleverbotSession(_creds.CleverbotApiKey, _httpFactory);
|
||||
switch (_gcs.Data.ChatBot)
|
||||
{
|
||||
case ChatBotImplementation.Cleverbot:
|
||||
if (!string.IsNullOrWhiteSpace(_creds.CleverbotApiKey))
|
||||
return new OfficialCleverbotSession(_creds.CleverbotApiKey, _httpFactory);
|
||||
|
||||
Log.Information("Cleverbot will not work as the api key is missing.");
|
||||
return null;
|
||||
Log.Information("Cleverbot will not work as the api key is missing.");
|
||||
return null;
|
||||
case ChatBotImplementation.Gpt3:
|
||||
if (!string.IsNullOrWhiteSpace(_creds.Gpt3ApiKey))
|
||||
return new OfficialGpt3Session(_creds.Gpt3ApiKey,
|
||||
_gcs.Data.ChatGpt.Model,
|
||||
_gcs.Data.ChatGpt.MaxTokens,
|
||||
_httpFactory);
|
||||
|
||||
Log.Information("Gpt3 will not work as the api key is missing.");
|
||||
return null;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public string PrepareMessage(IUserMessage msg, out IChatterBotSession cleverbot)
|
||||
@@ -102,7 +121,7 @@ public class ChatterBotService : IExecOnMessage
|
||||
{
|
||||
if (guild is not SocketGuild sg)
|
||||
return false;
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
var message = PrepareMessage(usrMsg, out var cbs);
|
||||
@@ -147,7 +166,7 @@ public class ChatterBotService : IExecOnMessage
|
||||
uint? monthly = quota.Quota is int mVal and >= 0
|
||||
? (uint)mVal
|
||||
: null;
|
||||
|
||||
|
||||
var maybeLimit = await _ps.TryIncrementQuotaCounterAsync(sg.OwnerId,
|
||||
sg.OwnerId == usrMsg.Author.Id,
|
||||
FeatureType.Limit,
|
||||
@@ -155,7 +174,7 @@ public class ChatterBotService : IExecOnMessage
|
||||
null,
|
||||
daily,
|
||||
monthly);
|
||||
|
||||
|
||||
if (maybeLimit.TryPickT1(out var ql, out var counters))
|
||||
{
|
||||
if (ql.Quota == 0)
|
||||
@@ -166,7 +185,7 @@ public class ChatterBotService : IExecOnMessage
|
||||
"In order to use the cleverbot feature, the owner of this server should be [Patron Tier X](https://patreon.com/join/nadekobot) on patreon.",
|
||||
footer:
|
||||
"You may disable the cleverbot feature, and this message via '.cleverbot' command");
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -174,7 +193,7 @@ public class ChatterBotService : IExecOnMessage
|
||||
null!,
|
||||
$"You've reached your quota limit of **{ql.Quota}** responses {ql.QuotaPeriod.ToFullName()} for the cleverbot feature.",
|
||||
footer: "You may wait for the quota reset or .");
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -185,7 +204,7 @@ public class ChatterBotService : IExecOnMessage
|
||||
title: null,
|
||||
response.SanitizeMentions(true)
|
||||
// , footer: counter > 0 ? counter.ToString() : null
|
||||
);
|
||||
);
|
||||
|
||||
Log.Information(@"CleverBot Executed
|
||||
Server: {GuildName} [{GuildId}]
|
||||
|
@@ -1,8 +0,0 @@
|
||||
#nullable disable
|
||||
namespace NadekoBot.Modules.Games.Common.ChatterBot;
|
||||
|
||||
public class ChatterBotResponse
|
||||
{
|
||||
public string Convo_id { get; set; }
|
||||
public string BotSay { get; set; }
|
||||
}
|
@@ -0,0 +1,30 @@
|
||||
#nullable disable
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace NadekoBot.Modules.Games.Common.ChatterBot;
|
||||
|
||||
public class Gpt3Response
|
||||
{
|
||||
[JsonPropertyName("choices")]
|
||||
public Choice[] Choices { get; set; }
|
||||
}
|
||||
|
||||
public class Choice
|
||||
{
|
||||
public string Text { get; set; }
|
||||
}
|
||||
|
||||
public class Gpt3ApiRequest
|
||||
{
|
||||
[JsonPropertyName("model")]
|
||||
public string Model { get; init; }
|
||||
|
||||
[JsonPropertyName("prompt")]
|
||||
public string Prompt { get; init; }
|
||||
|
||||
[JsonPropertyName("temperature")]
|
||||
public int Temperature { get; init; }
|
||||
|
||||
[JsonPropertyName("max_tokens")]
|
||||
public int MaxTokens { get; init; }
|
||||
}
|
@@ -0,0 +1,69 @@
|
||||
#nullable disable
|
||||
using Newtonsoft.Json;
|
||||
using System.Net.Http.Json;
|
||||
|
||||
namespace NadekoBot.Modules.Games.Common.ChatterBot;
|
||||
|
||||
public class OfficialGpt3Session : IChatterBotSession
|
||||
{
|
||||
private string Uri
|
||||
=> $"https://api.openai.com/v1/completions";
|
||||
|
||||
private readonly string _apiKey;
|
||||
private readonly string _model;
|
||||
private readonly int _maxTokens;
|
||||
private readonly IHttpClientFactory _httpFactory;
|
||||
|
||||
public OfficialGpt3Session(
|
||||
string apiKey,
|
||||
Gpt3Model model,
|
||||
int maxTokens,
|
||||
IHttpClientFactory factory)
|
||||
{
|
||||
_apiKey = apiKey;
|
||||
_httpFactory = factory;
|
||||
switch (model)
|
||||
{
|
||||
case Gpt3Model.Ada001:
|
||||
_model = "text-ada-001";
|
||||
break;
|
||||
case Gpt3Model.Babbage001:
|
||||
_model = "text-babbage-001";
|
||||
break;
|
||||
case Gpt3Model.Curie001:
|
||||
_model = "text-curie-001";
|
||||
break;
|
||||
case Gpt3Model.Davinci003:
|
||||
_model = "text-davinci-003";
|
||||
break;
|
||||
}
|
||||
|
||||
_maxTokens = maxTokens;
|
||||
}
|
||||
|
||||
public async Task<string> Think(string input)
|
||||
{
|
||||
using var http = _httpFactory.CreateClient();
|
||||
http.DefaultRequestHeaders.Authorization = new("Bearer", _apiKey);
|
||||
var data = await http.PostAsJsonAsync(Uri, new Gpt3ApiRequest()
|
||||
{
|
||||
Model = _model,
|
||||
Prompt = input,
|
||||
MaxTokens = _maxTokens,
|
||||
Temperature = 1,
|
||||
});
|
||||
var dataString = await data.Content.ReadAsStringAsync();
|
||||
try
|
||||
{
|
||||
var response = JsonConvert.DeserializeObject<Gpt3Response>(dataString);
|
||||
|
||||
return response?.Choices[0]?.Text;
|
||||
}
|
||||
catch
|
||||
{
|
||||
Log.Warning("Unexpected GPT-3 response received: {ResponseString}", dataString);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -8,7 +8,7 @@ namespace NadekoBot.Modules.Games.Common;
|
||||
public sealed partial class GamesConfig : ICloneable<GamesConfig>
|
||||
{
|
||||
[Comment("DO NOT CHANGE")]
|
||||
public int Version { get; set; }
|
||||
public int Version { get; set; } = 2;
|
||||
|
||||
[Comment("Hangman related settings (.hangman command)")]
|
||||
public HangmanConfig Hangman { get; set; } = new()
|
||||
@@ -95,6 +95,27 @@ public sealed partial class GamesConfig : ICloneable<GamesConfig>
|
||||
Name = "Unicorn"
|
||||
}
|
||||
};
|
||||
|
||||
[Comment(@"Which chatbot API should bot use.
|
||||
'cleverbot' - bot will use Cleverbot API.
|
||||
'gpt3' - bot will use GPT-3 API")]
|
||||
public ChatBotImplementation ChatBot { get; set; } = ChatBotImplementation.Gpt3;
|
||||
|
||||
public ChatGptConfig ChatGpt { get; set; } = new();
|
||||
}
|
||||
|
||||
[Cloneable]
|
||||
public sealed partial class ChatGptConfig
|
||||
{
|
||||
[Comment(@"Which GPT-3 Model should bot use.
|
||||
'ada' - cheapest and fastest
|
||||
'babbage' - 2nd option
|
||||
'curie' - 3rd option
|
||||
'davinci' - Most expensive, slowest")]
|
||||
public Gpt3Model Model { get; set; } = Gpt3Model.Ada001;
|
||||
|
||||
[Comment(@"The maximum number of tokens to use per GPT-3 API call")]
|
||||
public int MaxTokens { get; set; } = 100;
|
||||
}
|
||||
|
||||
[Cloneable]
|
||||
@@ -120,4 +141,18 @@ public sealed partial class RaceAnimal
|
||||
{
|
||||
public string Icon { get; set; }
|
||||
public string Name { get; set; }
|
||||
}
|
||||
|
||||
public enum ChatBotImplementation
|
||||
{
|
||||
Cleverbot,
|
||||
Gpt3
|
||||
}
|
||||
|
||||
public enum Gpt3Model
|
||||
{
|
||||
Ada001,
|
||||
Babbage001,
|
||||
Curie001,
|
||||
Davinci003
|
||||
}
|
@@ -28,6 +28,20 @@ public sealed class GamesConfigService : ConfigServiceBase<GamesConfig>
|
||||
long.TryParse,
|
||||
ConfigPrinters.ToString,
|
||||
val => val >= 0);
|
||||
|
||||
AddParsedProp("chatbot",
|
||||
gs => gs.ChatBot,
|
||||
ConfigParsers.InsensitiveEnum,
|
||||
ConfigPrinters.ToString);
|
||||
AddParsedProp("gpt.model",
|
||||
gs => gs.ChatGpt.Model,
|
||||
ConfigParsers.InsensitiveEnum,
|
||||
ConfigPrinters.ToString);
|
||||
AddParsedProp("gpt.max_tokens",
|
||||
gs => gs.ChatGpt.MaxTokens,
|
||||
int.TryParse,
|
||||
ConfigPrinters.ToString,
|
||||
val => val > 0);
|
||||
|
||||
Migrate();
|
||||
}
|
||||
@@ -45,5 +59,14 @@ public sealed class GamesConfigService : ConfigServiceBase<GamesConfig>
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
if (data.Version < 2)
|
||||
{
|
||||
ModifyConfig(c =>
|
||||
{
|
||||
c.Version = 2;
|
||||
c.ChatBot = ChatBotImplementation.Cleverbot;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@@ -23,7 +23,6 @@ public class GamesService : INService, IReadyExecutor
|
||||
|
||||
//channelId, game
|
||||
public ConcurrentDictionary<ulong, AcrophobiaGame> AcrophobiaGames { get; } = new();
|
||||
public ConcurrentDictionary<ulong, TriviaGame> RunningTrivias { get; } = new();
|
||||
public Dictionary<ulong, TicTacToe> TicTacToeGames { get; } = new();
|
||||
public ConcurrentDictionary<ulong, TypingGame> RunningContests { get; } = new();
|
||||
public ConcurrentDictionary<ulong, NunchiGame> NunchiGames { get; } = new();
|
||||
|
Reference in New Issue
Block a user