flowcat_core/processor/
metrics.rs1use serde::{Deserialize, Serialize};
9
10#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
13pub enum MetricsData {
14 Ttfb {
16 processor: String,
17 model: Option<String>,
18 seconds: f64,
19 },
20 Processing {
22 processor: String,
23 model: Option<String>,
24 seconds: f64,
25 },
26 LlmUsage {
28 processor: String,
29 model: Option<String>,
30 tokens: LlmTokenUsage,
31 },
32 TtsUsage { processor: String, characters: u64 },
34 TurnPrediction {
36 processor: String,
37 is_complete: bool,
38 probability: f32,
39 e2e_processing_ms: f64,
40 },
41}
42
43#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
45pub struct LlmTokenUsage {
46 pub prompt_tokens: u64,
47 pub completion_tokens: u64,
48 pub total_tokens: u64,
49 pub cache_read_input_tokens: Option<u64>,
50 pub cache_creation_input_tokens: Option<u64>,
51 pub reasoning_tokens: Option<u64>,
52}
53
54#[cfg(test)]
55mod tests {
56 use super::*;
57
58 #[test]
59 fn metrics_data_serde_roundtrips_every_variant() {
60 let cases = vec![
61 MetricsData::Ttfb {
62 processor: "stt".into(),
63 model: Some("nova-2".into()),
64 seconds: 0.123,
65 },
66 MetricsData::Processing {
67 processor: "llm".into(),
68 model: None,
69 seconds: 1.5,
70 },
71 MetricsData::LlmUsage {
72 processor: "llm".into(),
73 model: Some("gpt-4o".into()),
74 tokens: LlmTokenUsage {
75 prompt_tokens: 10,
76 completion_tokens: 20,
77 total_tokens: 30,
78 cache_read_input_tokens: Some(4),
79 cache_creation_input_tokens: None,
80 reasoning_tokens: Some(2),
81 },
82 },
83 MetricsData::TtsUsage {
84 processor: "tts".into(),
85 characters: 42,
86 },
87 MetricsData::TurnPrediction {
88 processor: "turn".into(),
89 is_complete: true,
90 probability: 0.97,
91 e2e_processing_ms: 12.0,
92 },
93 ];
94 for m in cases {
95 let json = serde_json::to_string(&m).expect("serialize");
96 let back: MetricsData = serde_json::from_str(&json).expect("deserialize");
97 assert_eq!(m, back);
98 }
99 }
100
101 #[test]
102 fn llm_token_usage_defaults_to_zero() {
103 let u = LlmTokenUsage::default();
104 assert_eq!(u.total_tokens, 0);
105 assert!(u.cache_read_input_tokens.is_none());
106 }
107}