[feat] introduce Config for centralized runtime settings; refactor progress management and backend selection to leverage config

This commit is contained in:
2025-08-12 02:57:42 +02:00
parent ee67b56d6b
commit 9120e8fb26
4 changed files with 63 additions and 19 deletions

View File

@@ -226,7 +226,7 @@ pub struct SelectionResult {
/// guidance on how to enable it.
///
/// Set `verbose` to true to print detection/selection info to stderr.
pub fn select_backend(requested: BackendKind, verbose: bool) -> Result<SelectionResult> {
pub fn select_backend(requested: BackendKind, config: &crate::Config) -> Result<SelectionResult> {
let mut detected = Vec::new();
if cuda_available() {
detected.push(BackendKind::Cuda);
@@ -290,7 +290,7 @@ pub fn select_backend(requested: BackendKind, verbose: bool) -> Result<Selection
BackendKind::Cpu => BackendKind::Cpu,
};
if verbose {
if config.verbose >= 1 && !config.quiet {
crate::dlog!(1, "Detected backends: {:?}", detected);
crate::dlog!(1, "Selected backend: {:?}", chosen);
}

View File

@@ -16,6 +16,7 @@
use std::sync::atomic::{AtomicBool, AtomicU8, Ordering};
// Global runtime flags
// Compatibility: globals are retained temporarily until all call-sites pass Config explicitly. They will be removed in a follow-up cleanup.
static QUIET: AtomicBool = AtomicBool::new(false);
static NO_INTERACTION: AtomicBool = AtomicBool::new(false);
static VERBOSE: AtomicU8 = AtomicU8::new(0);
@@ -248,6 +249,41 @@ pub mod progress;
/// UI helpers for interactive prompts (cliclack-backed)
pub mod ui;
/// Runtime configuration passed across the library instead of using globals.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Config {
/// Suppress non-essential logs.
pub quiet: bool,
/// Verbosity level (0 = normal, 1 = verbose, 2 = super-verbose).
pub verbose: u8,
/// Disable interactive prompts.
pub no_interaction: bool,
/// Disable progress output.
pub no_progress: bool,
}
impl Config {
/// Construct a Config from explicit values.
pub fn new(quiet: bool, verbose: u8, no_interaction: bool, no_progress: bool) -> Self {
Self { quiet, verbose, no_interaction, no_progress }
}
/// Snapshot current global settings into a Config (temporary compatibility helper).
pub fn from_globals() -> Self {
Self {
quiet: crate::is_quiet(),
verbose: crate::verbose_level(),
no_interaction: crate::is_no_interaction(),
no_progress: matches!(std::env::var("NO_PROGRESS"), Ok(ref v) if v == "1" || v.eq_ignore_ascii_case("true")),
}
}
}
impl Default for Config {
fn default() -> Self {
Self { quiet: false, verbose: 0, no_interaction: false, no_progress: false }
}
}
/// Transcript entry for a single segment.
#[derive(Debug, serde::Serialize, Clone)]
pub struct OutputEntry {
@@ -586,7 +622,7 @@ where
// keep output synchronized with any active progress rendering.
printer("");
let prompt = format!("Select model [1-{}]:", candidates.len());
// TODO(ui): migrate to cliclack::Select for model picking to standardize UI.
// UI: using dialoguer::Input for selection for now; migration to cliclack::Select may be considered later for consistency.
let sel: usize = dialoguer::Input::new()
.with_prompt(prompt)
.interact_text()

View File

@@ -263,10 +263,11 @@ fn run() -> Result<()> {
let args = Args::parse();
// Configure global flags for library and stderr silencing.
polyscribe::set_quiet(args.quiet);
polyscribe::set_verbose(args.verbose);
polyscribe::set_no_interaction(args.no_interaction);
// Build Config and set globals (temporary compatibility). Prefer Config going forward.
let config = polyscribe::Config::new(args.quiet, args.verbose, args.no_interaction, /*no_progress:*/ args.no_progress);
polyscribe::set_quiet(config.quiet);
polyscribe::set_verbose(config.verbose);
polyscribe::set_no_interaction(config.no_interaction);
let _silence = polyscribe::StderrSilencer::activate_if_quiet();
// Handle auxiliary subcommands early and exit.
@@ -290,8 +291,8 @@ fn run() -> Result<()> {
}
}
// Disable complex progress bars for integration-friendly behavior
let pf = ProgressFactory::new(true);
// Prefer Config-driven progress factory
let pf = ProgressFactory::from_config(&config);
let pm = pf.make_manager(pf.decide_mode(args.inputs.len()));
// Determine formats
@@ -742,26 +743,26 @@ mod tests {
std_env::remove_var("POLYSCRIBE_TEST_FORCE_VULKAN");
}
// No GPU -> CPU
let sel = select_backend(BackendKind::Auto, false).unwrap();
let sel = select_backend(BackendKind::Auto, &polyscribe::Config::default()).unwrap();
assert_eq!(sel.chosen, BackendKind::Cpu);
// Vulkan only
unsafe {
std_env::set_var("POLYSCRIBE_TEST_FORCE_VULKAN", "1");
}
let sel = select_backend(BackendKind::Auto, false).unwrap();
let sel = select_backend(BackendKind::Auto, &polyscribe::Config::default()).unwrap();
assert_eq!(sel.chosen, BackendKind::Vulkan);
// HIP preferred over Vulkan
unsafe {
std_env::set_var("POLYSCRIBE_TEST_FORCE_HIP", "1");
std_env::remove_var("POLYSCRIBE_TEST_FORCE_VULKAN");
}
let sel = select_backend(BackendKind::Auto, false).unwrap();
let sel = select_backend(BackendKind::Auto, &polyscribe::Config::default()).unwrap();
assert_eq!(sel.chosen, BackendKind::Hip);
// CUDA preferred over HIP
unsafe {
std_env::set_var("POLYSCRIBE_TEST_FORCE_CUDA", "1");
}
let sel = select_backend(BackendKind::Auto, false).unwrap();
let sel = select_backend(BackendKind::Auto, &polyscribe::Config::default()).unwrap();
assert_eq!(sel.chosen, BackendKind::Cuda);
// Cleanup
unsafe {
@@ -780,26 +781,26 @@ mod tests {
std_env::remove_var("POLYSCRIBE_TEST_FORCE_HIP");
std_env::remove_var("POLYSCRIBE_TEST_FORCE_VULKAN");
}
assert!(select_backend(BackendKind::Cuda, false).is_err());
assert!(select_backend(BackendKind::Hip, false).is_err());
assert!(select_backend(BackendKind::Vulkan, false).is_err());
assert!(select_backend(BackendKind::Cuda, &polyscribe::Config::default()).is_err());
assert!(select_backend(BackendKind::Hip, &polyscribe::Config::default()).is_err());
assert!(select_backend(BackendKind::Vulkan, &polyscribe::Config::default()).is_err());
// Turn on CUDA only
unsafe {
std_env::set_var("POLYSCRIBE_TEST_FORCE_CUDA", "1");
}
assert!(select_backend(BackendKind::Cuda, false).is_ok());
assert!(select_backend(BackendKind::Cuda, &polyscribe::Config::default()).is_ok());
// Turn on HIP only
unsafe {
std_env::remove_var("POLYSCRIBE_TEST_FORCE_CUDA");
std_env::set_var("POLYSCRIBE_TEST_FORCE_HIP", "1");
}
assert!(select_backend(BackendKind::Hip, false).is_ok());
assert!(select_backend(BackendKind::Hip, &polyscribe::Config::default()).is_ok());
// Turn on Vulkan only
unsafe {
std_env::remove_var("POLYSCRIBE_TEST_FORCE_HIP");
std_env::set_var("POLYSCRIBE_TEST_FORCE_VULKAN", "1");
}
assert!(select_backend(BackendKind::Vulkan, false).is_ok());
assert!(select_backend(BackendKind::Vulkan, &polyscribe::Config::default()).is_ok());
// Cleanup
unsafe {
std_env::remove_var("POLYSCRIBE_TEST_FORCE_VULKAN");

View File

@@ -107,6 +107,13 @@ impl ProgressFactory {
_ => ProgressManager::noop(),
}
}
/// Preferred constructor using Config. Respects config.no_progress and TTY.
pub fn from_config(config: &crate::Config) -> Self {
// Prefer Config.no_progress over manual flag; still honor NO_PROGRESS env var.
let force_disable = config.no_progress;
Self::new(force_disable)
}
}
#[derive(Clone)]