From faefd46f99b71182475828c60f6a083ed7c27f92 Mon Sep 17 00:00:00 2001 From: MaggotHATE Date: Sat, 9 Dec 2023 20:34:43 +0500 Subject: [PATCH] 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);