Skip to main content

systemprompt_cli/commands/analytics/content/
mod.rs

1mod stats;
2mod top;
3mod trends;
4
5use anyhow::Result;
6use clap::Subcommand;
7use schemars::JsonSchema;
8use serde::{Deserialize, Serialize};
9use systemprompt_runtime::DatabaseContext;
10
11use crate::shared::render_result;
12use crate::CliConfig;
13
14#[derive(Debug, Subcommand)]
15pub enum ContentCommands {
16    #[command(about = "Content engagement statistics")]
17    Stats(stats::StatsArgs),
18
19    #[command(about = "Top performing content")]
20    Top(top::TopArgs),
21
22    #[command(about = "Content trends over time")]
23    Trends(trends::TrendsArgs),
24}
25
26#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
27pub struct ContentStatsOutput {
28    pub period: String,
29    pub total_views: i64,
30    pub unique_visitors: i64,
31    pub avg_time_on_page_seconds: i64,
32    pub avg_scroll_depth: f64,
33    pub total_clicks: i64,
34}
35
36#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
37pub struct TopContentRow {
38    pub content_id: String,
39    pub views: i64,
40    pub unique_visitors: i64,
41    pub avg_time_seconds: i64,
42    pub trend: String,
43}
44
45#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
46pub struct TopContentOutput {
47    pub period: String,
48    pub content: Vec<TopContentRow>,
49}
50
51#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
52pub struct ContentTrendPoint {
53    pub timestamp: String,
54    pub views: i64,
55    pub unique_visitors: i64,
56}
57
58#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
59pub struct ContentTrendsOutput {
60    pub period: String,
61    pub group_by: String,
62    pub points: Vec<ContentTrendPoint>,
63}
64
65pub async fn execute(command: ContentCommands, config: &CliConfig) -> Result<()> {
66    match command {
67        ContentCommands::Stats(args) => {
68            let result = stats::execute(args, config).await?;
69            render_result(&result);
70            Ok(())
71        },
72        ContentCommands::Top(args) => {
73            let result = top::execute(args, config).await?;
74            render_result(&result);
75            Ok(())
76        },
77        ContentCommands::Trends(args) => {
78            let result = trends::execute(args, config).await?;
79            render_result(&result);
80            Ok(())
81        },
82    }
83}
84
85pub async fn execute_with_pool(
86    command: ContentCommands,
87    db_ctx: &DatabaseContext,
88    config: &CliConfig,
89) -> Result<()> {
90    match command {
91        ContentCommands::Stats(args) => {
92            let result = stats::execute_with_pool(args, db_ctx, config).await?;
93            render_result(&result);
94            Ok(())
95        },
96        ContentCommands::Top(args) => {
97            let result = top::execute_with_pool(args, db_ctx, config).await?;
98            render_result(&result);
99            Ok(())
100        },
101        ContentCommands::Trends(args) => {
102            let result = trends::execute_with_pool(args, db_ctx, config).await?;
103            render_result(&result);
104            Ok(())
105        },
106    }
107}