From 8701b58276ef7b5e41fb44caf4c2b2f5a1e72951 Mon Sep 17 00:00:00 2001 From: MaggotHATE Date: Wed, 6 Dec 2023 17:13:13 +0500 Subject: [PATCH 1/9] Json integration into common (parameters parsing) --- common/common.cpp | 68 ++++++++++++++++++++++++++++++++++++++++++++--- common/common.h | 4 +++ 2 files changed, 69 insertions(+), 3 deletions(-) diff --git a/common/common.cpp b/common/common.cpp index 4e823c526..99319471f 100644 --- a/common/common.cpp +++ b/common/common.cpp @@ -115,19 +115,81 @@ void process_escapes(std::string& input) { input.resize(output_idx); } +nlohmann::json get_json(std::string file_name) { + // safeguard since we expose this fucntion in header + if (file_name.find(".json") == file_name.npos) file_name += ".json"; + nlohmann::json config; + std::fstream jstream(file_name); + if (jstream.is_open()) { + try { + config = nlohmann::json::parse(jstream); + jstream.close(); + printf("Opened a json file %s\n", file_name.c_str()); + } + catch (nlohmann::json::parse_error& ex) { + jstream.close(); + fprintf(stderr, "%s\n", ex.what()); + return config; + } + } else { + printf("%s not found!\n", file_name.c_str()); + } + + return config; +} + bool gpt_params_parse(int argc, char ** argv, gpt_params & params) { bool result = true; + std::vector arguments_w_json; + arguments_w_json.push_back(argv[0]); + int pos = 1; + + if (argc > 1) { + std::string json_name = argv[1]; + // console arguments should override json values, so json processing goes first + // to avoid exta work, let's expect at least an extention + if (json_name.rfind(".json") != json_name.npos) { + nlohmann::json file_config = get_json(argv[1]); + // avoid putting file name in arguments + pos = 2; + for (auto& p : file_config.items()) { + // only use strings, numbers and booleans for switches + if (p.value().is_string() || p.value().is_number() || p.value().is_boolean()) { + char* key = new char[p.key().length() + 1]; + strcpy(key, p.key().c_str()); + arguments_w_json.push_back(key); + std::string param_value; + if (!p.value().is_boolean()){ + if (p.value().is_string()) param_value = p.value().get(); + else if (p.value().is_number()) param_value = std::to_string(p.value().get()); + + char* val = new char[param_value.length() + 1]; + strcpy(val, param_value.c_str()); + arguments_w_json.push_back(val); + } + } + } + } + for (int i = pos; i < argc; i++) { + arguments_w_json.push_back(argv[i]); + } + } + + int argc_json = arguments_w_json.size(); + char** argv_json = &arguments_w_json[0]; + try { - if (!gpt_params_parse_ex(argc, argv, params)) { - gpt_print_usage(argc, argv, gpt_params()); + if (!gpt_params_parse_ex(argc_json, argv_json, params)) { + gpt_print_usage(argc_json, argv_json, gpt_params()); exit(0); } } catch (const std::invalid_argument & ex) { fprintf(stderr, "%s\n", ex.what()); - gpt_print_usage(argc, argv, gpt_params()); + gpt_print_usage(argc_json, argv_json, gpt_params()); exit(1); } + return result; } diff --git a/common/common.h b/common/common.h index 024679380..5bb0db407 100644 --- a/common/common.h +++ b/common/common.h @@ -6,6 +6,8 @@ #include "sampling.h" +#include "examples/server/json.hpp" + #define LOG_NO_FILE_LINE_FUNCTION #include "log.h" @@ -131,6 +133,8 @@ struct gpt_params { std::string image = ""; // path to an image file }; +nlohmann::json get_json(std::string file_name); + bool gpt_params_parse_ex(int argc, char ** argv, gpt_params & params); bool gpt_params_parse(int argc, char ** argv, gpt_params & params); From 96b6806e1cff35c556597a31dcff72c86262bb80 Mon Sep 17 00:00:00 2001 From: MaggotHATE Date: Wed, 6 Dec 2023 17:56:28 +0500 Subject: [PATCH 2/9] Design and style fixes, better to not decide for users --- common/common.cpp | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/common/common.cpp b/common/common.cpp index 99319471f..95c10e5d1 100644 --- a/common/common.cpp +++ b/common/common.cpp @@ -116,8 +116,6 @@ void process_escapes(std::string& input) { } nlohmann::json get_json(std::string file_name) { - // safeguard since we expose this fucntion in header - if (file_name.find(".json") == file_name.npos) file_name += ".json"; nlohmann::json config; std::fstream jstream(file_name); if (jstream.is_open()) { @@ -143,15 +141,14 @@ bool gpt_params_parse(int argc, char ** argv, gpt_params & params) { std::vector arguments_w_json; arguments_w_json.push_back(argv[0]); int pos = 1; - + // only the second argument to reduce reading attempts (plus drag'n'drop) if (argc > 1) { - std::string json_name = argv[1]; // console arguments should override json values, so json processing goes first - // to avoid exta work, let's expect at least an extention - if (json_name.rfind(".json") != json_name.npos) { - nlohmann::json file_config = get_json(argv[1]); - // avoid putting file name in arguments - pos = 2; + std::string json_name = argv[1]; + nlohmann::json file_config = get_json(argv[1]); + pos = 2; // avoid putting file name into arguments + if (!file_config.empty()) { + for (auto& p : file_config.items()) { // only use strings, numbers and booleans for switches if (p.value().is_string() || p.value().is_number() || p.value().is_boolean()) { @@ -159,10 +156,14 @@ bool gpt_params_parse(int argc, char ** argv, gpt_params & params) { strcpy(key, p.key().c_str()); arguments_w_json.push_back(key); std::string param_value; - if (!p.value().is_boolean()){ - if (p.value().is_string()) param_value = p.value().get(); - else if (p.value().is_number()) param_value = std::to_string(p.value().get()); - + + if (!p.value().is_boolean()) { + if (p.value().is_string()) { + param_value = p.value().get(); + } else if (p.value().is_number()) { + param_value = std::to_string(p.value().get()); // nlohmann::json can't just get numbers as strings, float works fine for int values + } + char* val = new char[param_value.length() + 1]; strcpy(val, param_value.c_str()); arguments_w_json.push_back(val); @@ -170,12 +171,13 @@ bool gpt_params_parse(int argc, char ** argv, gpt_params & params) { } } } + for (int i = pos; i < argc; i++) { arguments_w_json.push_back(argv[i]); } } - int argc_json = arguments_w_json.size(); + int argc_json = arguments_w_json.size(); char** argv_json = &arguments_w_json[0]; try { From 872d004b642aaa29e01fc6ed9897d023af6305d6 Mon Sep 17 00:00:00 2001 From: MaggotHATE Date: Wed, 6 Dec 2023 18:41:25 +0500 Subject: [PATCH 3/9] Simplified file reading, fixed an oversight --- common/common.cpp | 28 ++++++++++------------------ common/common.h | 2 +- 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/common/common.cpp b/common/common.cpp index 95c10e5d1..72600f9b0 100644 --- a/common/common.cpp +++ b/common/common.cpp @@ -115,25 +115,17 @@ void process_escapes(std::string& input) { input.resize(output_idx); } -nlohmann::json get_json(std::string file_name) { - nlohmann::json config; - std::fstream jstream(file_name); - if (jstream.is_open()) { - try { - config = nlohmann::json::parse(jstream); - jstream.close(); - printf("Opened a json file %s\n", file_name.c_str()); - } - catch (nlohmann::json::parse_error& ex) { - jstream.close(); - fprintf(stderr, "%s\n", ex.what()); - return config; - } - } else { - printf("%s not found!\n", file_name.c_str()); +nlohmann::json get_json(std::string& file_name) noexcept { + try { + printf("Opening a json file %s\n", file_name.c_str()); + std::ifstream jstream(file_name); + return nlohmann::json::parse(jstream); + } + catch (const std::exception& ex) { + fprintf(stderr, "%s\n", ex.what()); } - return config; + return {}; } bool gpt_params_parse(int argc, char ** argv, gpt_params & params) { @@ -145,7 +137,7 @@ bool gpt_params_parse(int argc, char ** argv, gpt_params & params) { if (argc > 1) { // console arguments should override json values, so json processing goes first std::string json_name = argv[1]; - nlohmann::json file_config = get_json(argv[1]); + nlohmann::json file_config = get_json(json_name); pos = 2; // avoid putting file name into arguments if (!file_config.empty()) { diff --git a/common/common.h b/common/common.h index 5bb0db407..5327bf5e7 100644 --- a/common/common.h +++ b/common/common.h @@ -133,7 +133,7 @@ struct gpt_params { std::string image = ""; // path to an image file }; -nlohmann::json get_json(std::string file_name); +nlohmann::json get_json(std::string& file_name) noexcept; bool gpt_params_parse_ex(int argc, char ** argv, gpt_params & params); From e798e30cf23252236e1955ab81f4b21cdd8b0e32 Mon Sep 17 00:00:00 2001 From: MaggotHATE Date: Wed, 6 Dec 2023 19:06:58 +0500 Subject: [PATCH 4/9] Simplify reading --- common/common.cpp | 7 +++---- common/common.h | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/common/common.cpp b/common/common.cpp index 72600f9b0..bfb42da87 100644 --- a/common/common.cpp +++ b/common/common.cpp @@ -115,9 +115,9 @@ void process_escapes(std::string& input) { input.resize(output_idx); } -nlohmann::json get_json(std::string& file_name) noexcept { +nlohmann::json get_json(const char* file_name) noexcept { try { - printf("Opening a json file %s\n", file_name.c_str()); + printf("Opening a json file %s\n", file_name); std::ifstream jstream(file_name); return nlohmann::json::parse(jstream); } @@ -136,8 +136,7 @@ bool gpt_params_parse(int argc, char ** argv, gpt_params & params) { // only the second argument to reduce reading attempts (plus drag'n'drop) if (argc > 1) { // console arguments should override json values, so json processing goes first - std::string json_name = argv[1]; - nlohmann::json file_config = get_json(json_name); + nlohmann::json file_config = get_json(argv[1]); pos = 2; // avoid putting file name into arguments if (!file_config.empty()) { diff --git a/common/common.h b/common/common.h index 5327bf5e7..50026cd09 100644 --- a/common/common.h +++ b/common/common.h @@ -133,7 +133,7 @@ struct gpt_params { std::string image = ""; // path to an image file }; -nlohmann::json get_json(std::string& file_name) noexcept; +nlohmann::json get_json(const char* file_name) noexcept; bool gpt_params_parse_ex(int argc, char ** argv, gpt_params & params); From 6f3fb01ffbfcb448cb7b0ab442d2246f0467a327 Mon Sep 17 00:00:00 2001 From: MaggotHATE Date: Wed, 6 Dec 2023 22:37:24 +0500 Subject: [PATCH 5/9] Fixes and clearing memory --- common/common.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/common/common.cpp b/common/common.cpp index bfb42da87..e1946e276 100644 --- a/common/common.cpp +++ b/common/common.cpp @@ -146,9 +146,9 @@ bool gpt_params_parse(int argc, char ** argv, gpt_params & params) { char* key = new char[p.key().length() + 1]; strcpy(key, p.key().c_str()); arguments_w_json.push_back(key); - std::string param_value; if (!p.value().is_boolean()) { + std::string param_value; if (p.value().is_string()) { param_value = p.value().get(); } else if (p.value().is_number()) { @@ -182,6 +182,10 @@ bool gpt_params_parse(int argc, char ** argv, gpt_params & params) { gpt_print_usage(argc_json, argv_json, gpt_params()); exit(1); } + // clearing pointers + for (auto c : arguments_w_json) { + delete [] c; + } return result; } From 549050ad95d3d5f6f60ad9659da66c19cae558b1 Mon Sep 17 00:00:00 2001 From: MaggotHATE Date: Thu, 7 Dec 2023 17:44:39 +0500 Subject: [PATCH 6/9] Reworked into separate functions and a commandline, wip --- common/common.cpp | 165 +++++++++++++++++++++++++++++++++++----------- common/common.h | 8 +++ 2 files changed, 134 insertions(+), 39 deletions(-) diff --git a/common/common.cpp b/common/common.cpp index 03f35de16..6aac39aad 100644 --- a/common/common.cpp +++ b/common/common.cpp @@ -128,64 +128,148 @@ nlohmann::json get_json(const char* file_name) noexcept { return {}; } -bool gpt_params_parse(int argc, char ** argv, gpt_params & params) { - bool result = true; +std::vector args_parse_json_only(char* file_name) { std::vector arguments_w_json; - arguments_w_json.push_back(argv[0]); - int pos = 1; - // only the second argument to reduce reading attempts (plus drag'n'drop) - if (argc > 1) { - // console arguments should override json values, so json processing goes first - nlohmann::json file_config = get_json(argv[1]); - pos = 2; // avoid putting file name into arguments - if (!file_config.empty()) { + nlohmann::json file_config = get_json(file_name); + if (!file_config.empty()) { // ensures no unnecessary work + arguments_w_json.push_back(file_name); - for (auto& p : file_config.items()) { - // only use strings, numbers and booleans for switches - if (p.value().is_string() || p.value().is_number() || p.value().is_boolean()) { - char* key = new char[p.key().length() + 1]; - strcpy(key, p.key().c_str()); - arguments_w_json.push_back(key); + for (auto& p : file_config.items()) { + // only use strings, numbers and booleans for switches + if (p.value().is_string() || p.value().is_number() || p.value().is_boolean()) { + char* key = new char[p.key().length() + 1]; + strcpy(key, p.key().c_str()); + arguments_w_json.push_back(key); - if (!p.value().is_boolean()) { - std::string param_value; - if (p.value().is_string()) { - param_value = p.value().get(); - } else if (p.value().is_number()) { - param_value = std::to_string(p.value().get()); // nlohmann::json can't just get numbers as strings, float works fine for int values - } - - char* val = new char[param_value.length() + 1]; - strcpy(val, param_value.c_str()); - arguments_w_json.push_back(val); + if (!p.value().is_boolean()) { + std::string param_value; + if (p.value().is_string()) { + param_value = p.value().get(); + } else if (p.value().is_number()) { + param_value = std::to_string(p.value().get()); // nlohmann::json can't just get numbers as strings, float works fine for int values } + char* val = new char[param_value.length() + 1]; + strcpy(val, param_value.c_str()); + arguments_w_json.push_back(val); } } } + } + + return arguments_w_json; +} - for (int i = pos; i < argc; i++) { - arguments_w_json.push_back(argv[i]); +std::vector args_parse_json_only_string(char* file_name) { + std::vector arguments_w_json; + nlohmann::json file_config = get_json(file_name); + if (!file_config.empty()) { // ensures no unnecessary work + arguments_w_json.push_back(file_name); + + for (auto& p : file_config.items()) { + // only use strings, numbers and booleans for switches + if (p.value().is_string() || p.value().is_number() || p.value().is_boolean()) { + arguments_w_json.push_back(p.key()); + + if (!p.value().is_boolean()) { + std::string param_value; + if (p.value().is_string()) { + param_value = p.value().get(); + } else if (p.value().is_number()) { + param_value = std::to_string(p.value().get()); // nlohmann::json can't just get numbers as strings, float works fine for int values + } + arguments_w_json.push_back(param_value); + } + } } } + + return arguments_w_json; +} - int argc_json = arguments_w_json.size(); - char** argv_json = &arguments_w_json[0]; +// standalone parsing attempt +bool gpt_params_parse_json(char* file_name, gpt_params & params) { + bool result = true; + //std::vector arguments = args_parse_json_only(file_name); + std::vector arguments = args_parse_json_only_string(file_name); + + if (!arguments.empty()) { // ensures no unnecessary work + int argc_json = arguments.size(); + //char** args_json = const_cast(&arguments[0]); + char** args_json = new char*[arguments.size()]; + for(size_t i = 0; i < arguments.size(); i++) { + args_json[i] = new char[arguments[i].size() + 1]; + strcpy(args_json[i], arguments[i].c_str()); + } + + try { + if (!gpt_params_parse_ex(argc_json, args_json, params)) { + gpt_print_usage(argc_json, args_json, gpt_params()); + exit(0); + } + for (size_t i = 0; i < arguments.size(); i++) { + delete [] args_json[i]; + } + delete [] args_json; + } + catch (const std::invalid_argument & ex) { + fprintf(stderr, "%s\n", ex.what()); + gpt_print_usage(argc_json, args_json, gpt_params()); + exit(1); + } + } else { + // let's also print help, pointing at a faulty file name/parameter + char** args = new char* {file_name}; + gpt_print_usage(1, args, gpt_params()); + exit(1); + } + + return result; +} + +// still deciding which one is worse, both leak +bool gpt_params_parse_json0(char* file_name, gpt_params & params) { + bool result = true; + std::vector arguments = args_parse_json_only(file_name); + + if (!arguments.empty()) { // ensures no unnecessary work + int argc_json = arguments.size(); + char** args_json = &arguments[0]; + + try { + if (!gpt_params_parse_ex(argc_json, args_json, params)) { + gpt_print_usage(argc_json, args_json, gpt_params()); + exit(0); + } + } + catch (const std::invalid_argument & ex) { + fprintf(stderr, "%s\n", ex.what()); + gpt_print_usage(argc_json, args_json, gpt_params()); + exit(1); + } + } else { + // let's also print help, pointing at a faulty file name/parameter + char** args = new char* {file_name}; + gpt_print_usage(1, args, gpt_params()); + exit(1); + } + + return result; +} + +bool gpt_params_parse(int argc, char ** argv, gpt_params & params) { + bool result = true; try { - if (!gpt_params_parse_ex(argc_json, argv_json, params)) { - gpt_print_usage(argc_json, argv_json, gpt_params()); + if (!gpt_params_parse_ex(argc, argv, params)) { + gpt_print_usage(argc, argv, gpt_params()); exit(0); } } catch (const std::invalid_argument & ex) { fprintf(stderr, "%s\n", ex.what()); - gpt_print_usage(argc_json, argv_json, gpt_params()); + gpt_print_usage(argc, argv, gpt_params()); exit(1); } - // clearing pointers - for (auto c : arguments_w_json) { - delete [] c; - } return result; } @@ -814,7 +898,10 @@ bool gpt_params_parse_ex(int argc, char ** argv, gpt_params & params) { // End of Parse args for logging parameters #endif // LOG_DISABLE_LOGS } else { - throw std::invalid_argument("error: unknown argument: " + arg); + if (!gpt_params_parse_json0(argv[i], params)) { // attempt to read as a file + invalid_param = true; + throw std::invalid_argument("error: unknown argument: " + arg); + } } } if (invalid_param) { diff --git a/common/common.h b/common/common.h index d8c14467b..ad38142df 100644 --- a/common/common.h +++ b/common/common.h @@ -138,6 +138,14 @@ struct gpt_params { nlohmann::json get_json(const char* file_name) noexcept; +std::vector args_parse_json_only(char* file_name); + +std::vector args_parse_json_only_string(char* file_name); + +bool gpt_params_parse_json(char* file_name, gpt_params & params); + +bool gpt_params_parse_json0(char* file_name, gpt_params & params); + bool gpt_params_parse_ex(int argc, char ** argv, gpt_params & params); bool gpt_params_parse(int argc, char ** argv, gpt_params & params); From 209d7e6522aa510e5ffdd881173099ae254a7366 Mon Sep 17 00:00:00 2001 From: MaggotHATE Date: Thu, 7 Dec 2023 19:19:48 +0500 Subject: [PATCH 7/9] Chose seemingly safer option --- common/common.cpp | 74 ++++------------------------------------------- common/common.h | 4 --- 2 files changed, 6 insertions(+), 72 deletions(-) diff --git a/common/common.cpp b/common/common.cpp index 6aac39aad..11212e5a9 100644 --- a/common/common.cpp +++ b/common/common.cpp @@ -128,37 +128,7 @@ nlohmann::json get_json(const char* file_name) noexcept { return {}; } -std::vector args_parse_json_only(char* file_name) { - std::vector arguments_w_json; - nlohmann::json file_config = get_json(file_name); - if (!file_config.empty()) { // ensures no unnecessary work - arguments_w_json.push_back(file_name); - - for (auto& p : file_config.items()) { - // only use strings, numbers and booleans for switches - if (p.value().is_string() || p.value().is_number() || p.value().is_boolean()) { - char* key = new char[p.key().length() + 1]; - strcpy(key, p.key().c_str()); - arguments_w_json.push_back(key); - - if (!p.value().is_boolean()) { - std::string param_value; - if (p.value().is_string()) { - param_value = p.value().get(); - } else if (p.value().is_number()) { - param_value = std::to_string(p.value().get()); // nlohmann::json can't just get numbers as strings, float works fine for int values - } - char* val = new char[param_value.length() + 1]; - strcpy(val, param_value.c_str()); - arguments_w_json.push_back(val); - } - } - } - } - - return arguments_w_json; -} - +// standalone parsing attempt std::vector args_parse_json_only_string(char* file_name) { std::vector arguments_w_json; nlohmann::json file_config = get_json(file_name); @@ -175,32 +145,30 @@ std::vector args_parse_json_only_string(char* file_name) { if (p.value().is_string()) { param_value = p.value().get(); } else if (p.value().is_number()) { - param_value = std::to_string(p.value().get()); // nlohmann::json can't just get numbers as strings, float works fine for int values + param_value = std::to_string(p.value().get()); // works for int values too } arguments_w_json.push_back(param_value); } } } } - + return arguments_w_json; } -// standalone parsing attempt +// this variant seems safer, we can clear args after processing bool gpt_params_parse_json(char* file_name, gpt_params & params) { bool result = true; - //std::vector arguments = args_parse_json_only(file_name); std::vector arguments = args_parse_json_only_string(file_name); if (!arguments.empty()) { // ensures no unnecessary work int argc_json = arguments.size(); - //char** args_json = const_cast(&arguments[0]); char** args_json = new char*[arguments.size()]; for(size_t i = 0; i < arguments.size(); i++) { args_json[i] = new char[arguments[i].size() + 1]; strcpy(args_json[i], arguments[i].c_str()); } - + try { if (!gpt_params_parse_ex(argc_json, args_json, params)) { gpt_print_usage(argc_json, args_json, gpt_params()); @@ -226,36 +194,6 @@ bool gpt_params_parse_json(char* file_name, gpt_params & params) { return result; } -// still deciding which one is worse, both leak -bool gpt_params_parse_json0(char* file_name, gpt_params & params) { - bool result = true; - std::vector arguments = args_parse_json_only(file_name); - - if (!arguments.empty()) { // ensures no unnecessary work - int argc_json = arguments.size(); - char** args_json = &arguments[0]; - - try { - if (!gpt_params_parse_ex(argc_json, args_json, params)) { - gpt_print_usage(argc_json, args_json, gpt_params()); - exit(0); - } - } - catch (const std::invalid_argument & ex) { - fprintf(stderr, "%s\n", ex.what()); - gpt_print_usage(argc_json, args_json, gpt_params()); - exit(1); - } - } else { - // let's also print help, pointing at a faulty file name/parameter - char** args = new char* {file_name}; - gpt_print_usage(1, args, gpt_params()); - exit(1); - } - - return result; -} - bool gpt_params_parse(int argc, char ** argv, gpt_params & params) { bool result = true; @@ -898,7 +836,7 @@ bool gpt_params_parse_ex(int argc, char ** argv, gpt_params & params) { // End of Parse args for logging parameters #endif // LOG_DISABLE_LOGS } else { - if (!gpt_params_parse_json0(argv[i], params)) { // attempt to read as a file + if (!gpt_params_parse_json(argv[i], params)) { // attempt to read as a file invalid_param = true; throw std::invalid_argument("error: unknown argument: " + arg); } diff --git a/common/common.h b/common/common.h index ad38142df..c965a0cee 100644 --- a/common/common.h +++ b/common/common.h @@ -138,14 +138,10 @@ struct gpt_params { nlohmann::json get_json(const char* file_name) noexcept; -std::vector args_parse_json_only(char* file_name); - std::vector args_parse_json_only_string(char* file_name); bool gpt_params_parse_json(char* file_name, gpt_params & params); -bool gpt_params_parse_json0(char* file_name, gpt_params & params); - bool gpt_params_parse_ex(int argc, char ** argv, gpt_params & params); bool gpt_params_parse(int argc, char ** argv, gpt_params & params); From d8350a6a1b08f396f734c7702107f296bdf1f345 Mon Sep 17 00:00:00 2001 From: MaggotHATE Date: Fri, 8 Dec 2023 19:24:46 +0500 Subject: [PATCH 8/9] Example of using it on server --- examples/server/server.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/examples/server/server.cpp b/examples/server/server.cpp index 895f751c9..190a50d00 100644 --- a/examples/server/server.cpp +++ b/examples/server/server.cpp @@ -2319,9 +2319,11 @@ static void server_params_parse(int argc, char **argv, server_params &sparams, } else { - fprintf(stderr, "error: unknown argument: %s\n", arg.c_str()); - server_print_usage(argv[0], default_params, default_sparams); - exit(1); + if (!gpt_params_parse_json(argv[i], params)) { // attempt to read as a file + fprintf(stderr, "error: unknown argument: %s\n", arg.c_str()); + server_print_usage(argv[0], default_params, default_sparams); + exit(1); + } } } From faefd46f99b71182475828c60f6a083ed7c27f92 Mon Sep 17 00:00:00 2001 From: MaggotHATE Date: Sat, 9 Dec 2023 20:34:43 +0500 Subject: [PATCH 9/9] Reworked to be self-contained and more universal --- common/common.cpp | 90 +++--------------------------- common/common.h | 8 --- common/json-util.hpp | 110 +++++++++++++++++++++++++++++++++++++ examples/server/server.cpp | 10 +++- 4 files changed, 128 insertions(+), 90 deletions(-) create mode 100644 common/json-util.hpp diff --git a/common/common.cpp b/common/common.cpp index 11212e5a9..6b5f1ac5c 100644 --- a/common/common.cpp +++ b/common/common.cpp @@ -1,5 +1,6 @@ #include "common.h" #include "llama.h" +#include "json-util.hpp" #include #include @@ -115,85 +116,6 @@ void process_escapes(std::string& input) { input.resize(output_idx); } -nlohmann::json get_json(const char* file_name) noexcept { - try { - printf("Opening a json file %s\n", file_name); - std::ifstream jstream(file_name); - return nlohmann::json::parse(jstream); - } - catch (const std::exception& ex) { - fprintf(stderr, "%s\n", ex.what()); - } - - return {}; -} - -// standalone parsing attempt -std::vector args_parse_json_only_string(char* file_name) { - std::vector arguments_w_json; - nlohmann::json file_config = get_json(file_name); - if (!file_config.empty()) { // ensures no unnecessary work - arguments_w_json.push_back(file_name); - - for (auto& p : file_config.items()) { - // only use strings, numbers and booleans for switches - if (p.value().is_string() || p.value().is_number() || p.value().is_boolean()) { - arguments_w_json.push_back(p.key()); - - if (!p.value().is_boolean()) { - std::string param_value; - if (p.value().is_string()) { - param_value = p.value().get(); - } else if (p.value().is_number()) { - param_value = std::to_string(p.value().get()); // works for int values too - } - arguments_w_json.push_back(param_value); - } - } - } - } - - return arguments_w_json; -} - -// this variant seems safer, we can clear args after processing -bool gpt_params_parse_json(char* file_name, gpt_params & params) { - bool result = true; - std::vector arguments = args_parse_json_only_string(file_name); - - if (!arguments.empty()) { // ensures no unnecessary work - int argc_json = arguments.size(); - char** args_json = new char*[arguments.size()]; - for(size_t i = 0; i < arguments.size(); i++) { - args_json[i] = new char[arguments[i].size() + 1]; - strcpy(args_json[i], arguments[i].c_str()); - } - - try { - if (!gpt_params_parse_ex(argc_json, args_json, params)) { - gpt_print_usage(argc_json, args_json, gpt_params()); - exit(0); - } - for (size_t i = 0; i < arguments.size(); i++) { - delete [] args_json[i]; - } - delete [] args_json; - } - catch (const std::invalid_argument & ex) { - fprintf(stderr, "%s\n", ex.what()); - gpt_print_usage(argc_json, args_json, gpt_params()); - exit(1); - } - } else { - // let's also print help, pointing at a faulty file name/parameter - char** args = new char* {file_name}; - gpt_print_usage(1, args, gpt_params()); - exit(1); - } - - return result; -} - bool gpt_params_parse(int argc, char ** argv, gpt_params & params) { bool result = true; @@ -836,8 +758,14 @@ bool gpt_params_parse_ex(int argc, char ** argv, gpt_params & params) { // End of Parse args for logging parameters #endif // LOG_DISABLE_LOGS } else { - if (!gpt_params_parse_json(argv[i], params)) { // attempt to read as a file - invalid_param = true; + args_struct args_obj(argv[i]); + + if (args_obj.argc > 0) { + int argc_json = args_obj.argc; + char** args_json = args_obj.argv; + + return gpt_params_parse(argc_json, args_json, params); + } else { throw std::invalid_argument("error: unknown argument: " + arg); } } diff --git a/common/common.h b/common/common.h index c965a0cee..e87ce1133 100644 --- a/common/common.h +++ b/common/common.h @@ -6,8 +6,6 @@ #include "sampling.h" -#include "examples/server/json.hpp" - #define LOG_NO_FILE_LINE_FUNCTION #include "log.h" @@ -136,12 +134,6 @@ struct gpt_params { std::string image = ""; // path to an image file }; -nlohmann::json get_json(const char* file_name) noexcept; - -std::vector args_parse_json_only_string(char* file_name); - -bool gpt_params_parse_json(char* file_name, gpt_params & params); - bool gpt_params_parse_ex(int argc, char ** argv, gpt_params & params); bool gpt_params_parse(int argc, char ** argv, gpt_params & params); diff --git a/common/json-util.hpp b/common/json-util.hpp new file mode 100644 index 000000000..6a5e4f5ef --- /dev/null +++ b/common/json-util.hpp @@ -0,0 +1,110 @@ +#pragma once + +#include +#include +#include +#include "examples/server/json.hpp" + +static nlohmann::json get_json(const char* file_name) noexcept { + try { + printf("Opening a json file %s\n", file_name); + std::ifstream jstream(file_name); + return nlohmann::json::parse(jstream); + } + catch (const std::exception& ex) { + fprintf(stderr, "%s\n", ex.what()); + } + + return {}; +} + +struct args_struct { + size_t argc; + char** argv; + size_t elements_count = 0; + size_t index = 0; + + std::vector arg_chars = {}; + std::vector arg_idxs = {}; + std::vector arg_ptrs = {}; + + args_struct() = default; + + args_struct(char* file_name) { + createParams(file_name); + } + + ~args_struct() = default; + + void reset() noexcept { + elements_count = 0; + index = 0; + + arg_chars.clear(); + arg_idxs.clear(); + + reset_args(); + } + + void reset_args() noexcept { + arg_ptrs.clear(); + argc = 0; + argv = nullptr; + } + + void add(const std::string& data) { + // resetting previous args + reset_args(); + + arg_idxs.emplace_back(index); + for(const auto& character : data) { + arg_chars.emplace_back(character); + ++index; + } + + arg_chars.emplace_back('\0'); + ++index; + ++elements_count; + } + + void get_args() { + reset_args(); + if(elements_count) { + arg_ptrs.reserve(elements_count); + + for(const auto& index : arg_idxs) { + arg_ptrs.emplace_back(&arg_chars[index]); + } + } else { + arg_ptrs.emplace_back(nullptr); + } + + argc = elements_count; + argv = &arg_ptrs[0]; + } + + void createParams(char* file_name) { + reset(); // starting over + nlohmann::json file_config = get_json(file_name); + if (!file_config.empty()) { // ensures no unnecessary work + add(file_name); + for (auto& p : file_config.items()) { + // only use strings, numbers and booleans for switches + if (p.value().is_string() || p.value().is_number() || p.value().is_boolean()) { + add(p.key()); + + if (!p.value().is_boolean()) { + std::string param_value; + if (p.value().is_string()) { + param_value = p.value().get(); + } else if (p.value().is_number()) { + param_value = std::to_string(p.value().get()); // works for int values too + } + add(param_value); + } + } + } + get_args(); + } + } +}; diff --git a/examples/server/server.cpp b/examples/server/server.cpp index 190a50d00..1cc4b4444 100644 --- a/examples/server/server.cpp +++ b/examples/server/server.cpp @@ -1,6 +1,7 @@ #include "common.h" #include "llama.h" #include "grammar-parser.h" +#include "json-util.hpp" #include "../llava/clip.h" @@ -2319,7 +2320,14 @@ static void server_params_parse(int argc, char **argv, server_params &sparams, } else { - if (!gpt_params_parse_json(argv[i], params)) { // attempt to read as a file + args_struct args_obj(argv[i]); + + if (args_obj.argc > 0) { + int argc_json = args_obj.argc; + char** args_json = args_obj.argv; + + return server_params_parse(argc_json, args_json, sparams, params, llama); + } else { fprintf(stderr, "error: unknown argument: %s\n", arg.c_str()); server_print_usage(argv[0], default_params, default_sparams); exit(1);