1use serde::Serialize;
2use validator::Validate;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
6pub enum OcrToolType {
7 #[serde(rename = "hand_write")]
9 HandWrite,
10}
11
12impl OcrToolType {
13 pub const fn as_str(self) -> &'static str {
15 match self {
16 Self::HandWrite => "hand_write",
17 }
18 }
19}
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
23pub enum OcrLanguageType {
24 #[serde(rename = "AUTO")]
26 Auto,
27
28 #[serde(rename = "CHN_ENG")]
30 ChnEng,
31
32 #[serde(rename = "ENG")]
34 Eng,
35
36 #[serde(rename = "JAP")]
38 Jap,
39
40 #[serde(rename = "KOR")]
42 Kor,
43
44 #[serde(rename = "FRE")]
46 Fre,
47
48 #[serde(rename = "SPA")]
50 Spa,
51
52 #[serde(rename = "POR")]
54 Por,
55
56 #[serde(rename = "GER")]
58 Ger,
59
60 #[serde(rename = "ITA")]
62 Ita,
63
64 #[serde(rename = "RUS")]
66 Rus,
67
68 #[serde(rename = "DAN")]
70 Dan,
71
72 #[serde(rename = "DUT")]
74 Dut,
75
76 #[serde(rename = "MAL")]
78 Mal,
79
80 #[serde(rename = "SWE")]
82 Swe,
83
84 #[serde(rename = "IND")]
86 Ind,
87
88 #[serde(rename = "POL")]
90 Pol,
91
92 #[serde(rename = "ROM")]
94 Rom,
95
96 #[serde(rename = "TUR")]
98 Tur,
99
100 #[serde(rename = "GRE")]
102 Gre,
103
104 #[serde(rename = "HUN")]
106 Hun,
107
108 #[serde(rename = "THA")]
110 Tha,
111
112 #[serde(rename = "VIE")]
114 Vie,
115
116 #[serde(rename = "ARA")]
118 Ara,
119
120 #[serde(rename = "HIN")]
122 Hin,
123}
124
125impl OcrLanguageType {
126 pub const fn as_str(self) -> &'static str {
128 match self {
129 Self::Auto => "AUTO",
130 Self::ChnEng => "CHN_ENG",
131 Self::Eng => "ENG",
132 Self::Jap => "JAP",
133 Self::Kor => "KOR",
134 Self::Fre => "FRE",
135 Self::Spa => "SPA",
136 Self::Por => "POR",
137 Self::Ger => "GER",
138 Self::Ita => "ITA",
139 Self::Rus => "RUS",
140 Self::Dan => "DAN",
141 Self::Dut => "DUT",
142 Self::Mal => "MAL",
143 Self::Swe => "SWE",
144 Self::Ind => "IND",
145 Self::Pol => "POL",
146 Self::Rom => "ROM",
147 Self::Tur => "TUR",
148 Self::Gre => "GRE",
149 Self::Hun => "HUN",
150 Self::Tha => "THA",
151 Self::Vie => "VIE",
152 Self::Ara => "ARA",
153 Self::Hin => "HIN",
154 }
155 }
156}
157
158#[derive(Clone, Serialize, Validate)]
160pub struct OcrBody {
161 #[serde(skip_serializing_if = "Option::is_none")]
163 pub tool_type: Option<OcrToolType>,
164
165 #[serde(skip_serializing_if = "Option::is_none")]
167 pub language_type: Option<OcrLanguageType>,
168
169 #[serde(skip_serializing_if = "Option::is_none")]
171 pub probability: Option<bool>,
172
173 #[serde(skip_serializing_if = "Option::is_none")]
175 #[validate(length(min = 6, max = 64))]
176 pub request_id: Option<String>,
177
178 #[serde(skip_serializing_if = "Option::is_none")]
180 #[validate(length(min = 6, max = 128))]
181 pub user_id: Option<String>,
182}
183
184impl std::fmt::Debug for OcrBody {
185 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
186 formatter
187 .debug_struct("OcrBody")
188 .field("tool_type", &self.tool_type)
189 .field("language_type", &self.language_type)
190 .field("probability", &self.probability)
191 .field(
192 "request_id",
193 &self.request_id.as_ref().map(|_| "[REDACTED]"),
194 )
195 .field("user_id", &self.user_id.as_ref().map(|_| "[REDACTED]"))
196 .finish()
197 }
198}
199
200impl Default for OcrBody {
201 fn default() -> Self {
202 Self::new()
203 }
204}
205
206impl OcrBody {
207 pub fn new() -> Self {
209 Self {
210 tool_type: None,
211 language_type: None,
212 probability: None,
213 request_id: None,
214 user_id: None,
215 }
216 }
217
218 pub fn with_tool_type(mut self, tool_type: OcrToolType) -> Self {
220 self.tool_type = Some(tool_type);
221 self
222 }
223
224 pub fn with_language_type(mut self, language_type: OcrLanguageType) -> Self {
226 self.language_type = Some(language_type);
227 self
228 }
229
230 pub fn with_probability(mut self, probability: bool) -> Self {
232 self.probability = Some(probability);
233 self
234 }
235
236 pub fn with_request_id(mut self, request_id: impl Into<String>) -> Self {
238 self.request_id = Some(request_id.into());
239 self
240 }
241
242 pub fn with_user_id(mut self, user_id: impl Into<String>) -> Self {
244 self.user_id = Some(user_id.into());
245 self
246 }
247}
248
249#[cfg(test)]
250mod tests {
251 use super::*;
252
253 #[test]
254 fn debug_redacts_request_and_user_identifiers() {
255 let body = OcrBody::new()
256 .with_request_id("private-request")
257 .with_user_id("private-user");
258 let debug = format!("{body:?}");
259 assert!(!debug.contains("private-request"));
260 assert!(!debug.contains("private-user"));
261 }
262}