#![cfg(feature = "native")]
use crate::ansi_colors::Colorize;
use crate::viz;
#[derive(Debug, Clone, clap::Subcommand)]
pub enum VizCommand {
Tree {
#[arg(long)]
framework: Option<String>,
#[arg(long)]
integration: bool,
#[arg(long, default_value = "ascii")]
format: String,
},
Dashboard {
#[arg(long, default_value = "trueno-db://metrics")]
source: String,
#[arg(long, default_value = "3000")]
port: u16,
#[arg(long, default_value = "dark")]
theme: String,
#[arg(long)]
output: Option<String>,
},
}
pub fn cmd_viz(command: VizCommand) -> anyhow::Result<()> {
match command {
VizCommand::Tree { framework, integration, format } => {
cmd_viz_tree(framework.as_deref(), integration, &format)?;
}
VizCommand::Dashboard { source, port, theme, output } => {
cmd_viz_dashboard(&source, port, &theme, output.as_deref())?;
}
}
Ok(())
}
fn cmd_viz_tree(framework: Option<&str>, integration: bool, format: &str) -> anyhow::Result<()> {
use viz::tree::{
build_dash_tree, build_gradio_tree, build_integration_mappings, build_panel_tree,
build_streamlit_tree, format_all_frameworks, format_framework_tree,
format_integration_mappings,
};
if integration {
let output = match format {
"json" => {
let mappings = build_integration_mappings();
serde_json::to_string_pretty(&mappings)?
}
_ => format_integration_mappings(),
};
println!("{}", output);
} else if let Some(framework_name) = framework {
let fw = framework_name.to_lowercase();
let tree = match fw.as_str() {
"gradio" => build_gradio_tree(),
"streamlit" => build_streamlit_tree(),
"panel" => build_panel_tree(),
"dash" => build_dash_tree(),
_ => {
anyhow::bail!(
"Unknown framework: {}. Valid options: gradio, streamlit, panel, dash",
framework_name
);
}
};
let output = match format {
"json" => serde_json::to_string_pretty(&tree)?,
_ => format_framework_tree(&tree),
};
println!("{}", output);
} else {
let output = match format {
"json" => {
let trees = vec![
build_gradio_tree(),
build_streamlit_tree(),
build_panel_tree(),
build_dash_tree(),
];
serde_json::to_string_pretty(&trees)?
}
_ => format_all_frameworks(),
};
println!("{}", output);
}
Ok(())
}
fn cmd_viz_dashboard(
source: &str,
port: u16,
theme: &str,
output: Option<&str>,
) -> anyhow::Result<()> {
use std::path::Path;
let (source_type, source_path) = if let Some(rest) = source.strip_prefix("trueno-db://") {
("trueno-db", rest)
} else if let Some(rest) = source.strip_prefix("prometheus://") {
("prometheus", rest)
} else {
("file", source)
};
let config = format!(
r#"# Presentar Monitoring Dashboard
# Generated by: batuta viz dashboard
app:
name: "Realizar Monitoring"
version: "1.0.0"
port: {port}
theme: "{theme}"
data_source:
type: "{source_type}"
path: "{source_path}"
refresh_interval_ms: 1000
panels:
- id: "inference_latency"
title: "Inference Latency"
type: "timeseries"
query: |
SELECT time, p50, p95, p99
FROM realizar_metrics
WHERE metric = 'inference_latency_ms'
ORDER BY time DESC
LIMIT 100
y_axis: "Latency (ms)"
- id: "throughput"
title: "Token Throughput"
type: "gauge"
query: |
SELECT avg(tokens_per_second) as tps
FROM realizar_metrics
WHERE metric = 'throughput'
AND time > now() - interval '1 minute'
max: 1000
thresholds:
- value: 100
color: "red"
- value: 500
color: "yellow"
- value: 800
color: "green"
- id: "model_requests"
title: "Requests by Model"
type: "bar"
query: |
SELECT model_name, count(*) as requests
FROM realizar_metrics
WHERE metric = 'request_count'
GROUP BY model_name
ORDER BY requests DESC
LIMIT 10
- id: "error_rate"
title: "Error Rate"
type: "stat"
query: |
SELECT
(count(*) FILTER (WHERE status = 'error')) * 100.0 / count(*) as error_pct
FROM realizar_metrics
WHERE time > now() - interval '5 minutes'
unit: "%"
thresholds:
- value: 1
color: "green"
- value: 5
color: "yellow"
- value: 10
color: "red"
- id: "ab_tests"
title: "A/B Test Results"
type: "table"
query: |
SELECT
test_name,
variant,
requests,
success_rate,
avg_latency_ms
FROM ab_test_results
ORDER BY test_name, variant
layout:
rows:
- height: "300px"
panels: ["inference_latency", "throughput"]
- height: "250px"
panels: ["model_requests", "error_rate"]
- height: "200px"
panels: ["ab_tests"]
"#,
port = port,
theme = theme,
source_type = source_type,
source_path = source_path,
);
if let Some(output_path) = output {
std::fs::write(Path::new(output_path), &config)?;
println!("Dashboard config written to: {}", output_path);
} else {
println!("{}", config);
println!();
println!("{}", "To launch dashboard:".cyan());
println!(" presentar serve dashboard.yaml --port {}", port);
}
Ok(())
}