#include "handlers.hpp" #include #include #include #include #include #include #include #include "bundle.hpp" #include "commands/command.hpp" #include "commands/request.hpp" #include "commands/response_error.hpp" #include "constants.hpp" #include "cpr/api.h" #include "cpr/multipart.h" #include "cpr/response.h" #include "database.hpp" #include "irc/message.hpp" #include "localization/line_id.hpp" #include "logger.hpp" #include "nlohmann/json.hpp" #include "schemas/channel.hpp" #include "utils/string.hpp" namespace bot::handlers { void handle_private_message( const InstanceBundle &bundle, command::CommandLoader &command_loader, const irc::Message &message) { std::unique_ptr conn = db::create_connection(bundle.configuration); std::optional request = command::generate_request(command_loader, message, conn); if (request.has_value()) { try { auto response = command_loader.run(bundle, request.value()); if (response.has_value()) { if (response->is_single()) { bundle.irc_client.say(message.source.login, response->get_single()); } else if (response->is_multiple()) { for (const std::string &msg : response->get_multiple()) { bundle.irc_client.say(message.source.login, msg); } } return; } } catch (const std::exception &e) { bundle.irc_client.say(message.source.login, e.what()); log::error("PrivMsg/" + request->command_id, e.what()); } } db::DatabaseRows channels = conn->exec("SELECT * FROM channels WHERE alias_id = $1", {std::to_string(message.source.id)}); if (!channels.empty()) { schemas::Channel channel(channels[0]); db::DatabaseRows channel_preferences = conn->exec( "SELECT * FROM channel_preferences WHERE " "id = $1", {std::to_string(channel.get_id())}); schemas::ChannelPreferences preference(channel_preferences[0]); db::DatabaseRows cmds = conn->exec( "SELECT message FROM custom_commands WHERE name = $1 AND channel_id " "= $2", {message.message, std::to_string(channel.get_id())}); if (!cmds.empty()) { std::string msg = cmds[0].at("message"); bundle.irc_client.say(message.source.login, msg); } else { make_markov_response(bundle, message, channel, preference); } } conn->close(); } void make_markov_response( const InstanceBundle &bundle, const irc::Message &message, const schemas::Channel &channel, const schemas::ChannelPreferences &preference) { bool are_markov_responses_enabled = std::any_of(preference.get_features().begin(), preference.get_features().end(), [](const int &x) { return (schemas::ChannelFeature)x == schemas::ChannelFeature::MARKOV_RESPONSES; }); if (!are_markov_responses_enabled) return; bool are_random_markov_responses_enabled = std::any_of(preference.get_features().begin(), preference.get_features().end(), [](const int &x) { return (schemas::ChannelFeature)x == schemas::ChannelFeature::RANDOM_MARKOV_RESPONSES; }); std::string prefix = "@" + bundle.irc_client.get_bot_username() + ","; bool intended_call = message.message.substr(0, prefix.length()) == prefix; int random = -1; std::string question; if (are_random_markov_responses_enabled && !intended_call) { std::random_device dev; std::mt19937 rng(dev()); std::uniform_int_distribution dist(0, 100); random = dist(rng); if (random > MARKOV_RESPONSE_CHANCE) return; question = message.message; } else { question = message.message.substr(prefix.length(), message.message.length()); } if (random == -1 && !intended_call) return; cpr::Response response = cpr::Post(cpr::Url{"https://markov.ilotterytea.kz/api/v1/generate"}, cpr::Multipart{{"question", question}, {"max_length", 200}}); if (response.status_code != 200) return; nlohmann::json j = nlohmann::json::parse(response.text); std::string answer; auto answer_field = j["data"]["answer"]; if (answer_field.is_null()) answer = "..."; else answer = answer_field; bundle.irc_client.say(message.source.login, message.sender.login + ": " + answer); } }