zai_rs/model/ocr/
response.rs1use serde::{Deserialize, Serialize};
2use validator::Validate;
3
4#[derive(Debug, Clone, Serialize, Deserialize, Validate)]
6pub struct OcrResponse {
7 pub task_id: String,
9
10 pub message: String,
12
13 pub status: OcrStatus,
15
16 pub words_result_num: i64,
18
19 #[serde(skip_serializing_if = "Option::is_none")]
21 pub words_result: Option<Vec<WordsResultItem>>,
22}
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
26#[serde(rename_all = "lowercase")]
27pub enum OcrStatus {
28 Succeeded,
30 Failed,
32}
33
34#[derive(Debug, Clone, Serialize, Deserialize, Validate)]
36pub struct WordsResultItem {
37 pub location: Location,
39
40 pub words: String,
42
43 pub probability: Probability,
45}
46
47#[derive(Debug, Clone, Serialize, Deserialize, Validate)]
49pub struct Location {
50 pub left: i64,
52
53 pub top: i64,
55
56 pub width: i64,
58
59 pub height: i64,
61}
62
63#[derive(Debug, Clone, Serialize, Deserialize, Validate)]
65pub struct Probability {
66 pub average: f64,
68
69 pub variance: f64,
71
72 pub min: f64,
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79
80 #[test]
81 fn top_level_required_fields_and_status_enum_are_enforced() {
82 let valid = serde_json::json!({
83 "task_id": "ocr-1",
84 "message": "ok",
85 "status": "succeeded",
86 "words_result_num": 0
87 });
88 assert!(serde_json::from_value::<OcrResponse>(valid).is_ok());
89 assert!(serde_json::from_str::<OcrResponse>("{}").is_err());
90 assert!(
91 serde_json::from_value::<OcrResponse>(serde_json::json!({
92 "task_id": "ocr-1",
93 "message": "ok",
94 "status": "SUCCESS",
95 "words_result_num": 0
96 }))
97 .is_err()
98 );
99 }
100
101 #[test]
102 fn result_item_enforces_nested_required_fields() {
103 assert!(serde_json::from_str::<WordsResultItem>(r#"{"words":"hello"}"#).is_err());
104 let item = serde_json::json!({
105 "location": {"left": 1, "top": 2, "width": 3, "height": 4},
106 "words": "hello",
107 "probability": {"average": 0.9, "variance": 0.1, "min": 0.7}
108 });
109 assert!(serde_json::from_value::<WordsResultItem>(item).is_ok());
110 }
111}