//! Deterministic extraction of shipment identifiers from free text. //! //! Pulled out as its own unit (rather than a method on `DocumentRetriever`) //! purely so it's testable without spinning up a Qdrant connection. use regex::Regex; pub struct ReferenceExtractor { booking_reference_re: Regex, container_number_re: Regex, } impl ReferenceExtractor { pub fn new() -> Self { Self { booking_reference_re: Regex::new(r"\bMSL-[A-Z0-9]{7}\b").expect("valid regex"), container_number_re: Regex::new(r"\b[A-Z]{4}\d{7}\b").expect("valid regex"), } } /// Preferred over asking the LLM to do this: it's cheap, exact, and /// never hallucinates a reference that wasn't actually typed. pub fn extract(&self, query: &str) -> Option { let upper = query.to_uppercase(); self.booking_reference_re .find(&upper) .or_else(|| self.container_number_re.find(&upper)) .map(|m| m.as_str().to_string()) } } impl Default for ReferenceExtractor { fn default() -> Self { Self::new() } } #[cfg(test)] mod tests { use super::*; #[test] fn extracts_booking_reference_case_insensitively() { let r = ReferenceExtractor::new(); assert_eq!( r.extract("where is msl-4b7k921 right now?"), Some("MSL-4B7K921".to_string()) ); } #[test] fn extracts_container_number() { let r = ReferenceExtractor::new(); assert_eq!( r.extract("container MSCU1234567 status please"), Some("MSCU1234567".to_string()) ); } #[test] fn returns_none_when_no_reference_present() { let r = ReferenceExtractor::new(); assert_eq!(r.extract("what are your office hours?"), None); } }