use std::io::{self, Write};
use comfy_table::{Cell, Color, ContentArrangement, Table};
use console::style;
pub fn print_table(headers: &[&str], rows: Vec<Vec<String>>) {
let mut table = Table::new();
table.set_content_arrangement(ContentArrangement::Dynamic);
table.set_header(headers.iter().map(|h| Cell::new(h).fg(Color::Cyan)));
for row in rows {
table.add_row(row);
}
println!("{table}");
}
pub fn print_info_block(title: &str, items: &[(&str, String)]) {
println!("{}", style(title).bold().underlined());
for (key, value) in items {
println!(" {}: {}", style(key).dim(), value);
}
println!();
}
pub fn print_section(title: &str) {
println!("\n{}", style(title).bold().cyan());
println!("{}", style("─".repeat(title.len())).dim());
}
pub fn print_model_summary(
model_type: &str,
vocab_size: usize,
ngram_count: Option<u64>,
embedding_dim: Option<usize>,
) {
println!("{}", style("Model Summary").bold().underlined());
println!(" Type: {}", model_type);
println!(" Vocab size: {}", vocab_size);
if let Some(count) = ngram_count {
println!(" N-grams: {}", count);
}
if let Some(dim) = embedding_dim {
println!(" Embed dim: {}", dim);
}
println!();
}
pub fn print_perplexity_results(
model_path: &str,
corpus_path: &str,
sentences: u64,
tokens: u64,
perplexity: f64,
log_prob: f64,
oov_rate: f64,
) {
println!("{}", style("Perplexity Evaluation").bold().underlined());
println!();
println!(" Model: {}", model_path);
println!(
" Test corpus: {} ({} sentences, {} tokens)",
corpus_path, sentences, tokens
);
println!();
println!(
" Perplexity: {}",
style(format!("{:.2}", perplexity)).bold()
);
println!(" Log probability: {:.2}", log_prob);
println!(" OOV rate: {:.2}%", oov_rate * 100.0);
println!(" Avg tokens/sent: {:.2}", tokens as f64 / sentences as f64);
println!();
}
pub fn print_comparison_table(results: Vec<ModelComparisonResult>) {
let headers = &["Model", "Perplexity", "OOV Rate", "Time (s)"];
let rows: Vec<Vec<String>> = results
.iter()
.map(|r| {
vec![
r.model_name.clone(),
format!("{:.2}", r.perplexity),
format!("{:.2}%", r.oov_rate * 100.0),
format!("{:.2}", r.eval_time_secs),
]
})
.collect();
print_table(headers, rows);
}
pub struct ModelComparisonResult {
pub model_name: String,
pub perplexity: f64,
pub oov_rate: f64,
pub eval_time_secs: f64,
}
pub fn print_similar_words(word: &str, similar: &[(String, f64)]) {
println!("Similar to \"{}\":", style(word).bold());
for (i, (w, score)) in similar.iter().enumerate() {
println!(" {}. {:<15} {:.4}", i + 1, w, score);
}
}
pub fn print_completions(context: &[String], completions: &[(String, f64)]) {
println!(
"Top completions for \"{}\":",
style(context.join(" ")).bold()
);
for (i, (word, log_prob)) in completions.iter().enumerate() {
let prob = log_prob.exp();
println!(" {}. {:<15} {:.3} (P={:.4})", i + 1, word, log_prob, prob);
}
}
pub fn print_score(tokens: &[String], log_prob: f64, is_sentence: bool) {
let label = if is_sentence {
"Sentence"
} else {
"Continuation"
};
println!("{} \"{}\":", label, tokens.join(" "));
println!(" Log probability: {:.4}", log_prob);
println!(
" Perplexity: {:.2}",
(-log_prob / tokens.len() as f64).exp()
);
}
pub fn print_json<T: serde::Serialize>(value: &T) -> io::Result<()> {
let json = serde_json::to_string_pretty(value)
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
println!("{}", json);
Ok(())
}
pub fn print_corpus_stats(
path: &str,
format: &str,
documents: u64,
sentences: u64,
tokens: u64,
unique_words: u64,
top_words: &[(String, u64)],
) {
println!("{}", style("Corpus Statistics").bold().underlined());
println!();
println!(" Path: {}", path);
println!(" Format: {}", format);
println!();
println!(" Documents: {}", documents);
println!(" Sentences: {}", sentences);
println!(" Tokens: {}", tokens);
println!(" Unique words: {}", unique_words);
println!();
if !top_words.is_empty() {
println!(" Top {} words:", top_words.len());
for (i, (word, count)) in top_words.iter().enumerate() {
let pct = *count as f64 / tokens as f64 * 100.0;
println!(" {}. {:<15} {:>8} ({:.2}%)", i + 1, word, count, pct);
}
}
}
pub fn flush_stdout() -> io::Result<()> {
io::stdout().flush()
}