6 #define CPPHTTPLIB_READ_TIMEOUT_SECOND 60*60 
   26     virtual std::vector<std::vector<double>> 
Evaluate(
const std::vector<std::vector<double>>& inputs,
 
   28       (void)inputs; (void)config_json; 
 
   29       throw std::runtime_error(
"Evaluate was called, but not implemented by model!");
 
   32     virtual std::vector<double> 
Gradient(
unsigned int outWrt,
 
   34                           const std::vector<std::vector<double>>& inputs,
 
   35                           const std::vector<double>& sens,
 
   37       (void)outWrt; (void)inWrt; (void)inputs; (void)sens; (void)config_json; 
 
   38       throw std::runtime_error(
"Gradient was called, but not implemented by model!");
 
   43                               const std::vector<std::vector<double>>& inputs,
 
   44                               const std::vector<double>& vec,
 
   46       (void)outWrt; (void)inWrt; (void)inputs; (void)vec; (void)config_json; 
 
   47       throw std::runtime_error(
"ApplyJacobian was called, but not implemented by model!");
 
   53                               const std::vector<std::vector<double>>& inputs,
 
   54                               const std::vector<double>& sens,
 
   55                               const std::vector<double>& vec,
 
   57       (void)outWrt; (void)inWrt1; (void)inWrt2; (void)inputs; (void)sens; (void)vec; (void)config_json; 
 
   58       throw std::runtime_error(
"ApplyHessian was called, but not implemented by model!");
 
   82         if (response.
value<
double>(
"protocolVersion",0) != 1.0)
 
   83           throw std::runtime_error(
"Model protocol version not supported!");
 
   86         std::vector<std::string> models = response[
"models"];
 
   87         if (std::find(models.begin(), models.end(), 
name) == models.end()) {
 
   88           std::string model_names = 
"";
 
   89           for (
auto& m : models) {
 
   90             model_names += 
"'" + m + 
"' ";
 
   92           throw std::runtime_error(
"Model " + 
name + 
" not found on server! Available models: " + model_names + 
".");
 
   96         throw std::runtime_error(
"GET Info failed with error type '" + 
to_string(res.error()) + 
"'");
 
  100       request_body[
"name"] = 
name;
 
  102       if (
auto res = 
cli.Post(
"/ModelInfo", 
headers, request_body.
dump(), 
"application/json")) {
 
  105         json supported_features = response.
at(
"support");
 
  111         throw std::runtime_error(
"POST ModelInfo failed with error type '" + 
to_string(res.error()) + 
"'");
 
  118       request_body[
"name"] = 
name;
 
  119       if (!config_json.empty())
 
  120         request_body[
"config"] = config_json;
 
  122       if (
auto res = 
cli.Post(
"/InputSizes", 
headers, request_body.
dump(), 
"application/json")) {
 
  124         std::vector<std::size_t> outputvec = response_body[
"inputSizes"].
get<std::vector<std::size_t>>();
 
  127         throw std::runtime_error(
"POST InputSizes failed with error type '" + 
to_string(res.error()) + 
"'");
 
  128         return std::vector<std::size_t>(0);
 
  135       request_body[
"name"] = 
name;
 
  136       if (!config_json.empty())
 
  137         request_body[
"config"] = config_json;
 
  139       if (
auto res = 
cli.Post(
"/OutputSizes", 
headers, request_body.
dump(), 
"application/json")) {
 
  141         std::vector<std::size_t> outputvec = response_body[
"outputSizes"].
get<std::vector<std::size_t>>();
 
  144         throw std::runtime_error(
"POST OutputSizes failed with error type '" + 
to_string(res.error()) + 
"'");
 
  145         return std::vector<std::size_t>(0);
 
  149     std::vector<std::vector<double>> 
Evaluate(
const std::vector<std::vector<double>>& inputs, 
json config_json = 
json())
 override {
 
  152       request_body[
"name"] = 
name;
 
  154       for (std::size_t i = 0; i < inputs.size(); i++) {
 
  155         request_body[
"input"][i] = inputs[i];
 
  157       if (!config_json.empty())
 
  158         request_body[
"config"] = config_json;
 
  160       if (
auto res = 
cli.Post(
"/Evaluate", 
headers, request_body.
dump(), 
"application/json")) {
 
  164         std::vector<std::vector<double>> outputs(response_body[
"output"].size());
 
  165         for (std::size_t i = 0; i < response_body[
"output"].
size(); i++) {
 
  166           outputs[i] = response_body[
"output"][i].
get<std::vector<double>>();
 
  170         throw std::runtime_error(
"POST Evaluate failed with error type '" + 
to_string(res.error()) + 
"'");
 
  176                   const std::vector<std::vector<double>>& inputs,
 
  177                   const std::vector<double>& sens,
 
  182       request_body[
"name"] = 
name;
 
  183       request_body[
"outWrt"] = outWrt;
 
  184       request_body[
"inWrt"] = inWrt;
 
  185       for (std::size_t i = 0; i < inputs.size(); i++) {
 
  186         request_body[
"input"][i] = inputs[i];
 
  188       request_body[
"sens"] = sens;
 
  189       if (!config_json.empty())
 
  190         request_body[
"config"] = config_json;
 
  192       if (
auto res = 
cli.Post(
"/Gradient", 
headers, request_body.
dump(), 
"application/json")) {
 
  196         return response_body[
"output"].
get<std::vector<double>>();
 
  198         throw std::runtime_error(
"POST Gradient failed with error type '" + 
to_string(res.error()) + 
"'");
 
  204                               const std::vector<std::vector<double>>& inputs,
 
  205                               const std::vector<double>& vec,
 
  206                               json config_json = 
json())
 override {
 
  209       request_body[
"name"] = 
name;
 
  210       request_body[
"outWrt"] = outWrt;
 
  211       request_body[
"inWrt"] = inWrt;
 
  212       for (std::size_t i = 0; i < inputs.size(); i++) {
 
  213         request_body[
"input"][i] = inputs[i];
 
  215       request_body[
"vec"] = vec;
 
  216       if (!config_json.empty())
 
  217         request_body[
"config"] = config_json;
 
  219       if (
auto res = 
cli.Post(
"/ApplyJacobian", 
headers, request_body.
dump(), 
"application/json")) {
 
  223         return response_body[
"output"].
get<std::vector<double>>();
 
  225         throw std::runtime_error(
"POST ApplyJacobian failed with error type '" + 
to_string(res.error()) + 
"'");
 
  232                       const std::vector<std::vector<double>>& inputs,
 
  233                       const std::vector<double>& sens,
 
  234                       const std::vector<double>& vec,
 
  235                       json config_json = 
json())
 override {
 
  238       request_body[
"name"] = 
name;
 
  239       request_body[
"outWrt"] = outWrt;
 
  240       request_body[
"inWrt1"] = inWrt1;
 
  241       request_body[
"inWrt2"] = inWrt2;
 
  242       for (std::size_t i = 0; i < inputs.size(); i++) {
 
  243         request_body[
"input"][i] = inputs[i];
 
  245       request_body[
"sens"] = sens;
 
  246       request_body[
"vec"] = vec;
 
  247       if (!config_json.empty())
 
  248         request_body[
"config"] = config_json;
 
  250       if (
auto res = 
cli.Post(
"/ApplyHessian", 
headers, request_body.
dump(), 
"application/json")) {
 
  254         return response_body[
"output"].
get<std::vector<double>>();
 
  256         throw std::runtime_error(
"POST ApplyHessian failed with error type '" + 
to_string(res.error()) + 
"'");
 
  275     mutable httplib::Client 
cli;
 
  285       if (response_body.
find(
"error") != response_body.
end()) {
 
  286         throw std::runtime_error(
"Model server returned error of type " + response_body[
"error"][
"type"].get<std::string>() + 
", message: " + response_body[
"error"][
"message"].get<std::string>());
 
  293   bool check_input_sizes(
const std::vector<std::vector<double>>& inputs, 
const json& config_json, 
const Model& model, httplib::Response& res) {
 
  296       response_body[
"error"][
"type"] = 
"InvalidInput";
 
  297       response_body[
"error"][
"message"] = 
"Number of inputs does not match number of model inputs. Expected " + 
std::to_string(model.
GetInputSizes(config_json).size()) + 
" but got " + 
std::to_string(inputs.size());
 
  298       res.set_content(response_body.
dump(), 
"application/json");
 
  302     for (std::size_t i = 0; i < inputs.size(); i++) {
 
  303       if (inputs[i].size() != model.
GetInputSizes(config_json)[i]) {
 
  305         response_body[
"error"][
"type"] = 
"InvalidInput";
 
  307         res.set_content(response_body.
dump(), 
"application/json");
 
  319       response_body[
"error"][
"type"] = 
"InvalidInput";
 
  321       res.set_content(response_body.
dump(), 
"application/json");
 
  332       response_body[
"error"][
"type"] = 
"InvalidInput";
 
  334       res.set_content(response_body.
dump(), 
"application/json");
 
  345       response_body[
"error"][
"type"] = 
"InvalidOutput";
 
  346       response_body[
"error"][
"message"] = 
"Number of outputs declared by model does not match number of outputs returned by model. Model declared " + 
std::to_string(model.
GetOutputSizes(config_json).size()) + 
" but returned " + 
std::to_string(outputs.size());
 
  347       res.set_content(response_body.
dump(), 
"application/json");
 
  351     for (std::size_t i = 0; i < outputs.size(); i++) {
 
  354         response_body[
"error"][
"type"] = 
"InvalidOutput";
 
  356         res.set_content(response_body.
dump(), 
"application/json");
 
  366     if (inWrt < 0 || inWrt >= (
int)model.
GetInputSizes(config_json).size()) {
 
  368       response_body[
"error"][
"type"] = 
"InvalidInput";
 
  370       res.set_content(response_body.
dump(), 
"application/json");
 
  379     if (outWrt < 0 || outWrt >= (
int)model.
GetOutputSizes(config_json).size()) {
 
  381       response_body[
"error"][
"type"] = 
"InvalidInput";
 
  383       res.set_content(response_body.
dump(), 
"application/json");
 
  393     response_body[
"error"][
"type"] = 
"UnsupportedFeature";
 
  394     response_body[
"error"][
"message"] = 
"Feature '" + feature + 
"' is not supported by this model";
 
  395     res.set_content(response_body.
dump(), 
"application/json");
 
  401     for (
auto& model : models) {
 
  402       if (model->GetName() == name) {
 
  406     throw std::runtime_error(
"Model not found");
 
  413     } 
catch (std::runtime_error& 
e) {
 
  415       response_body[
"error"][
"type"] = 
"ModelNotFound";
 
  416       response_body[
"error"][
"message"] = 
"Model '" + name + 
"' not supported by this server!";
 
  417       res.set_content(response_body.
dump(), 
"application/json");
 
  425   void serveModels(std::vector<Model*> models, std::string host, 
int port) {
 
  428     std::mutex model_mutex; 
 
  430     svr.Post(
"/Evaluate", [&](
const httplib::Request &req, httplib::Response &res) {
 
  441       std::vector<std::vector<double>> inputs(request_body[
"input"].size());
 
  442       for (std::size_t i = 0; i < inputs.size(); i++) {
 
  443         inputs[i] = request_body[
"input"][i].
get<std::vector<double>>();
 
  446       json empty_default_config;
 
  447       json config_json = request_body.
value(
"config", empty_default_config);
 
  452       const std::lock_guard<std::mutex> model_lock(model_mutex);
 
  453       std::vector<std::vector<double>> outputs = model.
Evaluate(inputs, config_json);
 
  459       for (std::size_t i = 0; i < outputs.size(); i++) {
 
  460         response_body[
"output"][i] = outputs[i];
 
  463       res.set_content(response_body.
dump(), 
"application/json");
 
  466     svr.Post(
"/Gradient", [&](
const httplib::Request &req, httplib::Response &res) {
 
  477       unsigned int inWrt = request_body.
at(
"inWrt");
 
  478       unsigned int outWrt = request_body.
at(
"outWrt");
 
  480       std::vector<std::vector<double>> inputs(request_body[
"input"].size());
 
  481       for (std::size_t i = 0; i < inputs.size(); i++) {
 
  482         inputs[i] = request_body[
"input"][i].
get<std::vector<double>>();
 
  485       std::vector<double> sens = request_body.
at(
"sens");
 
  487       json empty_default_config;
 
  488       json config_json = request_body.
value(
"config", empty_default_config);
 
  499       const std::lock_guard<std::mutex> model_lock(model_mutex);
 
  500       std::vector<double> gradient = model.
Gradient(outWrt, inWrt, inputs, sens, config_json);
 
  503       response_body[
"output"] = gradient;
 
  505       res.set_content(response_body.
dump(), 
"application/json");
 
  508     svr.Post(
"/ApplyJacobian", [&](
const httplib::Request &req, httplib::Response &res) {
 
  519       unsigned int inWrt = request_body.
at(
"inWrt");
 
  520       unsigned int outWrt = request_body.
at(
"outWrt");
 
  522       std::vector<std::vector<double>> inputs(request_body[
"input"].size());
 
  523       for (std::size_t i = 0; i < inputs.size(); i++) {
 
  524         inputs[i] = request_body[
"input"][i].
get<std::vector<double>>();
 
  527       std::vector<double> vec = request_body.
at(
"vec");
 
  529       json empty_default_config;
 
  530       json config_json = request_body.
value(
"config", empty_default_config);
 
  541       const std::lock_guard<std::mutex> model_lock(model_mutex);
 
  542       std::vector<double> jacobian_action = model.
ApplyJacobian(outWrt, inWrt, inputs, vec, config_json);
 
  545       response_body[
"output"] = jacobian_action;
 
  547       res.set_content(response_body.
dump(), 
"application/json");
 
  550     svr.Post(
"/ApplyHessian", [&](
const httplib::Request &req, httplib::Response &res) {
 
  561       unsigned int outWrt = request_body.
at(
"outWrt");
 
  562       unsigned int inWrt1 = request_body.
at(
"inWrt1");
 
  563       unsigned int inWrt2 = request_body.
at(
"inWrt2");
 
  565       std::vector<std::vector<double>> inputs(request_body[
"input"].size());
 
  566       for (std::size_t i = 0; i < inputs.size(); i++) {
 
  567         inputs[i] = request_body[
"input"][i].
get<std::vector<double>>();
 
  570       std::vector<double> sens = request_body.
at(
"sens");
 
  571       std::vector<double> vec = request_body.
at(
"vec");
 
  573       json empty_default_config;
 
  574       json config_json = request_body.
value(
"config", empty_default_config);
 
  587       const std::lock_guard<std::mutex> model_lock(model_mutex);
 
  588       std::vector<double> hessian_action = model.
ApplyHessian(outWrt, inWrt1, inWrt2, inputs, sens, vec, config_json);
 
  591       response_body[
"output"] = hessian_action;
 
  593       res.set_content(response_body.
dump(), 
"application/json");
 
  596     svr.Get(
"/Info", [&](
const httplib::Request &, httplib::Response &res) {
 
  598       response_body[
"protocolVersion"] = 1.0;
 
  599       std::vector<std::string> model_names;
 
  600       for (
auto& model : models) {
 
  603       response_body[
"models"] = model_names;
 
  605       res.set_content(response_body.
dump(), 
"application/json");
 
  608     svr.Post(
"/ModelInfo", [&](
const httplib::Request &req, httplib::Response &res) {
 
  615       response_body[
"support"] = {};
 
  621       res.set_content(response_body.
dump(), 
"application/json");
 
  624     svr.Post(
"/InputSizes", [&](
const httplib::Request &req, httplib::Response &res) {
 
  630       json empty_default_config;
 
  631       json config_json = request_body.
value(
"config", empty_default_config);
 
  634       response_body[
"inputSizes"] = model.
GetInputSizes(config_json);
 
  636       res.set_content(response_body.
dump(), 
"application/json");
 
  639     svr.Post(
"/OutputSizes", [&](
const httplib::Request &req, httplib::Response &res) {
 
  645       json empty_default_config;
 
  646       json config_json = request_body.
value(
"config", empty_default_config);
 
  651       res.set_content(response_body.
dump(), 
"application/json");
 
  654     std::cout << 
"Listening on port " << port << 
"..." << std::endl;
 
  655     svr.listen(host.c_str(), port);
 
  656     std::cout << 
"Quit" << std::endl;
 
a class to store JSON values
 
basic_json get() const
get special-case overload
 
ValueType value(const typename object_t::key_type &key, const ValueType &default_value) const
access specified object element with default value
 
static JSON_HEDLEY_WARN_UNUSED_RESULT basic_json parse(InputType &&i, const parser_callback_t cb=nullptr, const bool allow_exceptions=true, const bool ignore_comments=false)
deserialize from a compatible input
 
size_type size() const noexcept
returns the number of elements
 
string_t dump(const int indent=-1, const char indent_char=' ', const bool ensure_ascii=false, const error_handler_t error_handler=error_handler_t::strict) const
serialization
 
reference at(size_type idx)
access specified array element with bounds checking
 
iterator end() noexcept
returns an iterator to one past the last element
 
void push_back(basic_json &&val)
add an object to an array
 
iterator find(KeyT &&key)
find an element in a JSON object
 
bool supportsApplyHessian
 
bool SupportsApplyHessian() override
 
bool SupportsEvaluate() override
 
bool SupportsGradient() override
 
bool SupportsApplyJacobian() override
 
std::vector< std::vector< double > > Evaluate(const std::vector< std::vector< double >> &inputs, json config_json=json()) override
 
std::vector< std::size_t > GetOutputSizes(const json &config_json=json()) const override
 
std::vector< double > Gradient(unsigned int outWrt, unsigned int inWrt, const std::vector< std::vector< double >> &inputs, const std::vector< double > &sens, json config_json=json()) override
 
void throw_if_error_in_response(const json &response_body)
 
std::vector< double > ApplyHessian(unsigned int outWrt, unsigned int inWrt1, unsigned int inWrt2, const std::vector< std::vector< double >> &inputs, const std::vector< double > &sens, const std::vector< double > &vec, json config_json=json()) override
 
bool supportsApplyJacobian
 
std::vector< double > ApplyJacobian(unsigned int outWrt, unsigned int inWrt, const std::vector< std::vector< double >> &inputs, const std::vector< double > &vec, json config_json=json()) override
 
HTTPModel(std::string host, std::string name, httplib::Headers headers=httplib::Headers())
 
std::vector< std::size_t > GetInputSizes(const json &config_json=json()) const override
 
virtual bool SupportsGradient()
 
virtual std::vector< double > ApplyHessian(unsigned int outWrt, unsigned int inWrt1, unsigned int inWrt2, const std::vector< std::vector< double >> &inputs, const std::vector< double > &sens, const std::vector< double > &vec, json config_json=json())
 
virtual bool SupportsApplyHessian()
 
virtual std::vector< std::size_t > GetInputSizes(const json &config_json=json()) const =0
 
virtual std::vector< double > Gradient(unsigned int outWrt, unsigned int inWrt, const std::vector< std::vector< double >> &inputs, const std::vector< double > &sens, json config_json=json())
 
virtual std::vector< std::vector< double > > Evaluate(const std::vector< std::vector< double >> &inputs, json config_json=json())
 
virtual std::vector< double > ApplyJacobian(unsigned int outWrt, unsigned int inWrt, const std::vector< std::vector< double >> &inputs, const std::vector< double > &vec, json config_json=json())
 
virtual std::vector< std::size_t > GetOutputSizes(const json &config_json=json()) const =0
 
std::string GetName() const
 
virtual bool SupportsApplyJacobian()
 
virtual bool SupportsEvaluate()
 
basic_json<> json
default JSON class
 
NLOHMANN_BASIC_JSON_TPL_DECLARATION std::string to_string(const NLOHMANN_BASIC_JSON_TPL &j)
user-defined to_string function for JSON values
 
void write_unsupported_feature_response(httplib::Response &res, std::string feature)
 
bool check_output_sizes(const std::vector< std::vector< double >> &outputs, const json &config_json, const Model &model, httplib::Response &res)
 
bool check_sensitivity_size(const std::vector< double > &sens, int outWrt, const json &config_json, const Model &model, httplib::Response &res)
 
bool check_input_sizes(const std::vector< std::vector< double >> &inputs, const json &config_json, const Model &model, httplib::Response &res)
 
bool check_output_wrt(int outWrt, const json &config_json, const Model &model, httplib::Response &res)
 
void serveModels(std::vector< Model * > models, std::string host, int port)
 
bool check_vector_size(const std::vector< double > &vec, int inWrt, const json &config_json, const Model &model, httplib::Response &res)
 
bool check_input_wrt(int inWrt, const json &config_json, const Model &model, httplib::Response &res)
 
Model & get_model_from_name(std::vector< Model * > &models, std::string name)
 
bool check_model_exists(std::vector< Model * > &models, std::string name, httplib::Response &res)