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