mirror of
https://github.com/aaronpo97/the-biergarten-app.git
synced 2026-10-15 01:54:43 +00:00
Formatted src/application_options
This commit is contained in:
@@ -10,207 +10,212 @@
|
|||||||
|
|
||||||
std::optional<ApplicationOptions> ParseArguments(
|
std::optional<ApplicationOptions> ParseArguments(
|
||||||
const int argc, char** argv, std::shared_ptr<ILogger> logger) {
|
const int argc, char** argv, std::shared_ptr<ILogger> logger) {
|
||||||
prog_opts::options_description desc("Pipeline Options");
|
prog_opts::options_description desc("Pipeline Options");
|
||||||
auto opt = desc.add_options();
|
auto opt = desc.add_options();
|
||||||
|
|
||||||
opt("help,h", "Produce help message");
|
opt("help,h", "Produce help message");
|
||||||
|
|
||||||
auto add_sampling_options = [&]() -> void {
|
auto add_sampling_options = [&]() -> void {
|
||||||
const SamplingOptions sampling_defaults{};
|
const SamplingOptions sampling_defaults{};
|
||||||
opt("temperature",
|
opt("temperature",
|
||||||
prog_opts::value<float>()->default_value(sampling_defaults.temperature),
|
prog_opts::value<float>()->default_value(
|
||||||
"Sampling temperature (higher = more random)");
|
sampling_defaults.temperature),
|
||||||
opt("top-p",
|
"Sampling temperature (higher = more random)");
|
||||||
prog_opts::value<float>()->default_value(sampling_defaults.top_p),
|
opt("top-p",
|
||||||
"Nucleus sampling top-p in (0,1] (higher = more random)");
|
prog_opts::value<float>()->default_value(sampling_defaults.top_p),
|
||||||
opt("top-k",
|
"Nucleus sampling top-p in (0,1] (higher = more random)");
|
||||||
prog_opts::value<uint32_t>()->default_value(sampling_defaults.top_k),
|
opt("top-k",
|
||||||
"Top-k sampling parameter (higher = more candidate tokens)");
|
prog_opts::value<uint32_t>()->default_value(sampling_defaults.top_k),
|
||||||
opt("n-ctx",
|
"Top-k sampling parameter (higher = more candidate tokens)");
|
||||||
prog_opts::value<uint32_t>()->default_value(sampling_defaults.n_ctx),
|
opt("n-ctx",
|
||||||
"Context window size in tokens");
|
prog_opts::value<uint32_t>()->default_value(sampling_defaults.n_ctx),
|
||||||
opt("seed", prog_opts::value<int>()->default_value(sampling_defaults.seed),
|
"Context window size in tokens");
|
||||||
"Sampler seed: -1 for random, otherwise non-negative integer");
|
opt("seed",
|
||||||
opt("n-gpu-layers", prog_opts::value<int>()->default_value(0),
|
prog_opts::value<int>()->default_value(sampling_defaults.seed),
|
||||||
"Number of layers to offload to GPU");
|
"Sampler seed: -1 for random, otherwise non-negative integer");
|
||||||
};
|
opt("n-gpu-layers", prog_opts::value<int>()->default_value(0),
|
||||||
|
"Number of layers to offload to GPU");
|
||||||
|
};
|
||||||
|
|
||||||
// --mocked and --model are mutually exclusive; validation is enforced below
|
// --mocked and --model are mutually exclusive; validation is enforced below
|
||||||
// rather than at registration to produce a clear diagnostic message.
|
// rather than at registration to produce a clear diagnostic message.
|
||||||
auto add_generator_options = [&]() -> void {
|
auto add_generator_options = [&]() -> void {
|
||||||
opt("mocked", prog_opts::bool_switch(),
|
opt("mocked", prog_opts::bool_switch(),
|
||||||
"Use mocked generator for brewery/user data");
|
"Use mocked generator for brewery/user data");
|
||||||
opt("model,m", prog_opts::value<std::string>()->default_value(""),
|
opt("model,m", prog_opts::value<std::string>()->default_value(""),
|
||||||
"Path to LLM model (gguf)");
|
"Path to LLM model (gguf)");
|
||||||
};
|
};
|
||||||
|
|
||||||
auto add_pipeline_options = [&]() -> void {
|
auto add_pipeline_options = [&]() -> void {
|
||||||
opt("output,o", prog_opts::value<std::string>()->default_value("output"),
|
opt("output,o", prog_opts::value<std::string>()->default_value("output"),
|
||||||
"Directory for generated artifacts");
|
"Directory for generated artifacts");
|
||||||
opt("log-path",
|
opt("log-path",
|
||||||
prog_opts::value<std::string>()->default_value("pipeline.log"),
|
prog_opts::value<std::string>()->default_value("pipeline.log"),
|
||||||
"Path for application logs");
|
"Path for application logs");
|
||||||
opt("prompt-dir", prog_opts::value<std::string>()->default_value(""),
|
opt("prompt-dir", prog_opts::value<std::string>()->default_value(""),
|
||||||
"Directory containing named prompt files (e.g. "
|
"Directory containing named prompt files (e.g. "
|
||||||
"BREWERY_GENERATION.md)."
|
"BREWERY_GENERATION.md)."
|
||||||
" Required when not using --mocked.");
|
" Required when not using --mocked.");
|
||||||
opt("location-count", prog_opts::value<uint32_t>()->default_value(10));
|
opt("location-count", prog_opts::value<uint32_t>()->default_value(10));
|
||||||
};
|
};
|
||||||
|
|
||||||
add_sampling_options();
|
add_sampling_options();
|
||||||
add_generator_options();
|
add_generator_options();
|
||||||
add_pipeline_options();
|
add_pipeline_options();
|
||||||
|
|
||||||
// No flags provided — treat as a help request rather than an error.
|
// No flags provided — treat as a help request rather than an error.
|
||||||
if (argc == 1) {
|
if (argc == 1) {
|
||||||
const std::string title = "Biergarten Pipeline";
|
const std::string title = "Biergarten Pipeline";
|
||||||
const std::string usage = ([&] {
|
const std::string usage = ([&] {
|
||||||
std::stringstream usage_stream;
|
std::stringstream usage_stream;
|
||||||
usage_stream << "\nUsage: biergarten-pipeline [options]\n\n" << desc;
|
usage_stream << "\nUsage: biergarten-pipeline [options]\n\n" << desc;
|
||||||
return usage_stream.str();
|
return usage_stream.str();
|
||||||
})();
|
})();
|
||||||
if (logger) {
|
|
||||||
logger->Log(LogDTO{.level = LogLevel::Info,
|
|
||||||
.phase = PipelinePhase::Startup,
|
|
||||||
.message = title});
|
|
||||||
logger->Log(LogDTO{.level = LogLevel::Info,
|
|
||||||
.phase = PipelinePhase::Startup,
|
|
||||||
.message = usage});
|
|
||||||
}
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
prog_opts::variables_map var_map;
|
|
||||||
prog_opts::store(prog_opts::parse_command_line(argc, argv, desc), var_map);
|
|
||||||
prog_opts::notify(var_map);
|
|
||||||
|
|
||||||
if (var_map.contains("help")) {
|
|
||||||
std::stringstream help_stream;
|
|
||||||
help_stream << "\n" << desc;
|
|
||||||
if (logger) {
|
if (logger) {
|
||||||
logger->Log(LogDTO{.level = LogLevel::Info,
|
logger->Log(LogDTO{.level = LogLevel::Info,
|
||||||
.phase = PipelinePhase::Startup,
|
.phase = PipelinePhase::Startup,
|
||||||
.message = help_stream.str()});
|
.message = title});
|
||||||
|
logger->Log(LogDTO{.level = LogLevel::Info,
|
||||||
|
.phase = PipelinePhase::Startup,
|
||||||
|
.message = usage});
|
||||||
}
|
}
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
ApplicationOptions options;
|
try {
|
||||||
|
prog_opts::variables_map var_map;
|
||||||
|
prog_opts::store(prog_opts::parse_command_line(argc, argv, desc),
|
||||||
|
var_map);
|
||||||
|
prog_opts::notify(var_map);
|
||||||
|
|
||||||
options.pipeline.output_path = var_map["output"].as<std::string>();
|
if (var_map.contains("help")) {
|
||||||
options.pipeline.log_path = var_map["log-path"].as<std::string>();
|
std::stringstream help_stream;
|
||||||
options.pipeline.prompt_dir = var_map["prompt-dir"].as<std::string>();
|
help_stream << "\n" << desc;
|
||||||
options.pipeline.location_count = var_map["location-count"].as<uint32_t>();
|
if (logger) {
|
||||||
|
logger->Log(LogDTO{.level = LogLevel::Info,
|
||||||
const bool use_mocked = var_map["mocked"].as<bool>();
|
.phase = PipelinePhase::Startup,
|
||||||
const std::string model_path = var_map["model"].as<std::string>();
|
.message = help_stream.str()});
|
||||||
const int n_gpu_layers = var_map["n-gpu-layers"].as<int>();
|
}
|
||||||
|
return std::nullopt;
|
||||||
// Enforce mutual exclusivity before any further configuration is
|
|
||||||
// applied.
|
|
||||||
if (use_mocked && !model_path.empty()) {
|
|
||||||
const std::string msg =
|
|
||||||
"Invalid arguments: --mocked and --model are mutually "
|
|
||||||
"exclusive";
|
|
||||||
if (logger) {
|
|
||||||
logger->Log(LogDTO{.level = LogLevel::Error,
|
|
||||||
.phase = PipelinePhase::Startup,
|
|
||||||
.message = msg});
|
|
||||||
} else {
|
|
||||||
std::cerr << msg << std::endl;
|
|
||||||
}
|
}
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!use_mocked && model_path.empty()) {
|
ApplicationOptions options;
|
||||||
const std::string msg =
|
|
||||||
"Invalid arguments: either --mocked or --model must be "
|
options.pipeline.output_path = var_map["output"].as<std::string>();
|
||||||
"specified";
|
options.pipeline.log_path = var_map["log-path"].as<std::string>();
|
||||||
if (logger) {
|
options.pipeline.prompt_dir = var_map["prompt-dir"].as<std::string>();
|
||||||
logger->Log(LogDTO{.level = LogLevel::Error,
|
options.pipeline.location_count =
|
||||||
.phase = PipelinePhase::Startup,
|
var_map["location-count"].as<uint32_t>();
|
||||||
.message = msg});
|
|
||||||
} else {
|
const bool use_mocked = var_map["mocked"].as<bool>();
|
||||||
std::cerr << msg << std::endl;
|
const std::string model_path = var_map["model"].as<std::string>();
|
||||||
|
const int n_gpu_layers = var_map["n-gpu-layers"].as<int>();
|
||||||
|
|
||||||
|
// Enforce mutual exclusivity before any further configuration is
|
||||||
|
// applied.
|
||||||
|
if (use_mocked && !model_path.empty()) {
|
||||||
|
const std::string msg =
|
||||||
|
"Invalid arguments: --mocked and --model are mutually "
|
||||||
|
"exclusive";
|
||||||
|
if (logger) {
|
||||||
|
logger->Log(LogDTO{.level = LogLevel::Error,
|
||||||
|
.phase = PipelinePhase::Startup,
|
||||||
|
.message = msg});
|
||||||
|
} else {
|
||||||
|
std::cerr << msg << std::endl;
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prompt directory is only meaningful for live inference — the mock
|
if (!use_mocked && model_path.empty()) {
|
||||||
// generator has no use for it and should not require it to be present.
|
const std::string msg =
|
||||||
if (!use_mocked && options.pipeline.prompt_dir.empty()) {
|
"Invalid arguments: either --mocked or --model must be "
|
||||||
const std::string msg =
|
"specified";
|
||||||
"Invalid arguments: --prompt-dir is required when not using "
|
if (logger) {
|
||||||
"--mocked";
|
logger->Log(LogDTO{.level = LogLevel::Error,
|
||||||
if (logger) {
|
.phase = PipelinePhase::Startup,
|
||||||
logger->Log({.level = LogLevel::Error,
|
.message = msg});
|
||||||
.phase = PipelinePhase::Startup,
|
} else {
|
||||||
.message = msg});
|
std::cerr << msg << std::endl;
|
||||||
} else {
|
}
|
||||||
std::cerr << msg << std::endl;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
options.generator.use_mocked = use_mocked;
|
// Prompt directory is only meaningful for live inference — the mock
|
||||||
options.generator.model_path = model_path;
|
// generator has no use for it and should not require it to be present.
|
||||||
|
if (!use_mocked && options.pipeline.prompt_dir.empty()) {
|
||||||
// Only populate sampling config when the user explicitly overrides at
|
const std::string msg =
|
||||||
// least one value. Leaving it as std::nullopt lets LlamaGenerator fall
|
"Invalid arguments: --prompt-dir is required when not using "
|
||||||
// back to its own SamplingOptions{} defaults, keeping the two paths
|
"--mocked";
|
||||||
// consistent without redundant copies.
|
if (logger) {
|
||||||
const bool user_provided_sampling =
|
logger->Log({.level = LogLevel::Error,
|
||||||
!var_map["temperature"].defaulted() || !var_map["top-p"].defaulted() ||
|
|
||||||
!var_map["top-k"].defaulted() || !var_map["n-ctx"].defaulted() ||
|
|
||||||
!var_map["seed"].defaulted() || !var_map["n_gpu_layers"].defaulted();
|
|
||||||
|
|
||||||
if (user_provided_sampling) {
|
|
||||||
// Warn but do not fail — the run is still valid, the flags are just
|
|
||||||
// silently irrelevant when no model is loaded.
|
|
||||||
if (use_mocked) {
|
|
||||||
const std::string msg =
|
|
||||||
"Sampling parameters are ignored when using --mocked";
|
|
||||||
if (logger) {
|
|
||||||
logger->Log(LogDTO{.level = LogLevel::Warn,
|
|
||||||
.phase = PipelinePhase::Startup,
|
|
||||||
.message = msg});
|
|
||||||
} else {
|
|
||||||
std::cerr << msg << std::endl;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
SamplingOptions sampling;
|
|
||||||
sampling.temperature = var_map["temperature"].as<float>();
|
|
||||||
sampling.top_p = var_map["top-p"].as<float>();
|
|
||||||
sampling.top_k = var_map["top-k"].as<uint32_t>();
|
|
||||||
sampling.n_ctx = var_map["n-ctx"].as<uint32_t>();
|
|
||||||
sampling.seed = var_map["seed"].as<int>();
|
|
||||||
sampling.n_gpu_layers = var_map["n-gpu-layers"].as<int>();
|
|
||||||
|
|
||||||
options.generator.sampling = sampling;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return options;
|
|
||||||
|
|
||||||
} catch (const std::exception& exception) {
|
|
||||||
const std::string msg =
|
|
||||||
std::string("Failed to parse command-line arguments: ") +
|
|
||||||
exception.what();
|
|
||||||
if (logger) {
|
|
||||||
logger->Log(LogDTO{.level = LogLevel::Error,
|
|
||||||
.phase = PipelinePhase::Startup,
|
.phase = PipelinePhase::Startup,
|
||||||
.message = msg});
|
.message = msg});
|
||||||
}
|
} else {
|
||||||
return std::nullopt;
|
std::cerr << msg << std::endl;
|
||||||
} catch (...) {
|
}
|
||||||
const std::string msg =
|
return std::nullopt;
|
||||||
"Failed to parse command-line arguments: unknown error";
|
}
|
||||||
if (logger) {
|
|
||||||
logger->Log(LogDTO{.level = LogLevel::Error,
|
options.generator.use_mocked = use_mocked;
|
||||||
.phase = PipelinePhase::Startup,
|
options.generator.model_path = model_path;
|
||||||
.message = msg});
|
|
||||||
}
|
// Only populate sampling config when the user explicitly overrides at
|
||||||
return std::nullopt;
|
// least one value. Leaving it as std::nullopt lets LlamaGenerator fall
|
||||||
}
|
// back to its own SamplingOptions{} defaults, keeping the two paths
|
||||||
|
// consistent without redundant copies.
|
||||||
|
const bool user_provided_sampling =
|
||||||
|
!var_map["temperature"].defaulted() ||
|
||||||
|
!var_map["top-p"].defaulted() || !var_map["top-k"].defaulted() ||
|
||||||
|
!var_map["n-ctx"].defaulted() || !var_map["seed"].defaulted() ||
|
||||||
|
!var_map["n_gpu_layers"].defaulted();
|
||||||
|
|
||||||
|
if (user_provided_sampling) {
|
||||||
|
// Warn but do not fail — the run is still valid, the flags are just
|
||||||
|
// silently irrelevant when no model is loaded.
|
||||||
|
if (use_mocked) {
|
||||||
|
const std::string msg =
|
||||||
|
"Sampling parameters are ignored when using --mocked";
|
||||||
|
if (logger) {
|
||||||
|
logger->Log(LogDTO{.level = LogLevel::Warn,
|
||||||
|
.phase = PipelinePhase::Startup,
|
||||||
|
.message = msg});
|
||||||
|
} else {
|
||||||
|
std::cerr << msg << std::endl;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
SamplingOptions sampling;
|
||||||
|
sampling.temperature = var_map["temperature"].as<float>();
|
||||||
|
sampling.top_p = var_map["top-p"].as<float>();
|
||||||
|
sampling.top_k = var_map["top-k"].as<uint32_t>();
|
||||||
|
sampling.n_ctx = var_map["n-ctx"].as<uint32_t>();
|
||||||
|
sampling.seed = var_map["seed"].as<int>();
|
||||||
|
sampling.n_gpu_layers = var_map["n-gpu-layers"].as<int>();
|
||||||
|
|
||||||
|
options.generator.sampling = sampling;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return options;
|
||||||
|
|
||||||
|
} catch (const std::exception& exception) {
|
||||||
|
const std::string msg =
|
||||||
|
std::string("Failed to parse command-line arguments: ") +
|
||||||
|
exception.what();
|
||||||
|
if (logger) {
|
||||||
|
logger->Log(LogDTO{.level = LogLevel::Error,
|
||||||
|
.phase = PipelinePhase::Startup,
|
||||||
|
.message = msg});
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
} catch (...) {
|
||||||
|
const std::string msg =
|
||||||
|
"Failed to parse command-line arguments: unknown error";
|
||||||
|
if (logger) {
|
||||||
|
logger->Log(LogDTO{.level = LogLevel::Error,
|
||||||
|
.phase = PipelinePhase::Startup,
|
||||||
|
.message = msg});
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user