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(about = "Aggregate AI request statistics")]
25 Stats(stats::StatsArgs),
26
27 #[command(about = "List individual AI requests")]
28 List(list::ListArgs),
29
30 #[command(about = "AI request trends over time")]
31 Trends(trends::TrendsArgs),
32
33 #[command(about = "Model usage breakdown")]
34 Models(models::ModelsArgs),
35}
36
37#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
38pub struct RequestStatsOutput {
39 pub period: String,
40 pub total_requests: i64,
41 pub total_tokens: i64,
42 pub input_tokens: i64,
43 pub output_tokens: i64,
44 pub total_cost_microdollars: i64,
45 pub avg_latency_ms: i64,
46 pub cache_hit_rate: f64,
47}
48
49#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
50pub struct RequestTrendPoint {
51 pub timestamp: String,
52 pub request_count: i64,
53 pub total_tokens: i64,
54 pub cost_microdollars: i64,
55 pub avg_latency_ms: i64,
56}
57
58#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
59pub struct RequestTrendsOutput {
60 pub period: String,
61 pub group_by: String,
62 pub points: Vec<RequestTrendPoint>,
63}
64
65#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
66pub struct ModelUsageRow {
67 pub provider: String,
68 pub model: String,
69 pub request_count: i64,
70 pub total_tokens: i64,
71 pub total_cost_microdollars: i64,
72 pub avg_latency_ms: i64,
73 pub percentage: f64,
74}
75
76#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
77pub struct ModelsOutput {
78 pub period: String,
79 pub models: Vec<ModelUsageRow>,
80 pub total_requests: i64,
81}
82
83pub async fn execute(command: RequestsCommands, config: &CliConfig) -> Result<()> {
84 match command {
85 RequestsCommands::Stats(args) => {
86 let result = stats::execute(args, config).await?;
87 render_result(&result);
88 Ok(())
89 },
90 RequestsCommands::List(args) => {
91 let result = list::execute(args, config).await?;
92 render_result(&result);
93 Ok(())
94 },
95 RequestsCommands::Trends(args) => {
96 let result = trends::execute(args, config).await?;
97 render_result(&result);
98 Ok(())
99 },
100 RequestsCommands::Models(args) => {
101 let result = models::execute(args, config).await?;
102 render_result(&result);
103 Ok(())
104 },
105 }
106}
107
108pub async fn execute_with_pool(
109 command: RequestsCommands,
110 db_ctx: &DatabaseContext,
111 config: &CliConfig,
112) -> Result<()> {
113 match command {
114 RequestsCommands::Stats(args) => {
115 let result = stats::execute_with_pool(args, db_ctx, config).await?;
116 render_result(&result);
117 Ok(())
118 },
119 RequestsCommands::List(args) => {
120 let result = list::execute_with_pool(args, db_ctx, config).await?;
121 render_result(&result);
122 Ok(())
123 },
124 RequestsCommands::Trends(args) => {
125 let result = trends::execute_with_pool(args, db_ctx, config).await?;
126 render_result(&result);
127 Ok(())
128 },
129 RequestsCommands::Models(args) => {
130 let result = models::execute_with_pool(args, db_ctx, config).await?;
131 render_result(&result);
132 Ok(())
133 },
134 }
135}