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