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::CliConfig;
13
14#[derive(Debug, Subcommand)]
15pub enum RequestsCommands {
16 #[command(about = "Aggregate AI request statistics")]
17 Stats(stats::StatsArgs),
18
19 #[command(about = "List individual AI requests")]
20 List(list::ListArgs),
21
22 #[command(about = "AI request trends over time")]
23 Trends(trends::TrendsArgs),
24
25 #[command(about = "Model usage breakdown")]
26 Models(models::ModelsArgs),
27}
28
29#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
30pub struct RequestStatsOutput {
31 pub period: String,
32 pub total_requests: i64,
33 pub total_tokens: i64,
34 pub input_tokens: i64,
35 pub output_tokens: i64,
36 pub total_cost_cents: i64,
37 pub avg_latency_ms: i64,
38 pub cache_hit_rate: f64,
39}
40
41#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
42pub struct RequestTrendPoint {
43 pub timestamp: String,
44 pub request_count: i64,
45 pub total_tokens: i64,
46 pub cost_cents: i64,
47 pub avg_latency_ms: i64,
48}
49
50#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
51pub struct RequestTrendsOutput {
52 pub period: String,
53 pub group_by: String,
54 pub points: Vec<RequestTrendPoint>,
55}
56
57#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
58pub struct ModelUsageRow {
59 pub provider: String,
60 pub model: String,
61 pub request_count: i64,
62 pub total_tokens: i64,
63 pub total_cost_cents: i64,
64 pub avg_latency_ms: i64,
65 pub percentage: f64,
66}
67
68#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
69pub struct ModelsOutput {
70 pub period: String,
71 pub models: Vec<ModelUsageRow>,
72 pub total_requests: i64,
73}
74
75pub async fn execute(command: RequestsCommands, config: &CliConfig) -> Result<()> {
76 match command {
77 RequestsCommands::Stats(args) => stats::execute(args, config).await,
78 RequestsCommands::List(args) => list::execute(args, config).await,
79 RequestsCommands::Trends(args) => trends::execute(args, config).await,
80 RequestsCommands::Models(args) => models::execute(args, config).await,
81 }
82}
83
84pub async fn execute_with_pool(
85 command: RequestsCommands,
86 db_ctx: &DatabaseContext,
87 config: &CliConfig,
88) -> Result<()> {
89 match command {
90 RequestsCommands::Stats(args) => stats::execute_with_pool(args, db_ctx, config).await,
91 RequestsCommands::List(args) => list::execute_with_pool(args, db_ctx, config).await,
92 RequestsCommands::Trends(args) => trends::execute_with_pool(args, db_ctx, config).await,
93 RequestsCommands::Models(args) => models::execute_with_pool(args, db_ctx, config).await,
94 }
95}