systemprompt_cli/commands/analytics/requests/
mod.rs1mod list;
12mod models;
13mod stats;
14mod trends;
15
16use anyhow::Result;
17use clap::{Args, Subcommand};
18use schemars::JsonSchema;
19use serde::{Deserialize, Serialize};
20
21use crate::context::CommandContext;
22use crate::shared::render_result;
23
24#[derive(Debug, Args)]
30pub struct RequestsArgs {
31 #[command(subcommand)]
32 pub cmd: Option<RequestsCommands>,
33
34 #[command(flatten)]
35 pub stats: stats::StatsArgs,
36}
37
38#[derive(Debug, Subcommand)]
39pub enum RequestsCommands {
40 #[command(
41 about = "Dashboard request metrics: time range, model filter, cache-hit rate, CSV export. For a quick operational aggregate, use `infra logs request stats`"
42 )]
43 Stats(stats::StatsArgs),
44
45 #[command(
46 about = "Dashboard list of AI requests with time range, model filter, and CSV export. For a quick operational list, use `infra logs request list`"
47 )]
48 List(list::ListArgs),
49
50 #[command(about = "AI request trends over time")]
51 Trends(trends::TrendsArgs),
52
53 #[command(about = "Model usage breakdown")]
54 Models(models::ModelsArgs),
55}
56
57#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
58pub struct RequestStatsOutput {
59 pub period: String,
60 pub total_requests: i64,
61 pub total_tokens: i64,
62 pub input_tokens: i64,
63 pub output_tokens: i64,
64 pub total_cost_microdollars: i64,
65 pub avg_latency_ms: i64,
66 pub cache_hit_rate: f64,
67}
68
69#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
70pub struct RequestTrendPoint {
71 pub timestamp: String,
72 pub request_count: i64,
73 pub total_tokens: i64,
74 pub cost_microdollars: i64,
75 pub avg_latency_ms: i64,
76}
77
78#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
79pub struct RequestTrendsOutput {
80 pub period: String,
81 pub group_by: String,
82 pub points: Vec<RequestTrendPoint>,
83}
84
85#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
86pub struct ModelUsageRow {
87 pub provider: String,
88 pub model: String,
89 pub request_count: i64,
90 pub total_tokens: i64,
91 pub total_cost_microdollars: i64,
92 pub avg_latency_ms: i64,
93 pub percentage: f64,
94}
95
96#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
97pub struct ModelsOutput {
98 pub period: String,
99 pub models: Vec<ModelUsageRow>,
100 pub total_requests: i64,
101}
102
103pub async fn execute(args: RequestsArgs, ctx: &CommandContext) -> Result<()> {
104 let db_ctx = ctx.database().await?;
105 match args.cmd.unwrap_or(RequestsCommands::Stats(args.stats)) {
106 RequestsCommands::Stats(args) => {
107 let result = stats::execute_with_pool(args, &db_ctx, &ctx.cli).await?;
108 render_result(&result, &ctx.cli);
109 Ok(())
110 },
111 RequestsCommands::List(args) => {
112 let result = list::execute_with_pool(args, &db_ctx, &ctx.cli).await?;
113 render_result(&result, &ctx.cli);
114 Ok(())
115 },
116 RequestsCommands::Trends(args) => {
117 let result = trends::execute_with_pool(args, &db_ctx, &ctx.cli).await?;
118 render_result(&result, &ctx.cli);
119 Ok(())
120 },
121 RequestsCommands::Models(args) => {
122 let result = models::execute_with_pool(args, &db_ctx, &ctx.cli).await?;
123 render_result(&result, &ctx.cli);
124 Ok(())
125 },
126 }
127}