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