1use redact_core::AnonymizationStrategy;
6use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct AnalyzeRequest {
11 pub text: String,
13
14 #[serde(default = "default_language")]
16 pub language: String,
17
18 #[serde(skip_serializing_if = "Option::is_none")]
20 pub entities: Option<Vec<String>>,
21
22 #[serde(skip_serializing_if = "Option::is_none")]
24 pub min_score: Option<f32>,
25}
26
27fn default_language() -> String {
28 "en".to_string()
29}
30
31#[derive(Debug, Clone, Serialize, Deserialize)]
33pub struct AnalyzeResponse {
34 #[serde(skip_serializing_if = "Option::is_none")]
36 pub original_text: Option<String>,
37
38 pub results: Vec<EntityResult>,
40
41 pub metadata: AnalysisMetadata,
43}
44
45#[derive(Debug, Clone, Serialize, Deserialize)]
47pub struct EntityResult {
48 pub entity_type: String,
50
51 pub start: usize,
53
54 pub end: usize,
56
57 pub score: f32,
59
60 #[serde(skip_serializing_if = "Option::is_none")]
62 pub text: Option<String>,
63
64 pub recognizer_name: String,
66}
67
68#[derive(Debug, Clone, Serialize, Deserialize)]
70pub struct AnalysisMetadata {
71 pub recognizers_used: usize,
73
74 pub processing_time_ms: u64,
76
77 pub language: String,
79
80 #[serde(skip_serializing_if = "Option::is_none")]
82 pub model_version: Option<String>,
83}
84
85#[derive(Debug, Clone, Serialize, Deserialize)]
87pub struct AnonymizeRequest {
88 pub text: String,
90
91 #[serde(default = "default_language")]
93 pub language: String,
94
95 #[serde(default)]
97 pub config: AnonymizationConfig,
98
99 #[serde(skip_serializing_if = "Option::is_none")]
101 pub entities: Option<Vec<String>>,
102}
103
104#[derive(Debug, Clone, Serialize, Deserialize)]
106pub struct AnonymizationConfig {
107 #[serde(default)]
109 pub strategy: AnonymizationStrategy,
110
111 #[serde(default = "default_mask_char")]
113 pub mask_char: String,
114
115 #[serde(default)]
117 pub mask_start_chars: usize,
118
119 #[serde(default)]
121 pub mask_end_chars: usize,
122
123 #[serde(default)]
125 pub preserve_format: bool,
126
127 #[serde(skip_serializing_if = "Option::is_none")]
129 pub encryption_key: Option<String>,
130
131 #[serde(skip_serializing_if = "Option::is_none")]
133 pub hash_salt: Option<String>,
134}
135
136impl Default for AnonymizationConfig {
137 fn default() -> Self {
138 Self {
139 strategy: AnonymizationStrategy::Replace,
140 mask_char: default_mask_char(),
141 mask_start_chars: 0,
142 mask_end_chars: 0,
143 preserve_format: false,
144 encryption_key: None,
145 hash_salt: None,
146 }
147 }
148}
149
150fn default_mask_char() -> String {
151 "*".to_string()
152}
153
154#[derive(Debug, Clone, Serialize, Deserialize)]
156pub struct AnonymizeResponse {
157 pub text: String,
159
160 pub results: Vec<EntityResult>,
162
163 #[serde(skip_serializing_if = "Option::is_none")]
165 pub tokens: Option<Vec<TokenInfo>>,
166
167 pub metadata: AnalysisMetadata,
169}
170
171#[derive(Debug, Clone, Serialize, Deserialize)]
173pub struct TokenInfo {
174 pub token_id: String,
176
177 pub entity_type: String,
179
180 pub start: usize,
182
183 pub end: usize,
185
186 #[serde(skip_serializing_if = "Option::is_none")]
188 pub expires_at: Option<String>,
189}
190
191#[derive(Debug, Clone, Serialize, Deserialize)]
193pub struct HealthResponse {
194 pub status: String,
195 pub version: String,
196 pub recognizers: usize,
198 pub entity_types: usize,
200}
201
202#[derive(Debug, Clone, Serialize, Deserialize)]
204pub struct ErrorResponse {
205 pub error: String,
206 pub message: String,
207}
208
209impl ErrorResponse {
210 pub fn new(error: impl Into<String>, message: impl Into<String>) -> Self {
211 Self {
212 error: error.into(),
213 message: message.into(),
214 }
215 }
216}
217
218impl From<redact_core::RecognizerResult> for EntityResult {
220 fn from(result: redact_core::RecognizerResult) -> Self {
221 Self {
222 entity_type: result.entity_type.as_str().to_string(),
223 start: result.start,
224 end: result.end,
225 score: result.score,
226 text: result.text,
227 recognizer_name: result.recognizer_name,
228 }
229 }
230}
231
232impl From<redact_core::AnalysisMetadata> for AnalysisMetadata {
233 fn from(metadata: redact_core::AnalysisMetadata) -> Self {
234 Self {
235 recognizers_used: metadata.recognizers_used,
236 processing_time_ms: metadata.processing_time_ms,
237 language: metadata.language,
238 model_version: metadata.model_version,
239 }
240 }
241}
242
243impl From<redact_core::Token> for TokenInfo {
244 fn from(token: redact_core::Token) -> Self {
245 Self {
246 token_id: token.token_id,
247 entity_type: token.entity_type.as_str().to_string(),
248 start: token.start,
249 end: token.end,
250 expires_at: token.expires_at.map(|dt| dt.to_rfc3339()),
251 }
252 }
253}