From abb5d7f43a202e75bf449fbe0489f28238f5c2fb Mon Sep 17 00:00:00 2001 From: Thuandz Date: Thu, 26 Sep 2024 00:46:56 +0700 Subject: [PATCH 1/5] fix/mistral-nemo-chat-template --- engine/config/chat_template_renderer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/config/chat_template_renderer.h b/engine/config/chat_template_renderer.h index f40894f7b..63a47ecf3 100644 --- a/engine/config/chat_template_renderer.h +++ b/engine/config/chat_template_renderer.h @@ -123,7 +123,7 @@ static int32_t llama_chat_apply_template_internal( ss << content << "\n"; } } else if (role == "user") { - ss << content << " [/INST]"; + ss << "[INST] " << content << " [/INST]"; } else { ss << (space_around_response ? " " : "") << content << (space_around_response ? " " : "") << ""; From 8d706ad34ff7af107c86aaf5767892b4c1014910 Mon Sep 17 00:00:00 2001 From: nguyenhoangthuan99 Date: Wed, 2 Oct 2024 08:42:48 +0700 Subject: [PATCH 2/5] Chore: Fix float number not rounded when write to yaml file --- engine/config/yaml_config.cc | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/engine/config/yaml_config.cc b/engine/config/yaml_config.cc index 85f086d46..07e3f996b 100644 --- a/engine/config/yaml_config.cc +++ b/engine/config/yaml_config.cc @@ -276,7 +276,28 @@ void YamlHandler::WriteYamlFile(const std::string& file_path) const { const std::string& comment = "") { if (!value) return; - outFile << key << ": " << value; + outFile << key << ": "; + + // Check if the value is a float and round it to 6 decimal places + if (value.IsScalar()) { + try { + double doubleValue = value.as(); + std::ostringstream oss; + oss << std::fixed << std::setprecision(6) << doubleValue; + std::string strValue = oss.str(); + // Remove trailing zeros after the decimal point + strValue.erase(strValue.find_last_not_of('0') + 1, std::string::npos); + if (strValue.back() == '.') { + strValue.pop_back(); + } + outFile << strValue; + } catch (...) { + outFile << value; // If not a float, write as is + } + } else { + outFile << value; + } + if (!comment.empty()) { outFile << " # " << comment; } @@ -358,9 +379,7 @@ void YamlHandler::WriteYamlFile(const std::string& file_path) const { "llama.context_length | 0 or undefined = loaded from model"); writeKeyValue("ngl", yaml_node_["ngl"], "Undefined = loaded from model"); outFile << "# END OPTIONAL\n"; - outFile << "# END MODEL LOAD PARAMETERS\n"; - - // Write new configuration parameters + outFile << "# END MODEL LOAD PARAMETERS\n"; outFile.close(); } catch (const std::exception& e) { From 087d522a9894cec0e65621132fe6303ff6019257 Mon Sep 17 00:00:00 2001 From: nguyenhoangthuan99 Date: Wed, 2 Oct 2024 08:59:47 +0700 Subject: [PATCH 3/5] Fix: unitest fail when write yaml --- engine/config/model_config.h | 13 ++++++++++--- engine/config/yaml_config.cc | 4 +++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/engine/config/model_config.h b/engine/config/model_config.h index a65114ca7..8ee3b37ff 100644 --- a/engine/config/model_config.h +++ b/engine/config/model_config.h @@ -264,12 +264,19 @@ struct ModelConfig { print_kv(key, value ? "true" : "false", MAGENTA); }; - // Helper function to print float values with fixed precision + // Updated helper function to print float values with fixed precision auto print_float = [&print_kv, &BLUE](const std::string& key, float value) { if (!std::isnan(value)) { std::ostringstream float_oss; - float_oss << std::fixed << std::setprecision(9) << value; - print_kv(key, float_oss.str(), BLUE); + float_oss << std::fixed << std::setprecision(6) << value; + std::string str_value = float_oss.str(); + // Remove trailing zeros + str_value.erase(str_value.find_last_not_of('0') + 1, std::string::npos); + // Remove trailing dot if present + if (str_value.back() == '.') { + str_value.pop_back(); + } + print_kv(key, str_value, BLUE); } }; diff --git a/engine/config/yaml_config.cc b/engine/config/yaml_config.cc index 07e3f996b..4b5c1ee3e 100644 --- a/engine/config/yaml_config.cc +++ b/engine/config/yaml_config.cc @@ -312,7 +312,9 @@ void YamlHandler::WriteYamlFile(const std::string& file_path) const { "Model ID which is used for request construct - should be " "unique between models (author / quantization)"); writeKeyValue("name", yaml_node_["name"], "metadata.general.name"); - writeKeyValue("version", yaml_node_["version"], "metadata.version"); + if(yaml_node_["version"]){ + outFile<<"version: "<()<<"\n"; + } if (yaml_node_["files"] && yaml_node_["files"].size()) { outFile << "files: # can be universal protocol (models://) " "OR absolute local file path (file://) OR https remote URL " From e3f0e5d42df61d6c12ccc350480b455e44823317 Mon Sep 17 00:00:00 2001 From: nguyenhoangthuan99 Date: Wed, 2 Oct 2024 15:35:58 +0700 Subject: [PATCH 4/5] Fix: CI build and add unitest --- engine/config/model_config.h | 155 ++++++++------------ engine/config/yaml_config.cc | 131 ++++++++--------- engine/test/components/test_format_utils.cc | 76 ++++++++++ engine/test/components/test_string_utils.cc | 39 ++++- engine/utils/format_utils.h | 39 ++++- engine/utils/string_utils.h | 46 +++++- 6 files changed, 316 insertions(+), 170 deletions(-) create mode 100644 engine/test/components/test_format_utils.cc diff --git a/engine/config/model_config.h b/engine/config/model_config.h index 8ee3b37ff..f175535ab 100644 --- a/engine/config/model_config.h +++ b/engine/config/model_config.h @@ -7,7 +7,7 @@ #include #include #include - +#include "utils/string_utils.h" namespace config { struct ModelConfig { std::string name; @@ -58,7 +58,7 @@ struct ModelConfig { int n_probs = 0; int min_keep = 0; std::string grammar; - + void FromJson(const Json::Value& json) { // do now allow to update ID and model field because it is unique identifier // if (json.isMember("id")) @@ -236,123 +236,90 @@ struct ModelConfig { std::string ToString() const { std::ostringstream oss; - // Color codes - const std::string RESET = "\033[0m"; - const std::string BOLD = "\033[1m"; - const std::string GREEN = "\033[1;32m"; - const std::string YELLOW = "\033[0;33m"; - const std::string BLUE = "\033[0;34m"; - const std::string MAGENTA = "\033[0;35m"; - const std::string GRAY = "\033[1;90m"; - - // Helper function to print comments - auto print_comment = [&oss, &GRAY, &RESET](const std::string& comment) { - oss << GRAY << "# " << comment << RESET << "\n"; - }; - - // Helper function to print key-value pairs - auto print_kv = [&oss, &GREEN, &RESET]( - const std::string& key, const auto& value, - const std::string& color = "\033[0m") { - oss << GREEN << key << ":" << RESET << " " << color << value << RESET - << "\n"; - }; - - // Helper function to print boolean values - auto print_bool = [&print_kv, &MAGENTA](const std::string& key, - bool value) { - print_kv(key, value ? "true" : "false", MAGENTA); - }; - - // Updated helper function to print float values with fixed precision - auto print_float = [&print_kv, &BLUE](const std::string& key, float value) { - if (!std::isnan(value)) { - std::ostringstream float_oss; - float_oss << std::fixed << std::setprecision(6) << value; - std::string str_value = float_oss.str(); - // Remove trailing zeros - str_value.erase(str_value.find_last_not_of('0') + 1, std::string::npos); - // Remove trailing dot if present - if (str_value.back() == '.') { - str_value.pop_back(); - } - print_kv(key, str_value, BLUE); - } - }; - - print_comment("BEGIN GENERAL GGUF METADATA"); + oss << string_utils::print_comment("BEGIN GENERAL GGUF METADATA"); if (!id.empty()) - print_kv("id", id, YELLOW); + oss << string_utils::print_kv("id", id, string_utils::YELLOW); if (!name.empty()) - print_kv("name", name, YELLOW); + oss << string_utils::print_kv("name", name, string_utils::YELLOW); if (!model.empty()) - print_kv("model", model, YELLOW); + oss << string_utils::print_kv("model", model, string_utils::YELLOW); if (!version.empty()) - print_kv("version", version, YELLOW); + oss << string_utils::print_kv("version", version, string_utils::YELLOW); if (!files.empty()) { - oss << GREEN << "files:" << RESET << "\n"; + oss << string_utils::GREEN << "files:" << string_utils::RESET << "\n"; for (const auto& file : files) { - oss << " - " << YELLOW << file << RESET << "\n"; + oss << " - " << string_utils::YELLOW << file << string_utils::RESET + << "\n"; } } - print_comment("END GENERAL GGUF METADATA"); + oss << string_utils::print_comment("END GENERAL GGUF METADATA"); - print_comment("BEGIN INFERENCE PARAMETERS"); - print_comment("BEGIN REQUIRED"); + oss << string_utils::print_comment("BEGIN INFERENCE PARAMETERS"); + oss << string_utils::print_comment("BEGIN REQUIRED"); if (!stop.empty()) { - oss << GREEN << "stop:" << RESET << "\n"; + oss << string_utils::GREEN << "stop:" << string_utils::RESET << "\n"; for (const auto& s : stop) { - oss << " - " << YELLOW << s << RESET << "\n"; + oss << " - " << string_utils::YELLOW << s << string_utils::RESET + << "\n"; } } - print_comment("END REQUIRED"); - print_comment("BEGIN OPTIONAL"); + oss << string_utils::print_comment("END REQUIRED"); + oss << string_utils::print_comment("BEGIN OPTIONAL"); - print_bool("stream", stream); - print_float("top_p", top_p); - print_float("temperature", temperature); - print_float("frequency_penalty", frequency_penalty); - print_float("presence_penalty", presence_penalty); + oss << string_utils::print_bool("stream", stream); + oss << string_utils::print_float("top_p", top_p); + oss << string_utils::print_float("temperature", temperature); + oss << string_utils::print_float("frequency_penalty", frequency_penalty); + oss << string_utils::print_float("presence_penalty", presence_penalty); if (max_tokens != std::numeric_limits::quiet_NaN()) - print_kv("max_tokens", max_tokens, MAGENTA); + oss << string_utils::print_kv("max_tokens", std::to_string(max_tokens), + string_utils::MAGENTA); if (seed != -1) - print_kv("seed", seed, MAGENTA); - print_float("dynatemp_range", dynatemp_range); - print_float("dynatemp_exponent", dynatemp_exponent); - print_kv("top_k", top_k, MAGENTA); - print_float("min_p", min_p); - print_kv("tfs_z", tfs_z, MAGENTA); - print_float("typ_p", typ_p); - print_kv("repeat_last_n", repeat_last_n, MAGENTA); - print_float("repeat_penalty", repeat_penalty); - print_bool("mirostat", mirostat); - print_float("mirostat_tau", mirostat_tau); - print_float("mirostat_eta", mirostat_eta); - print_bool("penalize_nl", penalize_nl); - print_bool("ignore_eos", ignore_eos); - print_kv("n_probs", n_probs, MAGENTA); - print_kv("min_keep", min_keep, MAGENTA); + oss << string_utils::print_kv("seed", std::to_string(seed), + string_utils::MAGENTA); + oss << string_utils::print_float("dynatemp_range", dynatemp_range); + oss << string_utils::print_float("dynatemp_exponent", dynatemp_exponent); + oss << string_utils::print_kv("top_k", std::to_string(top_k), + string_utils::MAGENTA); + oss << string_utils::print_float("min_p", min_p); + oss << string_utils::print_float("tfs_z", tfs_z); + oss << string_utils::print_float("typ_p", typ_p); + oss << string_utils::print_kv( + "repeat_last_n", std::to_string(repeat_last_n), string_utils::MAGENTA); + oss << string_utils::print_float("repeat_penalty", repeat_penalty); + oss << string_utils::print_bool("mirostat", mirostat); + oss << string_utils::print_float("mirostat_tau", mirostat_tau); + oss << string_utils::print_float("mirostat_eta", mirostat_eta); + oss << string_utils::print_bool("penalize_nl", penalize_nl); + oss << string_utils::print_bool("ignore_eos", ignore_eos); + oss << string_utils::print_kv("n_probs", std::to_string(n_probs), + string_utils::MAGENTA); + oss << string_utils::print_kv("min_keep", std::to_string(min_keep), + string_utils::MAGENTA); - print_comment("END OPTIONAL"); - print_comment("END INFERENCE PARAMETERS"); - print_comment("BEGIN MODEL LOAD PARAMETERS"); - print_comment("BEGIN REQUIRED"); + oss << string_utils::print_comment("END OPTIONAL"); + oss << string_utils::print_comment("END INFERENCE PARAMETERS"); + oss << string_utils::print_comment("BEGIN MODEL LOAD PARAMETERS"); + oss << string_utils::print_comment("BEGIN REQUIRED"); if (!engine.empty()) - print_kv("engine", engine, YELLOW); + oss << string_utils::print_kv("engine", engine, string_utils::YELLOW); if (!prompt_template.empty()) - print_kv("prompt_template", prompt_template, YELLOW); + oss << string_utils::print_kv("prompt_template", prompt_template, + string_utils::YELLOW); - print_comment("END REQUIRED"); - print_comment("BEGIN OPTIONAL"); + oss << string_utils::print_comment("END REQUIRED"); + oss << string_utils::print_comment("BEGIN OPTIONAL"); if (ctx_len != std::numeric_limits::quiet_NaN()) - print_kv("ctx_len", ctx_len, MAGENTA); + oss << string_utils::print_kv("ctx_len", std::to_string(ctx_len), + string_utils::MAGENTA); if (ngl != std::numeric_limits::quiet_NaN()) - print_kv("ngl", ngl, MAGENTA); + oss << string_utils::print_kv("ngl", std::to_string(ngl), + string_utils::MAGENTA); - print_comment("END OPTIONAL"); - print_comment("END MODEL LOAD PARAMETERS"); + oss << string_utils::print_comment("END OPTIONAL"); + oss << string_utils::print_comment("END MODEL LOAD PARAMETERS"); return oss.str(); } diff --git a/engine/config/yaml_config.cc b/engine/config/yaml_config.cc index 4b5c1ee3e..104fa3b5e 100644 --- a/engine/config/yaml_config.cc +++ b/engine/config/yaml_config.cc @@ -5,8 +5,8 @@ #include using namespace std; +#include "utils/format_utils.h" #include "yaml_config.h" - namespace config { // Method to read YAML file void YamlHandler::Reset() { @@ -271,49 +271,19 @@ void YamlHandler::WriteYamlFile(const std::string& file_path) const { if (!outFile) { throw std::runtime_error("Failed to open output file."); } - // Helper function to write a key-value pair with an optional comment - auto writeKeyValue = [&](const std::string& key, const YAML::Node& value, - const std::string& comment = "") { - if (!value) - return; - outFile << key << ": "; - - // Check if the value is a float and round it to 6 decimal places - if (value.IsScalar()) { - try { - double doubleValue = value.as(); - std::ostringstream oss; - oss << std::fixed << std::setprecision(6) << doubleValue; - std::string strValue = oss.str(); - // Remove trailing zeros after the decimal point - strValue.erase(strValue.find_last_not_of('0') + 1, std::string::npos); - if (strValue.back() == '.') { - strValue.pop_back(); - } - outFile << strValue; - } catch (...) { - outFile << value; // If not a float, write as is - } - } else { - outFile << value; - } - - if (!comment.empty()) { - outFile << " # " << comment; - } - outFile << "\n"; - }; - // Write GENERAL GGUF METADATA outFile << "# BEGIN GENERAL GGUF METADATA\n"; - writeKeyValue("id", yaml_node_["id"], - "Model ID unique between models (author / quantization)"); - writeKeyValue("model", yaml_node_["model"], - "Model ID which is used for request construct - should be " - "unique between models (author / quantization)"); - writeKeyValue("name", yaml_node_["name"], "metadata.general.name"); - if(yaml_node_["version"]){ - outFile<<"version: "<()<<"\n"; + outFile << format_utils::writeKeyValue( + "id", yaml_node_["id"], + "Model ID unique between models (author / quantization)"); + outFile << format_utils::writeKeyValue( + "model", yaml_node_["model"], + "Model ID which is used for request construct - should be " + "unique between models (author / quantization)"); + outFile << format_utils::writeKeyValue("name", yaml_node_["name"], + "metadata.general.name"); + if (yaml_node_["version"]) { + outFile << "version: " << yaml_node_["version"].as() << "\n"; } if (yaml_node_["files"] && yaml_node_["files"].size()) { outFile << "files: # can be universal protocol (models://) " @@ -339,49 +309,64 @@ void YamlHandler::WriteYamlFile(const std::string& file_path) const { outFile << "# END REQUIRED\n"; outFile << "\n"; outFile << "# BEGIN OPTIONAL\n"; - writeKeyValue("stream", yaml_node_["stream"], "Default true?"); - writeKeyValue("top_p", yaml_node_["top_p"], "Ranges: 0 to 1"); - writeKeyValue("temperature", yaml_node_["temperature"], "Ranges: 0 to 1"); - writeKeyValue("frequency_penalty", yaml_node_["frequency_penalty"], - "Ranges: 0 to 1"); - writeKeyValue("presence_penalty", yaml_node_["presence_penalty"], - "Ranges: 0 to 1"); - writeKeyValue("max_tokens", yaml_node_["max_tokens"], - "Should be default to context length"); - writeKeyValue("seed", yaml_node_["seed"]); - writeKeyValue("dynatemp_range", yaml_node_["dynatemp_range"]); - writeKeyValue("dynatemp_exponent", yaml_node_["dynatemp_exponent"]); - writeKeyValue("top_k", yaml_node_["top_k"]); - writeKeyValue("min_p", yaml_node_["min_p"]); - writeKeyValue("tfs_z", yaml_node_["tfs_z"]); - writeKeyValue("typ_p", yaml_node_["typ_p"]); - writeKeyValue("repeat_last_n", yaml_node_["repeat_last_n"]); - writeKeyValue("repeat_penalty", yaml_node_["repeat_penalty"]); - writeKeyValue("mirostat", yaml_node_["mirostat"]); - writeKeyValue("mirostat_tau", yaml_node_["mirostat_tau"]); - writeKeyValue("mirostat_eta", yaml_node_["mirostat_eta"]); - writeKeyValue("penalize_nl", yaml_node_["penalize_nl"]); - writeKeyValue("ignore_eos", yaml_node_["ignore_eos"]); - writeKeyValue("n_probs", yaml_node_["n_probs"]); - writeKeyValue("min_keep", yaml_node_["min_keep"]); - writeKeyValue("grammar", yaml_node_["grammar"]); + outFile << format_utils::writeKeyValue("stream", yaml_node_["stream"], + "Default true?"); + outFile << format_utils::writeKeyValue("top_p", yaml_node_["top_p"], + "Ranges: 0 to 1"); + outFile << format_utils::writeKeyValue( + "temperature", yaml_node_["temperature"], "Ranges: 0 to 1"); + outFile << format_utils::writeKeyValue( + "frequency_penalty", yaml_node_["frequency_penalty"], "Ranges: 0 to 1"); + outFile << format_utils::writeKeyValue( + "presence_penalty", yaml_node_["presence_penalty"], "Ranges: 0 to 1"); + outFile << format_utils::writeKeyValue( + "max_tokens", yaml_node_["max_tokens"], + "Should be default to context length"); + outFile << format_utils::writeKeyValue("seed", yaml_node_["seed"]); + outFile << format_utils::writeKeyValue("dynatemp_range", + yaml_node_["dynatemp_range"]); + outFile << format_utils::writeKeyValue("dynatemp_exponent", + yaml_node_["dynatemp_exponent"]); + outFile << format_utils::writeKeyValue("top_k", yaml_node_["top_k"]); + outFile << format_utils::writeKeyValue("min_p", yaml_node_["min_p"]); + outFile << format_utils::writeKeyValue("tfs_z", yaml_node_["tfs_z"]); + outFile << format_utils::writeKeyValue("typ_p", yaml_node_["typ_p"]); + outFile << format_utils::writeKeyValue("repeat_last_n", + yaml_node_["repeat_last_n"]); + outFile << format_utils::writeKeyValue("repeat_penalty", + yaml_node_["repeat_penalty"]); + outFile << format_utils::writeKeyValue("mirostat", yaml_node_["mirostat"]); + outFile << format_utils::writeKeyValue("mirostat_tau", + yaml_node_["mirostat_tau"]); + outFile << format_utils::writeKeyValue("mirostat_eta", + yaml_node_["mirostat_eta"]); + outFile << format_utils::writeKeyValue("penalize_nl", + yaml_node_["penalize_nl"]); + outFile << format_utils::writeKeyValue("ignore_eos", + yaml_node_["ignore_eos"]); + outFile << format_utils::writeKeyValue("n_probs", yaml_node_["n_probs"]); + outFile << format_utils::writeKeyValue("min_keep", yaml_node_["min_keep"]); + outFile << format_utils::writeKeyValue("grammar", yaml_node_["grammar"]); outFile << "# END OPTIONAL\n"; outFile << "# END INFERENCE PARAMETERS\n"; outFile << "\n"; // Write MODEL LOAD PARAMETERS outFile << "# BEGIN MODEL LOAD PARAMETERS\n"; outFile << "# BEGIN REQUIRED\n"; - writeKeyValue("engine", yaml_node_["engine"], "engine to run model"); + outFile << format_utils::writeKeyValue("engine", yaml_node_["engine"], + "engine to run model"); outFile << "prompt_template:"; outFile << " " << yaml_node_["prompt_template"] << "\n"; outFile << "# END REQUIRED\n"; outFile << "\n"; outFile << "# BEGIN OPTIONAL\n"; - writeKeyValue("ctx_len", yaml_node_["ctx_len"], - "llama.context_length | 0 or undefined = loaded from model"); - writeKeyValue("ngl", yaml_node_["ngl"], "Undefined = loaded from model"); + outFile << format_utils::writeKeyValue( + "ctx_len", yaml_node_["ctx_len"], + "llama.context_length | 0 or undefined = loaded from model"); + outFile << format_utils::writeKeyValue("ngl", yaml_node_["ngl"], + "Undefined = loaded from model"); outFile << "# END OPTIONAL\n"; - outFile << "# END MODEL LOAD PARAMETERS\n"; + outFile << "# END MODEL LOAD PARAMETERS\n"; outFile.close(); } catch (const std::exception& e) { diff --git a/engine/test/components/test_format_utils.cc b/engine/test/components/test_format_utils.cc new file mode 100644 index 000000000..ea9bee6a0 --- /dev/null +++ b/engine/test/components/test_format_utils.cc @@ -0,0 +1,76 @@ +#include +#include +#include "gtest/gtest.h" +#include "utils/format_utils.h" + +class FormatUtilsTest : public ::testing::Test {}; + +TEST_F(FormatUtilsTest, WriteKeyValue) { + { + YAML::Node node; + std::string result = format_utils::writeKeyValue("key", node["does_not_exist"]); + EXPECT_EQ(result, ""); + } + + { + YAML::Node node = YAML::Load("value"); + std::string result = format_utils::writeKeyValue("key", node); + EXPECT_EQ(result, "key: value\n"); + } + + { + YAML::Node node = YAML::Load("3.14159"); + std::string result = format_utils::writeKeyValue("key", node); + EXPECT_EQ(result, "key: 3.14159\n"); + } + + { + YAML::Node node = YAML::Load("3.000000"); + std::string result = format_utils::writeKeyValue("key", node); + EXPECT_EQ(result, "key: 3\n"); + } + + { + YAML::Node node = YAML::Load("3.140000"); + std::string result = format_utils::writeKeyValue("key", node); + EXPECT_EQ(result, "key: 3.14\n"); + } + + { + YAML::Node node = YAML::Load("value"); + std::string result = format_utils::writeKeyValue("key", node, "comment"); + EXPECT_EQ(result, "key: value # comment\n"); + } +} + +TEST_F(FormatUtilsTest, BytesToHumanReadable) { + { + uint64_t bytes = 500; + std::string result = format_utils::BytesToHumanReadable(bytes); + EXPECT_EQ(result, "500.00 B"); + } + + { + uint64_t bytes = 1500; + std::string result = format_utils::BytesToHumanReadable(bytes); + EXPECT_EQ(result, "1.46 KB"); + } + + { + uint64_t bytes = 1500000; + std::string result = format_utils::BytesToHumanReadable(bytes); + EXPECT_EQ(result, "1.43 MB"); + } + + { + uint64_t bytes = 1500000000; + std::string result = format_utils::BytesToHumanReadable(bytes); + EXPECT_EQ(result, "1.40 GB"); + } + + { + uint64_t bytes = 1500000000000; + std::string result = format_utils::BytesToHumanReadable(bytes); + EXPECT_EQ(result, "1.36 TB"); + } +} \ No newline at end of file diff --git a/engine/test/components/test_string_utils.cc b/engine/test/components/test_string_utils.cc index 7a51b4f58..3519796f4 100644 --- a/engine/test/components/test_string_utils.cc +++ b/engine/test/components/test_string_utils.cc @@ -1,6 +1,8 @@ +#include +#include #include "gtest/gtest.h" #include "utils/string_utils.h" - +#include "utils/string_utils.h" // Assuming the original code is in this header file class StringUtilsTestSuite : public ::testing::Test {}; TEST_F(StringUtilsTestSuite, TestSplitBy) { @@ -77,3 +79,38 @@ TEST_F(StringUtilsTestSuite, TestEndsWithWithEmptySuffix) { auto suffix = ""; EXPECT_TRUE(string_utils::EndsWith(input, suffix)); } + +TEST_F(StringUtilsTestSuite, PrintComment) { + std::string result = string_utils::print_comment("Test comment"); + EXPECT_EQ(result, "\033[1;90m# Test comment\033[0m\n"); +} + +TEST_F(StringUtilsTestSuite, PrintKV) { + std::string result = string_utils::print_kv("key", "value"); + EXPECT_EQ(result, "\033[1;32mkey:\033[0m \033[0mvalue\033[0m\n"); + + std::string result2 = string_utils::print_kv("key", "value", "\033[0;34m"); + EXPECT_EQ(result2, "\033[1;32mkey:\033[0m \033[0;34mvalue\033[0m\n"); +} + +TEST_F(StringUtilsTestSuite, PrintBool) { + std::string result = string_utils::print_bool("key", true); + EXPECT_EQ(result, "\033[1;32mkey:\033[0m \033[0;35mtrue\033[0m\n"); + + result = string_utils::print_bool("key", false); + EXPECT_EQ(result, "\033[1;32mkey:\033[0m \033[0;35mfalse\033[0m\n"); +} + +TEST_F(StringUtilsTestSuite, PrintFloat) { + std::string result = string_utils::print_float("key", 3.14159f); + EXPECT_EQ(result, "\033[1;32mkey:\033[0m \033[0;34m3.14159\033[0m\n"); + + result = string_utils::print_float("key", 3.000f); + EXPECT_EQ(result, "\033[1;32mkey:\033[0m \033[0;34m3\033[0m\n"); + + result = string_utils::print_float("key", 3.14000f); + EXPECT_EQ(result, "\033[1;32mkey:\033[0m \033[0;34m3.14\033[0m\n"); + + result = string_utils::print_float("key", std::numeric_limits::quiet_NaN()); + EXPECT_EQ(result, ""); +} \ No newline at end of file diff --git a/engine/utils/format_utils.h b/engine/utils/format_utils.h index 7824d138c..1470de345 100644 --- a/engine/utils/format_utils.h +++ b/engine/utils/format_utils.h @@ -1,10 +1,47 @@ #pragma once +#include #include +#include #include #include - namespace format_utils { + +inline std::string writeKeyValue(const std::string& key, + const YAML::Node& value, + const std::string& comment = "") { + std::ostringstream outFile; + if (!value) + return ""; + outFile << key << ": "; + + // Check if the value is a float and round it to 6 decimal places + if (value.IsScalar()) { + try { + double doubleValue = value.as(); + std::ostringstream oss; + oss << std::fixed << std::setprecision(6) << doubleValue; + std::string strValue = oss.str(); + // Remove trailing zeros after the decimal point + strValue.erase(strValue.find_last_not_of('0') + 1, std::string::npos); + if (strValue.back() == '.') { + strValue.pop_back(); + } + outFile << strValue; + } catch (const std::exception& e) { + outFile << value; // If not a float, write as is + } + } else { + outFile << value; + } + + if (!comment.empty()) { + outFile << " # " << comment; + } + outFile << "\n"; + return outFile.str(); +}; + inline std::string BytesToHumanReadable(uint64_t bytes) { const uint64_t KB = 1024; const uint64_t MB = KB * 1024; diff --git a/engine/utils/string_utils.h b/engine/utils/string_utils.h index 8da860631..a53e417b4 100644 --- a/engine/utils/string_utils.h +++ b/engine/utils/string_utils.h @@ -1,9 +1,53 @@ +#pragma once #include +#include +#include +#include #include #include +#include #include - namespace string_utils { +constexpr char RESET[] = "\033[0m"; +constexpr char BOLD[] = "\033[1m"; +constexpr char GREEN[] = "\033[1;32m"; +constexpr char YELLOW[] = "\033[0;33m"; +constexpr char BLUE[] = "\033[0;34m"; +constexpr char MAGENTA[] = "\033[0;35m"; +constexpr char GRAY[] = "\033[1;90m"; + +inline std::string print_comment(const std::string& comment) { + std::ostringstream oss; + oss << GRAY << "# " << comment << RESET << "\n"; + return oss.str(); +}; + +inline std::string print_kv(const std::string& key, const std::string& value, + const std::string& color = "\033[0m") { + std::ostringstream oss; + oss << GREEN << key << ":" << RESET << " " << color << value << RESET << "\n"; + return oss.str(); +}; + +inline std::string print_bool(const std::string& key, bool value) { + return print_kv(key, value ? "true" : "false", MAGENTA); +}; + +inline std::string print_float(const std::string& key, float value) { + if (!std::isnan(value)) { + std::ostringstream float_oss; + float_oss << std::fixed << std::setprecision(6) << value; + std::string str_value = float_oss.str(); + // Remove trailing zeros + str_value.erase(str_value.find_last_not_of('0') + 1, std::string::npos); + // Remove trailing dot if present + if (str_value.back() == '.') { + str_value.pop_back(); + } + return print_kv(key, str_value, BLUE); + } else + return ""; +}; inline bool StartsWith(const std::string& str, const std::string& prefix) { return str.rfind(prefix, 0) == 0; } From 132bd845aede3bef7c785614e3bcd37914461c79 Mon Sep 17 00:00:00 2001 From: nguyenhoangthuan99 Date: Wed, 2 Oct 2024 15:58:30 +0700 Subject: [PATCH 5/5] chore: move to format utils --- engine/config/model_config.h | 116 ++++++++++---------- engine/test/components/test_format_utils.cc | 36 ++++++ engine/test/components/test_string_utils.cc | 36 ------ engine/utils/format_utils.h | 39 +++++++ engine/utils/string_utils.h | 39 ------- 5 files changed, 133 insertions(+), 133 deletions(-) diff --git a/engine/config/model_config.h b/engine/config/model_config.h index f175535ab..9a97276a3 100644 --- a/engine/config/model_config.h +++ b/engine/config/model_config.h @@ -7,7 +7,7 @@ #include #include #include -#include "utils/string_utils.h" +#include "utils/format_utils.h" namespace config { struct ModelConfig { std::string name; @@ -236,90 +236,90 @@ struct ModelConfig { std::string ToString() const { std::ostringstream oss; - oss << string_utils::print_comment("BEGIN GENERAL GGUF METADATA"); + oss << format_utils::print_comment("BEGIN GENERAL GGUF METADATA"); if (!id.empty()) - oss << string_utils::print_kv("id", id, string_utils::YELLOW); + oss << format_utils::print_kv("id", id, format_utils::YELLOW); if (!name.empty()) - oss << string_utils::print_kv("name", name, string_utils::YELLOW); + oss << format_utils::print_kv("name", name, format_utils::YELLOW); if (!model.empty()) - oss << string_utils::print_kv("model", model, string_utils::YELLOW); + oss << format_utils::print_kv("model", model, format_utils::YELLOW); if (!version.empty()) - oss << string_utils::print_kv("version", version, string_utils::YELLOW); + oss << format_utils::print_kv("version", version, format_utils::YELLOW); if (!files.empty()) { - oss << string_utils::GREEN << "files:" << string_utils::RESET << "\n"; + oss << format_utils::GREEN << "files:" << format_utils::RESET << "\n"; for (const auto& file : files) { - oss << " - " << string_utils::YELLOW << file << string_utils::RESET + oss << " - " << format_utils::YELLOW << file << format_utils::RESET << "\n"; } } - oss << string_utils::print_comment("END GENERAL GGUF METADATA"); + oss << format_utils::print_comment("END GENERAL GGUF METADATA"); - oss << string_utils::print_comment("BEGIN INFERENCE PARAMETERS"); - oss << string_utils::print_comment("BEGIN REQUIRED"); + oss << format_utils::print_comment("BEGIN INFERENCE PARAMETERS"); + oss << format_utils::print_comment("BEGIN REQUIRED"); if (!stop.empty()) { - oss << string_utils::GREEN << "stop:" << string_utils::RESET << "\n"; + oss << format_utils::GREEN << "stop:" << format_utils::RESET << "\n"; for (const auto& s : stop) { - oss << " - " << string_utils::YELLOW << s << string_utils::RESET + oss << " - " << format_utils::YELLOW << s << format_utils::RESET << "\n"; } } - oss << string_utils::print_comment("END REQUIRED"); - oss << string_utils::print_comment("BEGIN OPTIONAL"); + oss << format_utils::print_comment("END REQUIRED"); + oss << format_utils::print_comment("BEGIN OPTIONAL"); - oss << string_utils::print_bool("stream", stream); - oss << string_utils::print_float("top_p", top_p); - oss << string_utils::print_float("temperature", temperature); - oss << string_utils::print_float("frequency_penalty", frequency_penalty); - oss << string_utils::print_float("presence_penalty", presence_penalty); + oss << format_utils::print_bool("stream", stream); + oss << format_utils::print_float("top_p", top_p); + oss << format_utils::print_float("temperature", temperature); + oss << format_utils::print_float("frequency_penalty", frequency_penalty); + oss << format_utils::print_float("presence_penalty", presence_penalty); if (max_tokens != std::numeric_limits::quiet_NaN()) - oss << string_utils::print_kv("max_tokens", std::to_string(max_tokens), - string_utils::MAGENTA); + oss << format_utils::print_kv("max_tokens", std::to_string(max_tokens), + format_utils::MAGENTA); if (seed != -1) - oss << string_utils::print_kv("seed", std::to_string(seed), - string_utils::MAGENTA); - oss << string_utils::print_float("dynatemp_range", dynatemp_range); - oss << string_utils::print_float("dynatemp_exponent", dynatemp_exponent); - oss << string_utils::print_kv("top_k", std::to_string(top_k), - string_utils::MAGENTA); - oss << string_utils::print_float("min_p", min_p); - oss << string_utils::print_float("tfs_z", tfs_z); - oss << string_utils::print_float("typ_p", typ_p); - oss << string_utils::print_kv( - "repeat_last_n", std::to_string(repeat_last_n), string_utils::MAGENTA); - oss << string_utils::print_float("repeat_penalty", repeat_penalty); - oss << string_utils::print_bool("mirostat", mirostat); - oss << string_utils::print_float("mirostat_tau", mirostat_tau); - oss << string_utils::print_float("mirostat_eta", mirostat_eta); - oss << string_utils::print_bool("penalize_nl", penalize_nl); - oss << string_utils::print_bool("ignore_eos", ignore_eos); - oss << string_utils::print_kv("n_probs", std::to_string(n_probs), - string_utils::MAGENTA); - oss << string_utils::print_kv("min_keep", std::to_string(min_keep), - string_utils::MAGENTA); + oss << format_utils::print_kv("seed", std::to_string(seed), + format_utils::MAGENTA); + oss << format_utils::print_float("dynatemp_range", dynatemp_range); + oss << format_utils::print_float("dynatemp_exponent", dynatemp_exponent); + oss << format_utils::print_kv("top_k", std::to_string(top_k), + format_utils::MAGENTA); + oss << format_utils::print_float("min_p", min_p); + oss << format_utils::print_float("tfs_z", tfs_z); + oss << format_utils::print_float("typ_p", typ_p); + oss << format_utils::print_kv( + "repeat_last_n", std::to_string(repeat_last_n), format_utils::MAGENTA); + oss << format_utils::print_float("repeat_penalty", repeat_penalty); + oss << format_utils::print_bool("mirostat", mirostat); + oss << format_utils::print_float("mirostat_tau", mirostat_tau); + oss << format_utils::print_float("mirostat_eta", mirostat_eta); + oss << format_utils::print_bool("penalize_nl", penalize_nl); + oss << format_utils::print_bool("ignore_eos", ignore_eos); + oss << format_utils::print_kv("n_probs", std::to_string(n_probs), + format_utils::MAGENTA); + oss << format_utils::print_kv("min_keep", std::to_string(min_keep), + format_utils::MAGENTA); - oss << string_utils::print_comment("END OPTIONAL"); - oss << string_utils::print_comment("END INFERENCE PARAMETERS"); - oss << string_utils::print_comment("BEGIN MODEL LOAD PARAMETERS"); - oss << string_utils::print_comment("BEGIN REQUIRED"); + oss << format_utils::print_comment("END OPTIONAL"); + oss << format_utils::print_comment("END INFERENCE PARAMETERS"); + oss << format_utils::print_comment("BEGIN MODEL LOAD PARAMETERS"); + oss << format_utils::print_comment("BEGIN REQUIRED"); if (!engine.empty()) - oss << string_utils::print_kv("engine", engine, string_utils::YELLOW); + oss << format_utils::print_kv("engine", engine, format_utils::YELLOW); if (!prompt_template.empty()) - oss << string_utils::print_kv("prompt_template", prompt_template, - string_utils::YELLOW); + oss << format_utils::print_kv("prompt_template", prompt_template, + format_utils::YELLOW); - oss << string_utils::print_comment("END REQUIRED"); - oss << string_utils::print_comment("BEGIN OPTIONAL"); + oss << format_utils::print_comment("END REQUIRED"); + oss << format_utils::print_comment("BEGIN OPTIONAL"); if (ctx_len != std::numeric_limits::quiet_NaN()) - oss << string_utils::print_kv("ctx_len", std::to_string(ctx_len), - string_utils::MAGENTA); + oss << format_utils::print_kv("ctx_len", std::to_string(ctx_len), + format_utils::MAGENTA); if (ngl != std::numeric_limits::quiet_NaN()) - oss << string_utils::print_kv("ngl", std::to_string(ngl), - string_utils::MAGENTA); + oss << format_utils::print_kv("ngl", std::to_string(ngl), + format_utils::MAGENTA); - oss << string_utils::print_comment("END OPTIONAL"); - oss << string_utils::print_comment("END MODEL LOAD PARAMETERS"); + oss << format_utils::print_comment("END OPTIONAL"); + oss << format_utils::print_comment("END MODEL LOAD PARAMETERS"); return oss.str(); } diff --git a/engine/test/components/test_format_utils.cc b/engine/test/components/test_format_utils.cc index ea9bee6a0..4042b4e65 100644 --- a/engine/test/components/test_format_utils.cc +++ b/engine/test/components/test_format_utils.cc @@ -73,4 +73,40 @@ TEST_F(FormatUtilsTest, BytesToHumanReadable) { std::string result = format_utils::BytesToHumanReadable(bytes); EXPECT_EQ(result, "1.36 TB"); } +} + +TEST_F(FormatUtilsTest, PrintComment) { + std::string result = format_utils::print_comment("Test comment"); + EXPECT_EQ(result, "\033[1;90m# Test comment\033[0m\n"); +} + +TEST_F(FormatUtilsTest, PrintKV) { + std::string result = format_utils::print_kv("key", "value"); + EXPECT_EQ(result, "\033[1;32mkey:\033[0m \033[0mvalue\033[0m\n"); + + std::string result2 = format_utils::print_kv("key", "value", "\033[0;34m"); + EXPECT_EQ(result2, "\033[1;32mkey:\033[0m \033[0;34mvalue\033[0m\n"); +} + +TEST_F(FormatUtilsTest, PrintBool) { + std::string result = format_utils::print_bool("key", true); + EXPECT_EQ(result, "\033[1;32mkey:\033[0m \033[0;35mtrue\033[0m\n"); + + result = format_utils::print_bool("key", false); + EXPECT_EQ(result, "\033[1;32mkey:\033[0m \033[0;35mfalse\033[0m\n"); +} + +TEST_F(FormatUtilsTest, PrintFloat) { + std::string result = format_utils::print_float("key", 3.14159f); + EXPECT_EQ(result, "\033[1;32mkey:\033[0m \033[0;34m3.14159\033[0m\n"); + + result = format_utils::print_float("key", 3.000f); + EXPECT_EQ(result, "\033[1;32mkey:\033[0m \033[0;34m3\033[0m\n"); + + result = format_utils::print_float("key", 3.14000f); + EXPECT_EQ(result, "\033[1;32mkey:\033[0m \033[0;34m3.14\033[0m\n"); + + result = + format_utils::print_float("key", std::numeric_limits::quiet_NaN()); + EXPECT_EQ(result, ""); } \ No newline at end of file diff --git a/engine/test/components/test_string_utils.cc b/engine/test/components/test_string_utils.cc index 3519796f4..a4f484e36 100644 --- a/engine/test/components/test_string_utils.cc +++ b/engine/test/components/test_string_utils.cc @@ -2,7 +2,6 @@ #include #include "gtest/gtest.h" #include "utils/string_utils.h" -#include "utils/string_utils.h" // Assuming the original code is in this header file class StringUtilsTestSuite : public ::testing::Test {}; TEST_F(StringUtilsTestSuite, TestSplitBy) { @@ -79,38 +78,3 @@ TEST_F(StringUtilsTestSuite, TestEndsWithWithEmptySuffix) { auto suffix = ""; EXPECT_TRUE(string_utils::EndsWith(input, suffix)); } - -TEST_F(StringUtilsTestSuite, PrintComment) { - std::string result = string_utils::print_comment("Test comment"); - EXPECT_EQ(result, "\033[1;90m# Test comment\033[0m\n"); -} - -TEST_F(StringUtilsTestSuite, PrintKV) { - std::string result = string_utils::print_kv("key", "value"); - EXPECT_EQ(result, "\033[1;32mkey:\033[0m \033[0mvalue\033[0m\n"); - - std::string result2 = string_utils::print_kv("key", "value", "\033[0;34m"); - EXPECT_EQ(result2, "\033[1;32mkey:\033[0m \033[0;34mvalue\033[0m\n"); -} - -TEST_F(StringUtilsTestSuite, PrintBool) { - std::string result = string_utils::print_bool("key", true); - EXPECT_EQ(result, "\033[1;32mkey:\033[0m \033[0;35mtrue\033[0m\n"); - - result = string_utils::print_bool("key", false); - EXPECT_EQ(result, "\033[1;32mkey:\033[0m \033[0;35mfalse\033[0m\n"); -} - -TEST_F(StringUtilsTestSuite, PrintFloat) { - std::string result = string_utils::print_float("key", 3.14159f); - EXPECT_EQ(result, "\033[1;32mkey:\033[0m \033[0;34m3.14159\033[0m\n"); - - result = string_utils::print_float("key", 3.000f); - EXPECT_EQ(result, "\033[1;32mkey:\033[0m \033[0;34m3\033[0m\n"); - - result = string_utils::print_float("key", 3.14000f); - EXPECT_EQ(result, "\033[1;32mkey:\033[0m \033[0;34m3.14\033[0m\n"); - - result = string_utils::print_float("key", std::numeric_limits::quiet_NaN()); - EXPECT_EQ(result, ""); -} \ No newline at end of file diff --git a/engine/utils/format_utils.h b/engine/utils/format_utils.h index 1470de345..38ab1b3fb 100644 --- a/engine/utils/format_utils.h +++ b/engine/utils/format_utils.h @@ -6,7 +6,46 @@ #include #include namespace format_utils { +constexpr char RESET[] = "\033[0m"; +constexpr char BOLD[] = "\033[1m"; +constexpr char GREEN[] = "\033[1;32m"; +constexpr char YELLOW[] = "\033[0;33m"; +constexpr char BLUE[] = "\033[0;34m"; +constexpr char MAGENTA[] = "\033[0;35m"; +constexpr char GRAY[] = "\033[1;90m"; +inline std::string print_comment(const std::string& comment) { + std::ostringstream oss; + oss << GRAY << "# " << comment << RESET << "\n"; + return oss.str(); +}; + +inline std::string print_kv(const std::string& key, const std::string& value, + const std::string& color = "\033[0m") { + std::ostringstream oss; + oss << GREEN << key << ":" << RESET << " " << color << value << RESET << "\n"; + return oss.str(); +}; + +inline std::string print_bool(const std::string& key, bool value) { + return print_kv(key, value ? "true" : "false", MAGENTA); +}; + +inline std::string print_float(const std::string& key, float value) { + if (!std::isnan(value)) { + std::ostringstream float_oss; + float_oss << std::fixed << std::setprecision(6) << value; + std::string str_value = float_oss.str(); + // Remove trailing zeros + str_value.erase(str_value.find_last_not_of('0') + 1, std::string::npos); + // Remove trailing dot if present + if (str_value.back() == '.') { + str_value.pop_back(); + } + return print_kv(key, str_value, BLUE); + } else + return ""; +}; inline std::string writeKeyValue(const std::string& key, const YAML::Node& value, const std::string& comment = "") { diff --git a/engine/utils/string_utils.h b/engine/utils/string_utils.h index a53e417b4..2bb005fc9 100644 --- a/engine/utils/string_utils.h +++ b/engine/utils/string_utils.h @@ -8,46 +8,7 @@ #include #include namespace string_utils { -constexpr char RESET[] = "\033[0m"; -constexpr char BOLD[] = "\033[1m"; -constexpr char GREEN[] = "\033[1;32m"; -constexpr char YELLOW[] = "\033[0;33m"; -constexpr char BLUE[] = "\033[0;34m"; -constexpr char MAGENTA[] = "\033[0;35m"; -constexpr char GRAY[] = "\033[1;90m"; -inline std::string print_comment(const std::string& comment) { - std::ostringstream oss; - oss << GRAY << "# " << comment << RESET << "\n"; - return oss.str(); -}; - -inline std::string print_kv(const std::string& key, const std::string& value, - const std::string& color = "\033[0m") { - std::ostringstream oss; - oss << GREEN << key << ":" << RESET << " " << color << value << RESET << "\n"; - return oss.str(); -}; - -inline std::string print_bool(const std::string& key, bool value) { - return print_kv(key, value ? "true" : "false", MAGENTA); -}; - -inline std::string print_float(const std::string& key, float value) { - if (!std::isnan(value)) { - std::ostringstream float_oss; - float_oss << std::fixed << std::setprecision(6) << value; - std::string str_value = float_oss.str(); - // Remove trailing zeros - str_value.erase(str_value.find_last_not_of('0') + 1, std::string::npos); - // Remove trailing dot if present - if (str_value.back() == '.') { - str_value.pop_back(); - } - return print_kv(key, str_value, BLUE); - } else - return ""; -}; inline bool StartsWith(const std::string& str, const std::string& prefix) { return str.rfind(prefix, 0) == 0; }