Skip to main content

cloudiful_redactor/redactor/
mod.rs

1mod detection;
2mod session;
3mod stats;
4
5use crate::replace::apply_replacements;
6use crate::{
7    Finding, InputKind, LlmConfig, RedactionArtifact, RedactionResult, RedactionSession,
8    RedactorError, RestoreResult, restore_patch_with_session, restore_text_with_session,
9};
10use detection::detect_internal;
11use session::SessionRedactorExt;
12use stats::stats_for;
13
14#[derive(Debug, Clone, Default)]
15pub struct RedactorBuilder {
16    llm: Option<LlmConfig>,
17    person_detection: bool,
18}
19
20impl RedactorBuilder {
21    pub fn new() -> Self {
22        Self::default()
23    }
24
25    pub fn with_llm(mut self, config: LlmConfig) -> Self {
26        self.llm = Some(config);
27        self
28    }
29
30    pub fn with_person_detection(mut self, enabled: bool) -> Self {
31        self.person_detection = enabled;
32        self
33    }
34
35    pub fn build(self) -> Redactor {
36        Redactor {
37            llm: self.llm,
38            person_detection: self.person_detection,
39        }
40    }
41}
42
43#[derive(Debug, Clone)]
44pub struct Redactor {
45    pub(super) llm: Option<LlmConfig>,
46    pub(super) person_detection: bool,
47}
48
49#[derive(Debug, Default)]
50pub struct SessionRedactor {
51    pub(super) processor: crate::replace::ReplacementProcessor,
52}
53
54impl Redactor {
55    pub fn redact(&self, text: &str) -> Result<RedactionResult, RedactorError> {
56        self.redact_with_input_kind(text, InputKind::Text)
57    }
58
59    pub fn redact_with_input_kind(
60        &self,
61        text: &str,
62        input_kind: InputKind,
63    ) -> Result<RedactionResult, RedactorError> {
64        let artifact = self.redact_artifact_with_input_kind(text, input_kind)?;
65        Ok(artifact.result)
66    }
67
68    pub fn redact_artifact(&self, text: &str) -> Result<RedactionArtifact, RedactorError> {
69        self.redact_artifact_with_input_kind(text, InputKind::Text)
70    }
71
72    pub fn redact_artifact_with_input_kind(
73        &self,
74        text: &str,
75        input_kind: InputKind,
76    ) -> Result<RedactionArtifact, RedactorError> {
77        let outcome = detect_internal(self, text, input_kind)?;
78        let findings = outcome.findings;
79        let output = apply_replacements(text, &findings);
80        let stats = stats_for(self.llm.is_some(), &findings, outcome.stats);
81
82        Ok(RedactionArtifact {
83            result: RedactionResult {
84                redacted_text: output.redacted_text,
85                findings,
86                applied_replacements: output.applied_replacements,
87                stats,
88            },
89            session: output.session,
90        })
91    }
92
93    pub fn redact_with_session(&self, text: &str) -> Result<RedactionSession, RedactorError> {
94        self.redact_with_session_input_kind(text, InputKind::Text)
95    }
96
97    pub fn redact_with_session_input_kind(
98        &self,
99        text: &str,
100        input_kind: InputKind,
101    ) -> Result<RedactionSession, RedactorError> {
102        Ok(self
103            .redact_artifact_with_input_kind(text, input_kind)?
104            .session)
105    }
106
107    pub fn detect(&self, text: &str) -> Result<Vec<Finding>, RedactorError> {
108        self.detect_with_input_kind(text, InputKind::Text)
109    }
110
111    pub fn detect_with_input_kind(
112        &self,
113        text: &str,
114        input_kind: InputKind,
115    ) -> Result<Vec<Finding>, RedactorError> {
116        Ok(detect_internal(self, text, input_kind)?.findings)
117    }
118
119    pub fn restore_text(&self, text: &str, session: &RedactionSession) -> RestoreResult {
120        restore_text_with_session(text, session)
121    }
122
123    pub fn restore_patch(&self, patch: &str, session: &RedactionSession) -> RestoreResult {
124        restore_patch_with_session(patch, session)
125    }
126}
127
128impl SessionRedactor {
129    pub fn new() -> Self {
130        Self::default()
131    }
132
133    pub fn redact_fragment(
134        &mut self,
135        redactor: &Redactor,
136        text: &str,
137    ) -> Result<String, RedactorError> {
138        self.redact_text_fragment(redactor, text)
139    }
140
141    pub fn build_session(&self, original_text: &str, redacted_text: &str) -> RedactionSession {
142        self.build_redaction_session(original_text, redacted_text)
143    }
144
145    pub fn max_token_len(&self) -> usize {
146        self.max_replacement_token_len()
147    }
148}