Skip to content

Commit ac0db97

Browse files
committed
args, server: Simplify and fix bugs
User-facing improvements * Bare `./tts-cli -p` no longer crashes * Merged --use-espeak into just omitting --phonemizer-path * Errors are now text/plain instead of JSON * We don't need to write so much error handling code * OpenAI compatibility isn't important for errors * Server startup page now only disappears after everything loads * Fixed buffer reuse race condition between audio generation and HTTP output * conditional_prompt is now a JSON key, no longer an HTTP endpoint * This lifts the limitation of 1 worker thread Internal improvements * struct arg is now pointer-free and like a regular std::variant * `args["my-arg"]` (+ cast rarely) should feel like Python * Deduplicated args.add, updated .md, unified descriptions * Converted many copies to pass-by-reference * Less related files are left for the code style PR * Cached the only 2 JSON success responses * The main thread is now simply the listener thread, not a worker * Timeouts are now also enforced on the HTTP threads * Removed simple_response_map to avoid collisions and thread contention * simple_text_prompt_task is pooled and no longer leaked every request * This is the first time we're freeing runner memory
1 parent c443aae commit ac0db97

31 files changed

+836
-1271
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ We are currently [working on upstreaming some of these operations inorder to dep
6060
#### Build:
6161

6262
Assuming that the above requirements are met the library and basic CLI example can be built by running the following command in the repository's base directory:
63-
```commandline
63+
```bash
6464
cmake -B build
6565
cmake --build build --config Release
6666
```

examples/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
add_library(examples_common
44
args.cpp
55
args.h
6+
args_common.cpp
7+
args_common.h
68
audio_file.h
79
)
810
target_include_directories(examples_common PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

examples/args.cpp

Lines changed: 51 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -1,164 +1,72 @@
11
#include "args.h"
22

3-
std::string arg::help_text() {
4-
std::string htxt = full_name;
5-
if (abbreviation != "") {
6-
htxt += " (" + abbreviation + ")";
3+
#include <iostream>
4+
#include <sstream>
5+
6+
void arg::print_help() const {
7+
cout << "--" << full_name;
8+
if (*abbreviation) {
9+
cout << " (-" << abbreviation << ")";
710
}
8-
htxt += ":\n ";
9-
if (description != "") {
10-
htxt += description + "\n";
11+
if (*description) {
12+
cout << (required ? ":\n (REQUIRED) " : ":\n (OPTIONAL) ") << description << ".\n";
1113
} else {
12-
htxt += "is a " + (std::string)(required ? "required " : "optional ") + "parameter.\n";
14+
cout << (required ? " is a required parameter.\n" : " is an optional parameter.\n");
1315
}
14-
return htxt;
1516
}
1617

17-
int string_arg::parse(int argc, const char ** argv) {
18+
void arg::parse(span<str> & argv) {
1819
required = false;
19-
value.assign(argv[0]);
20-
return 1;
21-
}
22-
23-
int int_arg::parse(int argc, const char ** argv) {
24-
if (required) {
25-
required = false;
20+
if (const auto bool_param{get_if<bool>(&value)}) {
21+
*bool_param = true;
22+
return;
23+
}
24+
const str a = argv[0];
25+
argv = argv.subspan(1);
26+
if (const auto string_param{get_if<str>(&value)}) {
27+
*string_param = a;
28+
} else if (const auto int_param{get_if<int>(&value)}) {
29+
istringstream{a} >> *int_param;
30+
} else if (const auto float_param{get_if<float>(&value)}) {
31+
istringstream{a} >> *float_param;
2632
}
27-
int val = atoi(argv[0]);
28-
*value = val;
29-
return 1;
3033
}
3134

32-
int float_arg::parse(int argc, const char ** argv) {
33-
if (required) {
34-
required = false;
35-
}
36-
float val = strtof(argv[0], nullptr);
37-
*value = val;
38-
return 1;
39-
}
40-
41-
void arg_list::help() {
42-
std::string help_text = "";
43-
for (auto arg : fargs) {
44-
help_text += arg.help_text();
45-
}
46-
for (auto arg : iargs) {
47-
help_text += arg.help_text();
48-
49-
}
50-
for (auto arg : bargs) {
51-
help_text += arg.help_text();
52-
53-
}
54-
for (auto arg : sargs) {
55-
help_text += arg.help_text();
56-
57-
}
58-
fprintf(stdout, "%s", help_text.c_str());
59-
}
60-
61-
void arg_list::validate() {
62-
for (auto arg : fargs) {
63-
if (arg.required) {
64-
fprintf(stderr, "argument '%s' is required.\n", arg.full_name.c_str());
35+
void arg_list::parse(int argc, str argv_[]) {
36+
TTS_ASSERT(argc);
37+
span<str> argv{argv_, static_cast<size_t>(argc)};
38+
argv = argv.subspan(1);
39+
while (!argv.empty()) {
40+
str name{argv[0]};
41+
if (*name != '-') {
42+
fprintf(stderr, "Only named arguments are supported\n");
6543
exit(1);
6644
}
67-
}
68-
for (auto arg : iargs) {
69-
if (arg.required) {
70-
fprintf(stderr, "argument '%s' is required.\n", arg.full_name.c_str());
71-
exit(1);
45+
++name;
46+
const map<sv, size_t> * lookup = &abbreviations;
47+
if (*name == '-') {
48+
++name;
49+
lookup = &full_names;
50+
if (name == "help"sv) {
51+
for (const size_t i : full_names | views::values) {
52+
args[i].print_help();
53+
}
54+
exit(0);
55+
}
7256
}
73-
}
74-
for (auto arg : bargs) {
75-
if (arg.required) {
76-
fprintf(stderr, "argument '%s' is required.\n", arg.full_name.c_str());
57+
const auto found = lookup->find(sv{name});
58+
if (found == lookup->end()) {
59+
fprintf(stderr, "argument '%s' is not a valid argument. "
60+
"Call '--help' for information on all valid arguments.\n", argv[0]);
7761
exit(1);
7862
}
63+
argv = argv.subspan(1);
64+
args[found->second].parse(argv);
7965
}
80-
for (auto arg : sargs) {
81-
if (arg.required) {
82-
fprintf(stderr, "argument '%s' is required.\n", arg.full_name.c_str());
66+
for (const arg & x : args) {
67+
if (x.required) {
68+
fprintf(stderr, "argument '--%s' is required.\n", x.full_name);
8369
exit(1);
8470
}
8571
}
8672
}
87-
88-
void arg_list::parse(int argc, const char ** argv) {
89-
int current_arg = 1;
90-
while (current_arg < argc) {
91-
std::string name(argv[current_arg]);
92-
if (name == "--help") {
93-
for_help = true;
94-
return;
95-
}
96-
current_arg += 1;
97-
current_arg += find_and_parse(name, argc - current_arg, argv + current_arg);
98-
}
99-
}
100-
101-
int arg_list::find_and_parse(std::string name, int argc, const char ** argv) {
102-
for (int i = 0; i < fargs.size(); i++) {
103-
if (fargs[i].full_name == name || fargs[i].abbreviation == name) {
104-
return fargs[i].parse(argc, argv);
105-
}
106-
}
107-
for (int i = 0; i < iargs.size(); i++) {
108-
if (iargs[i].full_name == name || iargs[i].abbreviation == name) {
109-
return iargs[i].parse(argc, argv);
110-
}
111-
}
112-
for (int i = 0; i < bargs.size(); i++) {
113-
if (bargs[i].full_name == name || bargs[i].abbreviation == name) {
114-
bargs[i].value = !bargs[i].value;
115-
bargs[i].required = false;
116-
return 0;
117-
}
118-
119-
}
120-
for (int i = 0; i < sargs.size(); i++) {
121-
if (sargs[i].full_name == name || sargs[i].abbreviation == name) {
122-
return sargs[i].parse(argc, argv);
123-
}
124-
}
125-
fprintf(stderr, "argument '%s' is not a valid argument. Call '--help' for information on all valid arguments.\n", name.c_str());
126-
exit(1);
127-
}
128-
129-
std::string arg_list::get_string_param(std::string full_name) {
130-
for (auto arg : sargs) {
131-
if (arg.full_name == full_name) {
132-
return arg.value;
133-
}
134-
}
135-
return "";
136-
}
137-
138-
int * arg_list::get_int_param(std::string full_name) {
139-
for (auto arg : iargs) {
140-
if (arg.full_name == full_name) {
141-
return arg.value;
142-
}
143-
}
144-
return nullptr;
145-
}
146-
147-
float * arg_list::get_float_param(std::string full_name) {
148-
for (auto arg : fargs) {
149-
if (arg.full_name == full_name) {
150-
return arg.value;
151-
}
152-
}
153-
return nullptr;
154-
}
155-
156-
bool arg_list::get_bool_param(std::string full_name) {
157-
for (auto arg : bargs) {
158-
if (arg.full_name == full_name) {
159-
return arg.value;
160-
}
161-
}
162-
return false;
163-
}
164-

examples/args.h

Lines changed: 48 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,115 +1,65 @@
1-
#ifndef args_h
2-
#define args_h
1+
#pragma once
32

4-
#include <stdio.h>
5-
#include <iostream>
3+
#include <map>
4+
#include <thread>
65
#include <vector>
76

8-
struct arg {
9-
std::string full_name;
10-
std::string abbreviation = "";
11-
std::string description = "";
12-
bool required = false;
13-
bool has_param = false;
7+
#include "imports.h"
148

15-
std::string help_text();
16-
};
17-
18-
struct bool_arg : public arg {
19-
bool_arg(std::string fn, std::string desc = "", std::string abbr = "", bool req = false, bool val = false) {
20-
full_name = fn;
21-
description = desc;
22-
abbreviation = abbr;
23-
required = req;
24-
value = val;
25-
};
26-
27-
bool value = false;
28-
};
29-
30-
struct string_arg : public arg {
31-
string_arg(std::string fn, std::string desc = "", std::string abbr = "", bool req = false, std::string val = "") {
32-
full_name = fn;
33-
description = desc;
34-
abbreviation = abbr;
35-
required = req;
36-
value = val;
37-
};
38-
bool has_param = true;
39-
std::string value;
40-
41-
int parse(int argc, const char ** argv);
42-
};
9+
/**
10+
* Holder of one argument.
11+
*/
12+
class arg {
13+
variant<bool, str, int, float> value;
14+
bool required;
4315

44-
struct int_arg : public arg {
45-
int_arg(std::string fn, std::string desc = "", std::string abbr = "", bool req = false, int * val = nullptr) {
46-
full_name = fn;
47-
description = desc;
48-
abbreviation = abbr;
49-
required = req;
50-
value = val;
51-
};
16+
void print_help() const;
5217

53-
int * value;
18+
void parse(span<str> & argv);
5419

55-
int parse(int argc, const char ** argv);
56-
57-
};
58-
59-
struct float_arg : public arg {
60-
float_arg(std::string fn, std::string desc = "", std::string abbr = "", bool req = false, float * val = nullptr) {
61-
full_name = fn;
62-
description = desc;
63-
abbreviation = abbr;
64-
required = req;
65-
value = val;
66-
};
67-
68-
bool has_param = true;
69-
float * value;
70-
71-
int parse(int argc, const char ** argv);
72-
};
20+
friend class arg_list;
7321

74-
struct arg_list {
75-
std::vector<float_arg> fargs;
76-
std::vector<int_arg> iargs;
77-
std::vector<bool_arg> bargs;
78-
std::vector<string_arg> sargs;
79-
bool for_help = false;
22+
public:
23+
const str full_name;
24+
const str abbreviation;
25+
const str description;
8026

81-
void add_argument(float_arg arg) {
82-
fargs.push_back(arg);
27+
template <typename T>
28+
constexpr arg(T default_value, str full_name, str abbreviation, str description, bool required = false)
29+
: value{default_value}, required{required},
30+
full_name{full_name}, abbreviation{abbreviation}, description{description} {
31+
TTS_ASSERT(full_name[0] != '-');
32+
TTS_ASSERT(abbreviation[0] != '-');
8333
}
8434

85-
void add_argument(int_arg arg) {
86-
iargs.push_back(arg);
87-
}
88-
89-
void add_argument(bool_arg arg) {
90-
bargs.push_back(arg);
35+
template <typename T>
36+
requires is_same_v<T, bool> || is_same_v<T, str> || is_same_v<T, int> || is_same_v<T, float>
37+
// ReSharper disable once CppNonExplicitConversionOperator // We want this to automatically cast
38+
constexpr operator T() const { // NOLINT(*-explicit-constructor)
39+
return get<T>(value);
9140
}
41+
};
9242

93-
void add_argument(string_arg arg) {
94-
sargs.push_back(arg);
43+
class arg_list {
44+
vector<arg> args{};
45+
map<sv, size_t> full_names{};
46+
map<sv, size_t> abbreviations{};
47+
48+
public:
49+
void add(const arg & x) {
50+
const size_t i{args.size()};
51+
args.push_back(x);
52+
TTS_ASSERT(!full_names.contains(args[i].full_name));
53+
full_names[args[i].full_name] = i;
54+
if (*args[i].abbreviation) {
55+
abbreviations[args[i].abbreviation] = i;
56+
}
9557
}
9658

97-
void help();
98-
99-
void validate();
100-
101-
void parse(int argc, const char ** argv);
102-
103-
int find_and_parse(std::string name, int argc, const char ** argv);
59+
void parse(int argc, str argv_[]);
10460

105-
std::string get_string_param(std::string full_name);
106-
107-
int * get_int_param(std::string full_name);
108-
109-
float * get_float_param(std::string full_name);
110-
111-
bool get_bool_param(std::string full_name);
61+
constexpr const arg & operator [](sv full_name) const noexcept {
62+
TTS_ASSERT(full_name[0] != '-');
63+
return args[full_names.at(full_name)];
64+
}
11265
};
113-
114-
#endif
115-

0 commit comments

Comments
 (0)