aimo_core/
receipt.rs

1use serde::{Deserialize, Serialize};
2use sha2::{Digest, Sha256};
3use solana_sdk::pubkey::Pubkey;
4
5#[derive(Debug, Clone, Default, Serialize, Deserialize)]
6pub struct RequestReceipt {
7    pub sender: String,
8    pub request_id: String,
9    pub service_id: String,
10    pub max_est_cost: u64,
11    pub timestamp: i64,
12    pub finish_reason: String,
13    pub prompt_tokens: u64,
14    pub completion_tokens: u64,
15    pub amount: u64,
16    pub token_mint: String,
17    pub model_name: String,
18    pub cache_discount: u64,
19
20    // Model Statistics
21    pub streamed: Option<bool>,
22    pub cancelled: Option<bool>,
23    pub latency: Option<i64>,
24    pub generation_time: Option<i64>,
25    pub moderation_latency: Option<i64>,
26    pub num_media_prompt: Option<u64>,
27    pub num_media_completion: Option<u64>,
28    pub num_search_results: Option<u64>,
29
30    // Optional Fields
31    pub app_id: Option<String>,
32    pub origin: Option<String>,
33}
34
35impl RequestReceipt {
36    pub fn new() -> Self {
37        Self::default()
38    }
39
40    pub fn sender(self, sender: Pubkey) -> Self {
41        Self {
42            sender: sender.to_string(),
43            ..self
44        }
45    }
46
47    pub fn request_id(self, request_id: Pubkey) -> Self {
48        Self {
49            request_id: request_id.to_string(),
50            ..self
51        }
52    }
53
54    pub fn service_id(self, service_id: impl Into<String>) -> Self {
55        Self {
56            service_id: service_id.into(),
57            ..self
58        }
59    }
60
61    pub fn max_est_cost(self, max_est_cost: u64) -> Self {
62        Self {
63            max_est_cost,
64            ..self
65        }
66    }
67
68    pub fn timestamp(self, timestamp: i64) -> Self {
69        Self {
70            timestamp,
71            ..self
72        }
73    }
74
75    pub fn finish_reason(self, finish_reason: impl Into<String>) -> Self {
76        Self {
77            finish_reason: finish_reason.into(),
78            ..self
79        }
80    }
81
82    pub fn prompt_tokens(self, prompt_tokens: u64) -> Self {
83        Self {
84            prompt_tokens,
85            ..self
86        }
87    }
88
89    pub fn completion_tokens(self, completion_tokens: u64) -> Self {
90        Self {
91            completion_tokens,
92            ..self
93        }
94    }
95
96    pub fn amount(self, amount: u64) -> Self {
97        Self {
98            amount,
99            ..self
100        }
101    }
102
103    pub fn token_mint(self, token_mint: impl Into<String>) -> Self {
104        Self {
105            token_mint: token_mint.into(),
106            ..self
107        }
108    }
109
110    pub fn model_name(self, model_name: impl Into<String>) -> Self {
111        Self {
112            model_name: model_name.into(),
113            ..self
114        }
115    }
116
117    pub fn cache_discount(self, cache_discount: u64) -> Self {
118        Self {
119            cache_discount,
120            ..self
121        }
122    }
123
124    pub fn streamed(self, streamed: bool) -> Self {
125        Self {
126            streamed: Some(streamed),
127            ..self
128        }
129    }
130
131    pub fn cancelled(self, cancelled: bool) -> Self {
132        Self {
133            cancelled: Some(cancelled),
134            ..self
135        }
136    }
137
138    pub fn latency(self, latency: i64) -> Self {
139        Self {
140            latency: Some(latency),
141            ..self
142        }
143    }
144
145    pub fn generation_time(self, generation_time: i64) -> Self {
146        Self {
147            generation_time: Some(generation_time),
148            ..self
149        }
150    }
151
152    pub fn moderation_latency(self, moderation_latency: i64) -> Self {
153        Self {
154            moderation_latency: Some(moderation_latency),
155            ..self
156        }
157    }
158
159    pub fn num_media_prompt(self, num_media_prompt: u64) -> Self {
160        Self {
161            num_media_prompt: Some(num_media_prompt),
162            ..self
163        }
164    }
165
166    pub fn num_media_completion(self, num_media_completion: u64) -> Self {
167        Self {
168            num_media_completion: Some(num_media_completion),
169            ..self
170        }
171    }
172
173    pub fn num_search_results(self, num_search_results: u64) -> Self {
174        Self {
175            num_search_results: Some(num_search_results),
176            ..self
177        }
178    }
179
180    pub fn app_id(self, app_id: impl Into<String>) -> Self {
181        Self {
182            app_id: Some(app_id.into()),
183            ..self
184        }
185    }
186
187    pub fn origin(self, origin: impl Into<String>) -> Self {
188        Self {
189            origin: Some(origin.into()),
190            ..self
191        }
192    }
193}
194
195impl RequestReceipt {
196    pub fn to_bytes(self) -> anyhow::Result<Vec<u8>> {
197        let json = serde_json::to_value(self)?;
198        let string = canonical_json::to_string(&json)?;
199        Ok(string.into_bytes())
200    }
201
202    pub fn to_hash(self) -> anyhow::Result<[u8; 32]> {
203        let mut hasher = Sha256::new();
204        hasher.update(self.to_bytes()?);
205        Ok(hasher.finalize().into())
206    }
207}