1
0
Fork 0
mirror of https://gitlab.com/niansa/SomeBot.git synced 2025-03-06 20:48:26 +01:00
SomeBot/main.cpp
2022-10-18 00:35:00 +02:00

308 lines
11 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <string>
#include <string_view>
#include <sstream>
#include <fstream>
#include <vector>
#include <unordered_map>
#include <thread>
#ifdef __linux__
# include <sys/sysinfo.h>
# include <sys/utsname.h>
#endif
#include <dpp/dpp.h>
#include "sqlite_modern_cpp/sqlite_modern_cpp.h"
#include <ai.hpp>
const std::string_view ai_init_prompt =
R"(<question> Hello
<answer> Hi!
<question> How are you?
<answer> Great!
<question> What is your favorite color?
<answer> Green!
<question> What is your name?
<answer> I don't have a name.
<question> How are you?
<answer> Good.
<question> )";
template<typename intT>
std::string intAsHex(intT i) {
std::ostringstream sstream;
sstream << "0x" << std::hex << i;
return std::move(sstream).str();
}
uint32_t getColorOfUser(const dpp::user& user) {
uint32_t colors[] = {
0x424cb6,
0x585f68,
0x2c7c45,
0xbc7d14,
0xb23234
};
return colors[user.discriminator % 5];
}
namespace SysInfo { // TODO: This currently works on linux only
# ifdef __linux__
# define SYSINFO_WORKS
size_t memUsed() {
const std::string identifier = "VmData:\t";
std::ifstream pstatus("/proc/self/status");
// Check for success
if (not pstatus) {
return 0;
}
// Find line
std::string currline;
while (currline.find(identifier) != 0) {
std::getline(pstatus, currline);
}
// Close pstatus
pstatus.close();
// Get number
size_t res = 0;
for (const auto& character : currline) {
// Check if character is digit
if (character> '9' or character < '0') {
continue;
}
// Append digit to res
res += static_cast<size_t>(character - '0');
res *= 10;
}
res /= 10;
// Return result in MB
return res / 1000;
}
size_t memTotal() {
// Get sysinfo
struct sysinfo i;
sysinfo(&i);
// Get total ram in MB
return i.totalram / 1000000;
}
std::string kernelNameAndVersion() {
struct utsname name;
uname(&name);
return std::string(name.sysname)+" "+std::string(name.release);
}
# endif
}
int main(int argc, char **argv) {
// Caches
std::vector<dpp::slashcommand> slashcommandCache; // Without IDs
std::unordered_map<dpp::snowflake, dpp::guild> guildCache;
// Initialize AI
Ai ai;
auto chat_reply = [&](const std::string& message) -> std::string {
auto prompt = std::string(ai_init_prompt)+message+"\n<answer>";
return ai.complete(prompt, '\n');
};
// Initialize database
sqlite::database db("db.sqlite3");
db << "CREATE TABLE IF NOT EXISTS guilds ("
" id TEXT PRIMARY KEY NOT NULL,"
" globalchat_channel TEXT,"
" UNIQUE(id)"
");";
// Initialize bot
dpp::cluster bot(argv[1]);
auto broadcast_message = [&](const dpp::message_create_t& message) {
dpp::message msg;
const auto& guild = guildCache.at(message.msg.guild_id);
auto messageCode = intAsHex(message.msg.id)+intAsHex(message.msg.channel_id)+std::to_string(message.msg.guild_id);
msg.add_embed(dpp::embed()
.set_title(":earth_africa: Globalchat")
.set_description(":speaking_head: ["+message.msg.author.format_username()+"](https://internal.tuxifan.net/discordInspectionData/"+messageCode+" 'Inspection Data')")
.set_thumbnail(message.msg.author.get_avatar_url())
.set_color(getColorOfUser(message.msg.author))
.add_field(message.msg.member.nickname.empty()?message.msg.author.username:message.msg.member.nickname, message.msg.content+"\n")
.set_footer(dpp::embed_footer().set_text(guild.name))
);
db << "SELECT globalchat_channel FROM guilds;"
>> [&](std::string channel_id_str) {
if (channel_id_str.empty())
return;
msg.set_channel_id(std::stoul(channel_id_str));
bot.message_create(msg);
};
};
bot.on_log(dpp::utility::cout_logger());
bot.on_slashcommand([&](const dpp::slashcommand_t& event) {
// Help
if (event.command.get_command_name() == "help") {
// Help command
dpp::embed embed;
embed.set_title("Help")
.set_description("Commands")
.set_footer(dpp::embed_footer().set_text("Bot made by 353535#3535"));
for (const auto& command : slashcommandCache) {
embed.add_field(command.name, command.description, true);
}
event.reply(dpp::message().add_embed(embed));
} else if (event.command.get_command_name() == "about") {
// Info command
std::ostringstream info;
info << "**Peak server count**: " << guildCache.size() << "\n"
# ifdef SYSINFO_WORKS
"**VM memory usage**: " << SysInfo::memUsed() << " MB / " << SysInfo::memTotal() << " MB\n"
"**Kernel**: " << SysInfo::kernelNameAndVersion() << "\n"
# endif
"**Compiler**: " COMPILER_ID " " COMPILER_VERSION " (" COMPILER_PLATFORM ")\n"
"**C++ standard**: " << __cplusplus << "\n"
;
event.reply(dpp::message()
.add_embed(dpp::embed()
.set_title("about")
.set_description(std::move(info).str())
));
}
// Fun
else if (event.command.get_command_name() == "ping") {
// Ping command
event.reply("Pong!");
} else if (event.command.get_command_name() == "chat") {
// Chat command
auto& content = std::get<std::string>(event.get_parameter("message"));
event.thinking(false);
std::thread([=, &bot]() {
auto reply = chat_reply(content);
event.delete_original_response();
bot.message_create(dpp::message(event.command.channel_id, event.command.member.get_mention()+" asked:\n> "+content+"\nI reply:\n> "+reply));
}).detach();
}
// Global chat
else if (event.command.get_command_name() == "set_gc") {
// Set global chat command
auto channel_id = std::get<dpp::snowflake>(event.get_parameter("channel"));
// Update globalchat ID
db << "UPDATE guilds "
"SET globalchat_channel = ? "
"WHERE id = ?;"
<< std::to_string(channel_id)
<< std::to_string(event.command.guild_id);
// Reply
event.reply("Globalchat is now in <#"+std::to_string(channel_id)+">");
} else if (event.command.get_command_name() == "reset_gc") {
// Update globalchat ID
db << "UPDATE guilds "
"SET globalchat_channel = NULL "
"WHERE id = ?;"
<< std::to_string(event.command.guild_id);
// Reply
event.reply("Globalchat reset");
}
});
bot.on_message_create([&](const dpp::message_create_t& message) {
// Make sure sender isn't a bot
if (message.msg.author.is_bot())
return;
// Chat with bot
if (message.msg.content[0] == '-') {
auto content = message.msg.content;
content.erase(0, 1);
for (auto& c : content) {
if (c == '\n')
c = ' ';
}
auto reply = chat_reply(content);
message.reply(reply);
return;
}
// Global chat
{
// Get current globalchat channel for server
dpp::snowflake globalchat_channel;
{
std::string globalchat_channel_str;
db << "SELECT globalchat_channel FROM guilds "
"WHERE id = ?;"
<< std::to_string(message.msg.guild_id)
>> std::tie(globalchat_channel_str);
globalchat_channel = std::stoul(globalchat_channel_str);
}
// If this channel is globalchat channel, broadcast message
if (message.msg.channel_id == globalchat_channel) {
broadcast_message(message);
bot.message_delete(message.msg.id, message.msg.channel_id);
return;
}
}
});
bot.on_guild_create([&](const dpp::guild_create_t& guild) {
// Make sure guild is in database
db << "INSERT OR IGNORE INTO guilds (id) VALUES (?);"
<< std::to_string(guild.created->id);
// Add guild to cache
guildCache[guild.created->id] = *guild.created;
});
bot.on_ready([&](const dpp::ready_t& event) {
// Register bot commands once
if (dpp::run_once<struct register_bot_commands>()) {
// Clear all commands first
for (const auto& command : bot.global_commands_get_sync()) {
bot.global_command_delete_sync(command.first);
}
slashcommandCache.clear();
// Help
{
dpp::slashcommand sc("help", "Get help", bot.me.id);
bot.global_command_create(sc);
slashcommandCache.push_back(sc);
}
{
dpp::slashcommand sc("about", "About me", bot.me.id);
bot.global_command_create(sc);
slashcommandCache.push_back(sc);
}
// Fun
{
dpp::slashcommand sc("ping", "Ping pong!", bot.me.id);
bot.global_command_create(sc);
slashcommandCache.push_back(sc);
}{
dpp::slashcommand sc("chat", "Chat with the bot", bot.me.id);
sc.add_option(dpp::command_option(dpp::command_option_type::co_string, "message", "Your message", true));
bot.global_command_create(sc);
slashcommandCache.push_back(sc);
}
// Global chat
{
dpp::slashcommand sc("set_gc", "Set global chat location", bot.me.id);
sc.add_option(dpp::command_option(dpp::command_option_type::co_channel, "channel", "Channel", true));
bot.global_command_create(sc);
slashcommandCache.push_back(sc);
}{
dpp::slashcommand sc("reset_gc", "Reset global chat location", bot.me.id);
bot.global_command_create(sc);
slashcommandCache.push_back(sc);
}
}
});
// Configure intents and start bot
bot.intents |= dpp::intents::i_message_content | dpp::intents::i_guilds;
bot.start(dpp::st_wait);
}