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