diff --git a/CMakeLists.txt b/CMakeLists.txt index 0004b5b..a98d598 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,8 +20,14 @@ FetchContent_Declare( GIT_TAG 1.11.0 GIT_SHALLOW TRUE ) +FetchContent_Declare( + glaze + GIT_REPOSITORY https://github.com/stephenberry/glaze.git + GIT_TAG main + GIT_SHALLOW TRUE +) -FetchContent_MakeAvailable(ctre cpr) +FetchContent_MakeAvailable(ctre cpr glaze) add_executable( nutri @@ -30,6 +36,5 @@ add_executable( src/Helpers/Utility.cpp src/Helpers/Utility.hpp src/Helpers/WolframAlpha.hpp - src/Helpers/WolframAlpha.cpp) - -target_link_libraries(nutri PRIVATE cpr::cpr nlohmann_json::nlohmann_json ctre::ctre) + ) +target_link_libraries(nutri PRIVATE cpr::cpr nlohmann_json::nlohmann_json ctre::ctre glaze::glaze) diff --git a/src/Helpers/WolframAlpha.cpp b/src/Helpers/WolframAlpha.cpp deleted file mode 100644 index b69a482..0000000 --- a/src/Helpers/WolframAlpha.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "WolframAlpha.hpp" - -#include "Utility.hpp" -#include -#include -#include -#include - -WolframAlpha::WolframAlpha(const std::string& query, double amount) : m_json(fetchJson(query)), m_amount(amount) {} - -double WolframAlpha::getCalories() { - if (auto match = ctre::search(getPod())) { - return std::stod(match.data()) * m_amount; - } - throw std::runtime_error("Calorie information not found."); -} - -double WolframAlpha::getProtein() { - auto m = ctre::search<"(?<=protein\\s)(\\d+)\\s*(\\w+)">(getPod()); - double d = m.get<1>().to_number(); - std::string u = m.get<2>().to_string(); - return u == "g" ? d : d / 1000; -} - -double WolframAlpha::getCarbs() { - auto m = ctre::search<"(?<=total carbohydrates\\s)(\\d+)\\s*(\\w+)">(getPod()); - double d = m.get<1>().to_number(); - std::string u = m.get<2>().to_string(); - return u == "g" ? d : d / 1000; -} - -double WolframAlpha::getFat() { - auto m = ctre::search<"(?<=total fat\\s)(\\d+)\\s*(\\w+)">(getPod()); - double d = m.get<1>().to_number(); - std::string u = m.get<2>().to_string(); - return u == "g" ? d : d / 1000; -} - -nlohmann::json WolframAlpha::fetchJson(const std::string& query) { - const auto WOLFRAM_KEY = utl::getEnv("NUTRI_WA_KEY"); - cpr::Response json = Get(cpr::Url{"https://api.wolframalpha.com/v2/query"}, - cpr::Parameters{{"input", query + "100g nutrition"}, {"appid", WOLFRAM_KEY}, {"output", "JSON"}, {"format", "plaintext"}}); - return nlohmann::json::parse(json.text); -} - -std::string WolframAlpha::getPod() { - return to_string(m_json["queryresult"]["pods"][1]["subpods"][0]["plaintext"]); -} - -nlohmann::json m_json{}; -double m_amount{}; diff --git a/src/Helpers/WolframAlpha.hpp b/src/Helpers/WolframAlpha.hpp index 401d3de..d2cf51f 100644 --- a/src/Helpers/WolframAlpha.hpp +++ b/src/Helpers/WolframAlpha.hpp @@ -1,21 +1,80 @@ #pragma once -#include +#include "Utility.hpp" +#include "ctll/fixed_string.hpp" +#include +#include +#include +#include +#include #include +// Example regex patern: (?<=protein\s)(\d+)\s(\w) + +struct Data { + double cals{}; + double proteins{}; + double carbs{}; + double fats{}; +}; + class WolframAlpha { public: - explicit WolframAlpha(const std::string& query, double amount); + WolframAlpha(const std::string& query, double amount) : m_plaintext{getData(query)}, m_amount{amount / 100} {} - double getCalories(); - double getProtein(); - double getCarbs(); - double getFat(); + //debug + std::string getPlain() { + return m_plaintext; + } + + Data getNutrition() { + return m_data; + } private: - nlohmann::json fetchJson(const std::string& query); - std::string getPod(); + void getMacro() { + static constexpr ctll::fixed_string calories_regex{R"((?<=total calories\s)\d+)"}; + static constexpr ctll::fixed_string proteins_regex{R"((?<=protein\s)(\d+)\s(\w))"}; + static constexpr ctll::fixed_string carbs_regex{R"((?<=total carbohydrates\s)(\d+)\s(\w))"}; + static constexpr ctll::fixed_string fats_regex{R"((?<=total fat\s)(\d+)\s(\w))"}; - nlohmann::json m_json{}; - double m_amount{}; + const auto convertToGrams = [this](const auto& match, const std::string& unit) -> double { + const double value = (unit == "g") ? match.to_number() : match.to_number() / 1000; + return value * m_amount; + }; + + if (auto match = ctre::search(m_plaintext); match) { + m_data.proteins = convertToGrams(match.get<1>(), match.get<2>().to_string()); + } + + if (auto match = ctre::search(m_plaintext); match) { + m_data.carbs = convertToGrams(match.get<1>(), match.get<2>().to_string()); + } + + if (auto match = ctre::search(m_plaintext); match) { + m_data.fats = convertToGrams(match.get<1>(), match.get<2>().to_string()); + } + + if (auto match = ctre::search(m_plaintext); match) { + m_data.cals = match.get<0>().to_number(); + } + } + std::string getData(const std::string& query) { + const auto WOLFRAM_KEY = utl::getEnv("NUTRI_WA_KEY"); + cpr::Response response = Get(cpr::Url{"https://api.wolframalpha.com/v2/query"}, + cpr::Parameters{{"input", query + "100g nutrition"}, {"appid", WOLFRAM_KEY}, {"output", "JSON"}, {"format", "plaintext"}}); + + glz::json_t json{}; + // Pretty sure this is wrong and i always is false + if (glz::read_json(json, response.text)) { + throw std::runtime_error("Failed to parse the JSON"); + } else { + return json["queryresult"]["pods"][1]["subpods"][0]["plaintext"].get(); + } + } + + Data m_data{}; + std::string m_pod{}; + std::string m_plaintext{}; + double m_amount{}; }; diff --git a/src/main.cpp b/src/main.cpp index 37f3844..fbf3916 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,13 +1,10 @@ #include "ArgParser.hpp" #include "Helpers/WolframAlpha.hpp" -#include -#include #include int main(const int argc, char* argv[]) { try { ArgParser args; - args.addArg("-s", "--source", "Specify the source of the data (Wolfram|OpenFoodFacts)"); args.addArg("-f", "--food", "Specify the food item"); args.addArg("-a", "--amount", "Specify the amount (in grams)"); args.addArg("-h", "--help", "Print help", false); @@ -16,10 +13,10 @@ int main(const int argc, char* argv[]) { const auto food = args.get("--food"); const double amount = args.get("--amount") / 100; - if (!args.has("--source") || args.get("--source") == "Wolfram") { - WolframAlpha wa(food, amount); - std::println("Calories: {:.2f} kcal\nProtein: {:.2f} g\nCarbs: {:.2f} g\nFat: {:.2f} g", wa.getCalories(), wa.getProtein(), wa.getCarbs(), wa.getFat()); - } + WolframAlpha wa(food, amount); + + auto a = wa.getNutrition(); + std::println("cals: {}\nprotein: {}\ncarbs: {}\nfat: {}", a.cals, a.proteins, a.carbs, a.fats); } catch (const std::exception& e) { std::println(stderr, "Error: {}", e.what());