use anyhow::Result;
use diffx_core::format_diff_output;
use crate::types::{DiffResult, OutputFormat};
pub fn format_output(results: &[DiffResult], format: OutputFormat) -> Result<String> {
format_diff_results(results, format)
}
pub fn format_diff_results(results: &[DiffResult], format: OutputFormat) -> Result<String> {
match format {
OutputFormat::Json => {
Ok(serde_json::to_string_pretty(results)?)
}
OutputFormat::Yaml => {
Ok(serde_yaml::to_string(results)?)
}
OutputFormat::Diffai => {
let base_results: Vec<diffx_core::DiffResult> = results
.iter()
.filter_map(|r| match r {
DiffResult::Added(path, value) => {
Some(diffx_core::DiffResult::Added(path.clone(), value.clone()))
}
DiffResult::Removed(path, value) => {
Some(diffx_core::DiffResult::Removed(path.clone(), value.clone()))
}
DiffResult::Modified(path, old, new) => Some(diffx_core::DiffResult::Modified(
path.clone(),
old.clone(),
new.clone(),
)),
DiffResult::TypeChanged(path, old, new) => Some(
diffx_core::DiffResult::TypeChanged(path.clone(), old.clone(), new.clone()),
),
_ => None,
})
.collect();
let mut output = String::new();
if !base_results.is_empty() {
let base_format = format.to_base_format();
let formatted = format_diff_output(&base_results, base_format, None)?;
output.push_str(&formatted);
}
let ml_results: Vec<&DiffResult> = results
.iter()
.filter(|r| {
match r {
DiffResult::TensorStatsChanged(path, _, _) => {
!path.contains("data_summary")
}
DiffResult::TensorShapeChanged(_, _, _)
| DiffResult::TensorDataChanged(_, _, _)
| DiffResult::ModelArchitectureChanged(_, _, _)
| DiffResult::WeightSignificantChange(_, _)
| DiffResult::ActivationFunctionChanged(_, _, _)
| DiffResult::LearningRateChanged(_, _, _)
| DiffResult::OptimizerChanged(_, _, _)
| DiffResult::LossChange(_, _, _)
| DiffResult::AccuracyChange(_, _, _)
| DiffResult::ModelVersionChanged(_, _, _) => true,
_ => false,
}
})
.collect();
if !ml_results.is_empty() {
if !output.is_empty() && !output.ends_with('\n') {
output.push('\n');
}
output.push('\n');
for result in &ml_results {
match result {
DiffResult::ModelArchitectureChanged(path, old, new) => {
output.push_str(&format!(" ~ {path}: {old} -> {new}\n"));
}
DiffResult::TensorShapeChanged(path, old_shape, new_shape) => {
output.push_str(&format!(
" ~ {path} shape: {old_shape:?} -> {new_shape:?}\n"
));
}
DiffResult::TensorStatsChanged(path, old_stats, new_stats) => {
output.push_str(&format!(
" ~ {} stats: mean {:.3} -> {:.3}\n",
path, old_stats.mean, new_stats.mean
));
}
_ => {
output.push_str(&format!(
" ~ ML analysis: {}\n",
serde_json::to_string(result)?
));
}
}
}
}
Ok(output)
}
}
}