cloudiful_redactor/redactor/
mod.rs1mod 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}