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 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 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}