1use serde::{Deserialize, Serialize};
6use std::collections::HashMap;
7
8#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
19pub struct ExtractContactRequest {
20 pub message_ids: Vec<String>,
22}
23
24#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
26pub struct ExtractContactResponse {
27 pub contacts: HashMap<String, Vec<ExtractedContact>>,
29}
30
31#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
33pub struct ExtractedContact {
34 #[serde(skip_serializing_if = "Option::is_none")]
36 pub name: Option<String>,
37
38 #[serde(skip_serializing_if = "Option::is_none")]
40 pub email: Option<String>,
41
42 #[serde(skip_serializing_if = "Option::is_none")]
44 pub phone: Option<String>,
45
46 #[serde(skip_serializing_if = "Option::is_none")]
48 pub company: Option<String>,
49
50 #[serde(skip_serializing_if = "Option::is_none")]
52 pub title: Option<String>,
53
54 #[serde(skip_serializing_if = "Option::is_none")]
56 pub address: Option<String>,
57
58 #[serde(skip_serializing_if = "Option::is_none")]
60 pub confidence: Option<f64>,
61}
62
63#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
75pub struct ExtractSignatureRequest {
76 pub message_ids: Vec<String>,
78
79 #[serde(skip_serializing_if = "Option::is_none")]
81 pub parse_contacts: Option<bool>,
82}
83
84#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
86pub struct ExtractSignatureResponse {
87 pub signatures: HashMap<String, ExtractedSignature>,
89}
90
91#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
93pub struct ExtractedSignature {
94 pub text: String,
96
97 #[serde(skip_serializing_if = "Option::is_none")]
99 pub contact: Option<ExtractedContact>,
100
101 #[serde(skip_serializing_if = "Option::is_none")]
103 pub confidence: Option<f64>,
104}
105
106#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
117pub struct ExtractOrderRequest {
118 pub message_ids: Vec<String>,
120}
121
122#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
124pub struct ExtractOrderResponse {
125 pub orders: HashMap<String, Vec<ExtractedOrder>>,
127}
128
129#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
131pub struct ExtractedOrder {
132 #[serde(skip_serializing_if = "Option::is_none")]
134 pub order_number: Option<String>,
135
136 #[serde(skip_serializing_if = "Option::is_none")]
138 pub order_date: Option<i64>,
139
140 #[serde(skip_serializing_if = "Option::is_none")]
142 pub total: Option<f64>,
143
144 #[serde(skip_serializing_if = "Option::is_none")]
146 pub currency: Option<String>,
147
148 #[serde(skip_serializing_if = "Option::is_none")]
150 pub merchant: Option<String>,
151
152 #[serde(skip_serializing_if = "Option::is_none")]
154 pub status: Option<String>,
155
156 #[serde(skip_serializing_if = "Option::is_none")]
158 pub items: Option<Vec<OrderItem>>,
159
160 #[serde(skip_serializing_if = "Option::is_none")]
162 pub shipping: Option<ShippingInfo>,
163
164 #[serde(skip_serializing_if = "Option::is_none")]
166 pub confidence: Option<f64>,
167}
168
169#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
171pub struct OrderItem {
172 pub name: String,
174
175 #[serde(skip_serializing_if = "Option::is_none")]
177 pub quantity: Option<i32>,
178
179 #[serde(skip_serializing_if = "Option::is_none")]
181 pub price: Option<f64>,
182
183 #[serde(skip_serializing_if = "Option::is_none")]
185 pub total: Option<f64>,
186
187 #[serde(skip_serializing_if = "Option::is_none")]
189 pub sku: Option<String>,
190}
191
192#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
194pub struct ShippingInfo {
195 #[serde(skip_serializing_if = "Option::is_none")]
197 pub tracking_number: Option<String>,
198
199 #[serde(skip_serializing_if = "Option::is_none")]
201 pub carrier: Option<String>,
202
203 #[serde(skip_serializing_if = "Option::is_none")]
205 pub address: Option<String>,
206
207 #[serde(skip_serializing_if = "Option::is_none")]
209 pub delivery_date: Option<i64>,
210}
211
212#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
224pub struct ExtractEntitiesRequest {
225 pub message_ids: Vec<String>,
227
228 pub entity_types: Vec<String>,
230}
231
232#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
234pub struct ExtractEntitiesResponse {
235 pub entities: HashMap<String, Vec<ExtractedEntity>>,
237}
238
239#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
241pub struct ExtractedEntity {
242 pub entity_type: String,
244
245 pub value: String,
247
248 #[serde(skip_serializing_if = "Option::is_none")]
250 pub text: Option<String>,
251
252 #[serde(skip_serializing_if = "Option::is_none")]
254 pub position: Option<EntityPosition>,
255
256 #[serde(skip_serializing_if = "Option::is_none")]
258 pub confidence: Option<f64>,
259}
260
261#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
263pub struct EntityPosition {
264 pub start: usize,
266
267 pub end: usize,
269}
270
271#[cfg(test)]
272mod tests {
273 use super::*;
274
275 #[test]
276 fn test_extract_contact_request() {
277 let request = ExtractContactRequest {
278 message_ids: vec!["msg_123".to_string()],
279 };
280
281 let json = serde_json::to_string(&request).unwrap();
282 let deserialized: ExtractContactRequest = serde_json::from_str(&json).unwrap();
283
284 assert_eq!(request, deserialized);
285 }
286
287 #[test]
288 fn test_extracted_contact() {
289 let contact = ExtractedContact {
290 name: Some("John Doe".to_string()),
291 email: Some("john@example.com".to_string()),
292 phone: Some("+1-555-0100".to_string()),
293 company: Some("Acme Corp".to_string()),
294 title: Some("CEO".to_string()),
295 address: Some("123 Main St".to_string()),
296 confidence: Some(0.95),
297 };
298
299 let json = serde_json::to_string(&contact).unwrap();
300 let deserialized: ExtractedContact = serde_json::from_str(&json).unwrap();
301
302 assert_eq!(contact, deserialized);
303 }
304
305 #[test]
306 fn test_extract_signature_request() {
307 let request = ExtractSignatureRequest {
308 message_ids: vec!["msg_123".to_string()],
309 parse_contacts: Some(true),
310 };
311
312 let json = serde_json::to_string(&request).unwrap();
313 let deserialized: ExtractSignatureRequest = serde_json::from_str(&json).unwrap();
314
315 assert_eq!(request, deserialized);
316 }
317
318 #[test]
319 fn test_extracted_order() {
320 let order = ExtractedOrder {
321 order_number: Some("ORD-12345".to_string()),
322 order_date: Some(1735689600),
323 total: Some(99.99),
324 currency: Some("USD".to_string()),
325 merchant: Some("Example Store".to_string()),
326 status: Some("shipped".to_string()),
327 items: Some(vec![OrderItem {
328 name: "Product A".to_string(),
329 quantity: Some(2),
330 price: Some(49.99),
331 total: Some(99.98),
332 sku: Some("SKU-001".to_string()),
333 }]),
334 shipping: Some(ShippingInfo {
335 tracking_number: Some("1Z999AA10123456784".to_string()),
336 carrier: Some("UPS".to_string()),
337 address: Some("456 Oak Ave".to_string()),
338 delivery_date: Some(1735776000),
339 }),
340 confidence: Some(0.92),
341 };
342
343 let json = serde_json::to_string(&order).unwrap();
344 let deserialized: ExtractedOrder = serde_json::from_str(&json).unwrap();
345
346 assert_eq!(order, deserialized);
347 }
348
349 #[test]
350 fn test_extract_entities_request() {
351 let request = ExtractEntitiesRequest {
352 message_ids: vec!["msg_123".to_string()],
353 entity_types: vec!["date".to_string(), "location".to_string()],
354 };
355
356 let json = serde_json::to_string(&request).unwrap();
357 let deserialized: ExtractEntitiesRequest = serde_json::from_str(&json).unwrap();
358
359 assert_eq!(request, deserialized);
360 }
361
362 #[test]
363 fn test_extracted_entity() {
364 let entity = ExtractedEntity {
365 entity_type: "date".to_string(),
366 value: "2025-01-01".to_string(),
367 text: Some("January 1st, 2025".to_string()),
368 position: Some(EntityPosition { start: 10, end: 27 }),
369 confidence: Some(0.98),
370 };
371
372 let json = serde_json::to_string(&entity).unwrap();
373 let deserialized: ExtractedEntity = serde_json::from_str(&json).unwrap();
374
375 assert_eq!(entity, deserialized);
376 }
377}