Files
wifi-densepose/vendor/ruvector/examples/scipix/src/cli/output.rs

224 lines
6.5 KiB
Rust

use comfy_table::{modifiers::UTF8_ROUND_CORNERS, presets::UTF8_FULL, Cell, Color, Table};
use console::style;
use super::commands::OcrResult;
/// Print a summary of a single OCR result
pub fn print_ocr_summary(result: &OcrResult) {
println!("\n{}", style("OCR Processing Summary").bold().cyan());
println!("{}", style("".repeat(60)).dim());
let mut table = Table::new();
table
.load_preset(UTF8_FULL)
.apply_modifier(UTF8_ROUND_CORNERS)
.set_header(vec![
Cell::new("Property").fg(Color::Cyan),
Cell::new("Value").fg(Color::Green),
]);
table.add_row(vec![
Cell::new("File"),
Cell::new(result.file.display().to_string()),
]);
table.add_row(vec![
Cell::new("Confidence"),
Cell::new(format!("{:.2}%", result.confidence * 100.0))
.fg(confidence_color(result.confidence)),
]);
table.add_row(vec![
Cell::new("Processing Time"),
Cell::new(format!("{}ms", result.processing_time_ms)),
]);
if let Some(latex) = &result.latex {
table.add_row(vec![
Cell::new("LaTeX"),
Cell::new(if latex.len() > 50 {
format!("{}...", &latex[..50])
} else {
latex.clone()
}),
]);
}
if !result.errors.is_empty() {
table.add_row(vec![
Cell::new("Errors").fg(Color::Red),
Cell::new(result.errors.len().to_string()).fg(Color::Red),
]);
}
println!("{table}");
if !result.errors.is_empty() {
println!("\n{}", style("Errors:").bold().red());
for (i, error) in result.errors.iter().enumerate() {
println!(" {}. {}", i + 1, style(error).red());
}
}
println!();
}
/// Print a summary of batch processing results
pub fn print_batch_summary(passed: &[OcrResult], failed: &[OcrResult], threshold: f64) {
println!("\n{}", style("Batch Processing Summary").bold().cyan());
println!("{}", style("".repeat(60)).dim());
let total = passed.len() + failed.len();
let avg_confidence = if !passed.is_empty() {
passed.iter().map(|r| r.confidence).sum::<f64>() / passed.len() as f64
} else {
0.0
};
let total_time: u64 = passed.iter().map(|r| r.processing_time_ms).sum();
let avg_time = if !passed.is_empty() {
total_time / passed.len() as u64
} else {
0
};
let mut table = Table::new();
table
.load_preset(UTF8_FULL)
.apply_modifier(UTF8_ROUND_CORNERS)
.set_header(vec![
Cell::new("Metric").fg(Color::Cyan),
Cell::new("Value").fg(Color::Green),
]);
table.add_row(vec![Cell::new("Total Files"), Cell::new(total.to_string())]);
table.add_row(vec![
Cell::new("Passed").fg(Color::Green),
Cell::new(format!(
"{} ({:.1}%)",
passed.len(),
(passed.len() as f64 / total as f64) * 100.0
))
.fg(Color::Green),
]);
table.add_row(vec![
Cell::new("Failed").fg(Color::Red),
Cell::new(format!(
"{} ({:.1}%)",
failed.len(),
(failed.len() as f64 / total as f64) * 100.0
))
.fg(if failed.is_empty() {
Color::Green
} else {
Color::Red
}),
]);
table.add_row(vec![
Cell::new("Threshold"),
Cell::new(format!("{:.2}%", threshold * 100.0)),
]);
table.add_row(vec![
Cell::new("Avg Confidence"),
Cell::new(format!("{:.2}%", avg_confidence * 100.0)).fg(confidence_color(avg_confidence)),
]);
table.add_row(vec![
Cell::new("Avg Processing Time"),
Cell::new(format!("{}ms", avg_time)),
]);
table.add_row(vec![
Cell::new("Total Processing Time"),
Cell::new(format!("{:.2}s", total_time as f64 / 1000.0)),
]);
println!("{table}");
if !failed.is_empty() {
println!("\n{}", style("Failed Files:").bold().red());
let mut failed_table = Table::new();
failed_table
.load_preset(UTF8_FULL)
.apply_modifier(UTF8_ROUND_CORNERS)
.set_header(vec![
Cell::new("#").fg(Color::Cyan),
Cell::new("File").fg(Color::Cyan),
Cell::new("Confidence").fg(Color::Cyan),
]);
for (i, result) in failed.iter().enumerate() {
failed_table.add_row(vec![
Cell::new((i + 1).to_string()),
Cell::new(result.file.display().to_string()),
Cell::new(format!("{:.2}%", result.confidence * 100.0)).fg(Color::Red),
]);
}
println!("{failed_table}");
}
// Summary statistics
println!("\n{}", style("Statistics:").bold().cyan());
if !passed.is_empty() {
let confidences: Vec<f64> = passed.iter().map(|r| r.confidence).collect();
let min_confidence = confidences.iter().cloned().fold(f64::INFINITY, f64::min);
let max_confidence = confidences
.iter()
.cloned()
.fold(f64::NEG_INFINITY, f64::max);
println!(
" Min confidence: {}",
style(format!("{:.2}%", min_confidence * 100.0)).green()
);
println!(
" Max confidence: {}",
style(format!("{:.2}%", max_confidence * 100.0)).green()
);
let times: Vec<u64> = passed.iter().map(|r| r.processing_time_ms).collect();
let min_time = times.iter().min().unwrap_or(&0);
let max_time = times.iter().max().unwrap_or(&0);
println!(" Min processing time: {}ms", style(min_time).cyan());
println!(" Max processing time: {}ms", style(max_time).cyan());
}
println!();
}
/// Get color based on confidence value
fn confidence_color(confidence: f64) -> Color {
if confidence >= 0.9 {
Color::Green
} else if confidence >= 0.7 {
Color::Yellow
} else {
Color::Red
}
}
/// Create a progress bar style for batch processing
pub fn create_progress_style() -> indicatif::ProgressStyle {
indicatif::ProgressStyle::default_bar()
.template(
"{spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] {pos}/{len} ({eta}) {msg}",
)
.unwrap()
.progress_chars("█▓▒░ ")
}
/// Create a spinner style for individual file processing
pub fn create_spinner_style() -> indicatif::ProgressStyle {
indicatif::ProgressStyle::default_spinner()
.template("{spinner:.cyan} {msg}")
.unwrap()
.tick_chars("⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏")
}