1use redact_core::AnonymizationStrategy;
7use serde::{Deserialize, Serialize};
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct AnalyzeRequest {
12 pub text: String,
14
15 #[serde(default = "default_language")]
17 pub language: String,
18
19 #[serde(skip_serializing_if = "Option::is_none")]
21 pub entities: Option<Vec<String>>,
22
23 #[serde(skip_serializing_if = "Option::is_none")]
25 pub min_score: Option<f32>,
26}
27
28fn default_language() -> String {
29 "en".to_string()
30}
31
32#[derive(Debug, Clone, Serialize, Deserialize)]
34pub struct AnalyzeResponse {
35 #[serde(skip_serializing_if = "Option::is_none")]
37 pub original_text: Option<String>,
38
39 pub results: Vec<EntityResult>,
41
42 pub metadata: AnalysisMetadata,
44}
45
46#[derive(Debug, Clone, Serialize, Deserialize)]
48pub struct EntityResult {
49 pub entity_type: String,
51
52 pub start: usize,
54
55 pub end: usize,
57
58 pub score: f32,
60
61 #[serde(skip_serializing_if = "Option::is_none")]
63 pub text: Option<String>,
64
65 pub recognizer_name: String,
67}
68
69#[derive(Debug, Clone, Serialize, Deserialize)]
71pub struct AnalysisMetadata {
72 pub recognizers_used: usize,
74
75 pub processing_time_ms: u64,
77
78 pub language: String,
80
81 #[serde(skip_serializing_if = "Option::is_none")]
83 pub model_version: Option<String>,
84}
85
86#[derive(Debug, Clone, Serialize, Deserialize)]
88pub struct AnonymizeRequest {
89 pub text: String,
91
92 #[serde(default = "default_language")]
94 pub language: String,
95
96 #[serde(default)]
98 pub config: AnonymizationConfig,
99
100 #[serde(skip_serializing_if = "Option::is_none")]
102 pub entities: Option<Vec<String>>,
103}
104
105#[derive(Debug, Clone, Serialize, Deserialize)]
107pub struct AnonymizationConfig {
108 #[serde(default)]
110 pub strategy: AnonymizationStrategy,
111
112 #[serde(default = "default_mask_char")]
114 pub mask_char: String,
115
116 #[serde(default)]
118 pub mask_start_chars: usize,
119
120 #[serde(default)]
122 pub mask_end_chars: usize,
123
124 #[serde(default)]
126 pub preserve_format: bool,
127
128 #[serde(skip_serializing_if = "Option::is_none")]
130 pub encryption_key: Option<String>,
131
132 #[serde(skip_serializing_if = "Option::is_none")]
134 pub hash_salt: Option<String>,
135}
136
137impl Default for AnonymizationConfig {
138 fn default() -> Self {
139 Self {
140 strategy: AnonymizationStrategy::Replace,
141 mask_char: default_mask_char(),
142 mask_start_chars: 0,
143 mask_end_chars: 0,
144 preserve_format: false,
145 encryption_key: None,
146 hash_salt: None,
147 }
148 }
149}
150
151fn default_mask_char() -> String {
152 "*".to_string()
153}
154
155#[derive(Debug, Clone, Serialize, Deserialize)]
157pub struct AnonymizeResponse {
158 pub text: String,
160
161 pub results: Vec<EntityResult>,
163
164 #[serde(skip_serializing_if = "Option::is_none")]
166 pub tokens: Option<Vec<TokenInfo>>,
167
168 pub metadata: AnalysisMetadata,
170}
171
172#[derive(Debug, Clone, Serialize, Deserialize)]
174pub struct TokenInfo {
175 pub token_id: String,
177
178 pub entity_type: String,
180
181 pub start: usize,
183
184 pub end: usize,
186
187 #[serde(skip_serializing_if = "Option::is_none")]
189 pub expires_at: Option<String>,
190}
191
192#[derive(Debug, Clone, Serialize, Deserialize)]
194pub struct HealthResponse {
195 pub status: String,
196 pub version: String,
197 pub recognizers: usize,
198}
199
200#[derive(Debug, Clone, Serialize, Deserialize)]
202pub struct ErrorResponse {
203 pub error: String,
204 pub message: String,
205}
206
207impl ErrorResponse {
208 pub fn new(error: impl Into<String>, message: impl Into<String>) -> Self {
209 Self {
210 error: error.into(),
211 message: message.into(),
212 }
213 }
214}
215
216impl From<redact_core::RecognizerResult> for EntityResult {
218 fn from(result: redact_core::RecognizerResult) -> Self {
219 Self {
220 entity_type: result.entity_type.as_str().to_string(),
221 start: result.start,
222 end: result.end,
223 score: result.score,
224 text: result.text,
225 recognizer_name: result.recognizer_name,
226 }
227 }
228}
229
230impl From<redact_core::AnalysisMetadata> for AnalysisMetadata {
231 fn from(metadata: redact_core::AnalysisMetadata) -> Self {
232 Self {
233 recognizers_used: metadata.recognizers_used,
234 processing_time_ms: metadata.processing_time_ms,
235 language: metadata.language,
236 model_version: metadata.model_version,
237 }
238 }
239}
240
241impl From<redact_core::Token> for TokenInfo {
242 fn from(token: redact_core::Token) -> Self {
243 Self {
244 token_id: token.token_id,
245 entity_type: token.entity_type.as_str().to_string(),
246 start: token.start,
247 end: token.end,
248 expires_at: token.expires_at.map(|dt| dt.to_rfc3339()),
249 }
250 }
251}