systemprompt_cli/commands/analytics/content/
mod.rs1mod 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::CliConfig;
12use crate::shared::render_result;
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 = "Top performing content", hide = true)]
23 Popular(top::TopArgs),
24
25 #[command(about = "Content trends over time")]
26 Trends(trends::TrendsArgs),
27}
28
29#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
30pub struct ContentStatsOutput {
31 pub period: String,
32 pub total_views: i64,
33 pub unique_visitors: i64,
34 pub avg_time_on_page_seconds: i64,
35 pub avg_scroll_depth: f64,
36 pub total_clicks: i64,
37}
38
39#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
40pub struct TopContentRow {
41 pub content_id: String,
42 pub slug: String,
43 pub title: String,
44 pub source: String,
45 pub views: i64,
46 pub unique_visitors: i64,
47 pub avg_time_seconds: i64,
48 pub trend: String,
49}
50
51#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
52pub struct TopContentOutput {
53 pub period: String,
54 pub content: Vec<TopContentRow>,
55}
56
57#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
58pub struct ContentTrendPoint {
59 pub timestamp: String,
60 pub views: i64,
61 pub unique_visitors: i64,
62}
63
64#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
65pub struct ContentTrendsOutput {
66 pub period: String,
67 pub group_by: String,
68 pub points: Vec<ContentTrendPoint>,
69}
70
71pub async fn execute(command: ContentCommands, config: &CliConfig) -> Result<()> {
72 match command {
73 ContentCommands::Stats(args) => {
74 let result = stats::execute(args, config).await?;
75 render_result(&result);
76 Ok(())
77 },
78 ContentCommands::Top(args) | ContentCommands::Popular(args) => {
79 let result = top::execute(args, config).await?;
80 render_result(&result);
81 Ok(())
82 },
83 ContentCommands::Trends(args) => {
84 let result = trends::execute(args, config).await?;
85 render_result(&result);
86 Ok(())
87 },
88 }
89}
90
91pub async fn execute_with_pool(
92 command: ContentCommands,
93 db_ctx: &DatabaseContext,
94 config: &CliConfig,
95) -> Result<()> {
96 match command {
97 ContentCommands::Stats(args) => {
98 let result = stats::execute_with_pool(args, db_ctx, config).await?;
99 render_result(&result);
100 Ok(())
101 },
102 ContentCommands::Top(args) | ContentCommands::Popular(args) => {
103 let result = top::execute_with_pool(args, db_ctx, config).await?;
104 render_result(&result);
105 Ok(())
106 },
107 ContentCommands::Trends(args) => {
108 let result = trends::execute_with_pool(args, db_ctx, config).await?;
109 render_result(&result);
110 Ok(())
111 },
112 }
113}