fix: integrate LLM verifier into proxy handler, remove dead dependency
- Integrate LlmVerifier into scan_and_redact(): when classification is sensitive_partial, split entities by confidence, verify low-confidence ones via RKLLM, rebuild summary from verified entities - Pass verifier from proxy.rs process_upload() to scanner - Remove #[allow(dead_code)] from llm_verifier field - Remove unused multer dependency from Cargo.toml Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -26,9 +26,6 @@ axum = { version = "0.8", features = ["multipart"] }
|
||||
# HTTP client for info-privacy-rs, RKLLM, KVM backend
|
||||
reqwest = { version = "0.12", features = ["json", "multipart"] }
|
||||
|
||||
# Multipart parsing
|
||||
multer = "3"
|
||||
|
||||
# MariaDB audit logging
|
||||
sqlx = { version = "0.8", features = ["mysql", "runtime-tokio", "chrono"] }
|
||||
|
||||
|
||||
@@ -33,7 +33,6 @@ pub struct ProxyState {
|
||||
pub info_privacy_url: String,
|
||||
/// LLM verifier for false-positive reduction (used when scanner
|
||||
/// returns sensitive_partial classification)
|
||||
#[allow(dead_code)]
|
||||
pub llm_verifier: Arc<LlmVerifier>,
|
||||
/// Audit logger (optional — None if MariaDB is unavailable)
|
||||
pub audit: Option<AuditLogger>,
|
||||
@@ -194,6 +193,7 @@ impl PrivacyProxyHandler {
|
||||
&self.state.info_privacy_url,
|
||||
&f.filename,
|
||||
&f.data,
|
||||
Some(self.state.llm_verifier.as_ref()),
|
||||
)
|
||||
.await;
|
||||
|
||||
|
||||
@@ -76,7 +76,8 @@ struct AnalyzeResponse {
|
||||
/// Steps:
|
||||
/// 1. Call POST /api/v1/analyze with the file as multipart upload
|
||||
/// 2. Parse the detection report
|
||||
/// 3. If PII found, call POST /api/v1/redact to get redacted file bytes
|
||||
/// 3. If sensitive_partial AND verifier provided: LLM-verify low-confidence entities
|
||||
/// 4. If PII found, call POST /api/v1/redact to get redacted file bytes
|
||||
///
|
||||
/// Returns `Err` on network/HTTP errors (caller decides whether to block or allow).
|
||||
pub async fn scan_and_redact(
|
||||
@@ -84,6 +85,7 @@ pub async fn scan_and_redact(
|
||||
base_url: &str,
|
||||
filename: &str,
|
||||
data: &[u8],
|
||||
verifier: Option<&crate::llm_verifier::LlmVerifier>,
|
||||
) -> Result<ScanResult, ScanError> {
|
||||
let original_hash = hex_sha256(data);
|
||||
|
||||
@@ -128,9 +130,37 @@ pub async fn scan_and_redact(
|
||||
});
|
||||
}
|
||||
|
||||
// Use the summary from the report (LLM verification is done by llm_verifier
|
||||
// at a higher level if needed)
|
||||
let summary = report.summary;
|
||||
// LLM verification for sensitive_partial with low-confidence entities
|
||||
let summary = if report.classification == "sensitive_partial" {
|
||||
if let Some(v) = verifier {
|
||||
let (high_conf, low_conf) = split_by_confidence(&report.entities);
|
||||
if !low_conf.is_empty() {
|
||||
let context = if report.doc_id.is_empty() {
|
||||
filename.to_string()
|
||||
} else {
|
||||
report.doc_id.clone()
|
||||
};
|
||||
let verified = v.verify_detections(&context, &low_conf).await;
|
||||
let mut all_verified = high_conf;
|
||||
all_verified.extend(verified);
|
||||
if all_verified.is_empty() {
|
||||
return Ok(ScanResult {
|
||||
pii_found: false,
|
||||
pii_types: HashMap::new(),
|
||||
redacted_bytes: None,
|
||||
original_hash,
|
||||
});
|
||||
}
|
||||
build_summary(&all_verified)
|
||||
} else {
|
||||
report.summary
|
||||
}
|
||||
} else {
|
||||
report.summary
|
||||
}
|
||||
} else {
|
||||
report.summary
|
||||
};
|
||||
|
||||
// Step 2: Redact
|
||||
let redact_types: Vec<String> = summary.keys().cloned().collect();
|
||||
|
||||
Reference in New Issue
Block a user