1pub mod encoder;
11pub mod hard_negatives;
12pub mod rerank;
13pub mod cross_encoder;
14pub mod calibration;
15pub mod isotonic_calibration;
16pub mod sla_bounded_evaluation;
17pub mod pipeline;
18pub mod validation;
19pub mod ltr_trainer;
20
21pub mod embedding;
23pub mod query_classifier;
24pub mod intent_router;
25pub mod conformal_router;
26pub mod benchmarks;
27pub mod integration;
28pub mod examples;
29
30pub use pipeline::{SemanticPipeline, SemanticSearchRequest, SemanticSearchResponse, initialize_semantic_pipeline};
32pub use encoder::{SemanticEncoder, CodeEmbedding};
33pub use rerank::{LearnedReranker, SearchResult, RerankedResult};
34pub use cross_encoder::{CrossEncoder, QueryAnalysis};
35pub use calibration::{CalibrationSystem, CalibrationMetrics};
36pub use isotonic_calibration::{IsotonicCalibrationSystem, IsotonicCalibrationConfig, CalibrationTrainingSample};
37pub use sla_bounded_evaluation::{SLABoundedEvaluator, SLAEvaluationConfig, SLABoundedEvaluationResult};
38pub use hard_negatives::{HardNegativesGenerator, ContrastivePair};
39pub use validation::{validate_phase3_implementation, ValidationResults};
40pub use ltr_trainer::{LTRTrainer, LTRConfig, LTRObjective, BoundedLTRModel, TrainingReport};
41
42pub use embedding::{SemanticEncoder as RustSemanticEncoder, CodeEmbedding as RustCodeEmbedding, EmbeddingConfig};
44pub use query_classifier::{QueryClassifier, QueryClassification, QueryIntent as RustQueryIntent, ClassifierConfig};
45pub use intent_router::{IntentRouter, IntentRouterConfig};
46pub use conformal_router::{ConformalRouter, ConformalRouterConfig, UpshiftType};
47pub use integration::{
48 SemanticSearchIntegration,
49 SemanticIntegrationConfig,
50 SemanticSearchRequest as IntegratedSemanticSearchRequest,
51 SemanticSearchResponse as IntegratedSemanticSearchResponse,
52 SearchEngineSemanticExt,
53 SemanticHealthStatus,
54 IntegrationMetrics,
55};
56
57use anyhow::Result;
58use serde::{Deserialize, Serialize};
59use std::time::Duration;
60
61#[derive(Debug, Clone, Serialize, Deserialize)]
63pub struct SemanticConfig {
64 pub encoder: EncoderConfig,
66 pub rerank: RerankConfig,
68 pub cross_encoder: CrossEncoderConfig,
70 pub calibration: CalibrationConfig,
72}
73
74#[derive(Debug, Clone, Serialize, Deserialize)]
75pub struct EncoderConfig {
76 pub model_type: String,
78 pub max_tokens: usize,
80 pub embedding_dim: usize,
82 pub batch_size: usize,
84 pub device: String,
86}
87
88#[derive(Debug, Clone, Serialize, Deserialize)]
89pub struct RerankConfig {
90 pub top_k: usize,
92 pub use_isotonic: bool,
94 pub learning_rate: f32,
96}
97
98#[derive(Debug, Clone, Serialize, Deserialize)]
99pub struct CrossEncoderConfig {
100 pub enabled: bool,
102 pub max_inference_ms: u64,
104 pub complexity_threshold: f32,
106 pub top_k: usize,
108}
109
110#[derive(Debug, Clone, Serialize, Deserialize)]
111pub struct CalibrationConfig {
112 pub max_ece_drift: f32,
114 pub log_odds_cap: f32,
116 pub temperature: f32,
118}
119
120impl Default for SemanticConfig {
121 fn default() -> Self {
122 Self {
123 encoder: EncoderConfig {
124 model_type: "codet5-base".to_string(),
125 max_tokens: 2048,
126 embedding_dim: 768,
127 batch_size: 16,
128 device: "cpu".to_string(),
129 },
130 rerank: RerankConfig {
131 top_k: 100,
132 use_isotonic: true,
133 learning_rate: 0.01,
134 },
135 cross_encoder: CrossEncoderConfig {
136 enabled: false, max_inference_ms: 50,
138 complexity_threshold: 0.7,
139 top_k: 10,
140 },
141 calibration: CalibrationConfig {
142 max_ece_drift: 0.005,
143 log_odds_cap: 5.0,
144 temperature: 1.0,
145 },
146 }
147 }
148}
149
150pub const SEMANTIC_INFERENCE_TARGET_MS: u64 = 50;
152pub const SEMANTIC_P95_TARGET_MS: u64 = 50;
153pub const COIR_NDCG_TARGET: f32 = 0.52;
154pub const NL_IMPROVEMENT_TARGET_PP: f32 = 4.0; #[derive(Debug, Clone, Serialize, Deserialize)]
158pub struct SemanticMetrics {
159 pub latency_p50_ms: f64,
161 pub latency_p95_ms: f64,
162 pub latency_p99_ms: f64,
163
164 pub ndcg_at_10: f32,
166 pub success_at_10: f32,
167 pub recall_at_50: f32,
168
169 pub expected_calibration_error: f32,
171 pub ece_drift_from_baseline: f32,
172
173 pub nl_slice_improvement_pp: f32,
175
176 pub meets_coir_target: bool,
178 pub meets_latency_target: bool,
179 pub meets_ece_target: bool,
180}
181
182impl SemanticMetrics {
183 pub fn passes_gates(&self) -> bool {
185 self.meets_coir_target && self.meets_latency_target && self.meets_ece_target
186 }
187
188 pub fn validate_phase3_gates(&self) -> Result<()> {
190 if self.ndcg_at_10 < COIR_NDCG_TARGET {
191 anyhow::bail!(
192 "CoIR nDCG@10 {} < target {}",
193 self.ndcg_at_10,
194 COIR_NDCG_TARGET
195 );
196 }
197
198 if self.latency_p95_ms > SEMANTIC_P95_TARGET_MS as f64 {
199 anyhow::bail!(
200 "Semantic p95 latency {}ms > target {}ms",
201 self.latency_p95_ms,
202 SEMANTIC_P95_TARGET_MS
203 );
204 }
205
206 if self.ece_drift_from_baseline > 0.005 {
207 anyhow::bail!(
208 "ECE drift {} > target 0.005",
209 self.ece_drift_from_baseline
210 );
211 }
212
213 if self.nl_slice_improvement_pp < NL_IMPROVEMENT_TARGET_PP {
214 anyhow::bail!(
215 "NL improvement {}pp < target {}pp",
216 self.nl_slice_improvement_pp,
217 NL_IMPROVEMENT_TARGET_PP
218 );
219 }
220
221 Ok(())
222 }
223}
224
225pub async fn initialize_semantic_integration(config: &SemanticConfig) -> Result<SemanticSearchIntegration> {
227 tracing::info!("Initializing Rust-based semantic integration system");
228
229 let integration_config = SemanticIntegrationConfig {
230 enabled: true,
231 nl_upshift_threshold: 0.7,
232 max_processing_time_ms: 100, enable_conformal_routing: true,
234 fallback_on_error: true,
235 enable_result_caching: config.cross_encoder.enabled,
236 similarity_threshold: 0.5,
237 };
238
239 let integration = SemanticSearchIntegration::new(integration_config).await?;
240
241 tracing::info!("✅ Rust-based semantic integration system initialized successfully");
242 Ok(integration)
243}
244
245pub async fn initialize_semantic(config: &SemanticConfig) -> Result<()> {
247 tracing::info!("Initializing semantic search module");
248 tracing::info!("Encoder: {} with {} tokens", config.encoder.model_type, config.encoder.max_tokens);
249 tracing::info!("Rerank: top-{} with isotonic={}", config.rerank.top_k, config.rerank.use_isotonic);
250 tracing::info!("Cross-encoder: enabled={}", config.cross_encoder.enabled);
251 tracing::info!("Performance targets: CoIR nDCG@10 ≥ {}, p95 ≤ {}ms",
252 COIR_NDCG_TARGET, SEMANTIC_P95_TARGET_MS);
253
254 encoder::initialize_encoder(&config.encoder).await?;
256
257 let rerank_config = rerank::RerankConfig {
259 top_k: config.rerank.top_k,
260 use_isotonic: config.rerank.use_isotonic,
261 learning_rate: config.rerank.learning_rate,
262 l2_regularization: 0.01, min_training_samples: 100, combination_strategy: rerank::CombinationStrategy::LearnedWeights,
265 };
266 rerank::initialize_reranker(&rerank_config).await?;
267
268 if config.cross_encoder.enabled {
270 let cross_encoder_config = cross_encoder::CrossEncoderConfig {
271 enabled: config.cross_encoder.enabled,
272 max_inference_ms: config.cross_encoder.max_inference_ms,
273 complexity_threshold: config.cross_encoder.complexity_threshold,
274 top_k: config.cross_encoder.top_k,
275 model_type: "bert-base-uncased".to_string(), max_batch_size: 16, budget_strategy: cross_encoder::BudgetStrategy::FixedPerQuery,
278 };
279 cross_encoder::initialize_cross_encoder(&cross_encoder_config).await?;
280 }
281
282 let calibration_config = calibration::CalibrationConfig {
284 max_ece_drift: config.calibration.max_ece_drift,
285 log_odds_cap: config.calibration.log_odds_cap,
286 temperature: config.calibration.temperature,
287 min_samples_for_calibration: 1000, measurement_window_size: 10000, auto_temperature_adjustment: true, };
291 calibration::initialize_calibration(&calibration_config).await?;
292
293 tracing::info!("Semantic search module initialized successfully");
294 Ok(())
295}
296
297#[cfg(test)]
298mod tests {
299 use super::*;
300
301 #[test]
302 fn test_semantic_config_default() {
303 let config = SemanticConfig::default();
304 assert_eq!(config.encoder.max_tokens, 2048);
305 assert_eq!(config.encoder.model_type, "codet5-base");
306 assert!(config.rerank.use_isotonic);
307 assert!(!config.cross_encoder.enabled); }
309
310 #[test]
311 fn test_semantic_metrics_validation() {
312 let mut metrics = SemanticMetrics {
313 latency_p50_ms: 25.0,
314 latency_p95_ms: 45.0, latency_p99_ms: 75.0,
316 ndcg_at_10: 0.53, success_at_10: 0.65,
318 recall_at_50: 0.85,
319 expected_calibration_error: 0.012,
320 ece_drift_from_baseline: 0.003, nl_slice_improvement_pp: 5.2, meets_coir_target: true,
323 meets_latency_target: true,
324 meets_ece_target: true,
325 };
326
327 assert!(metrics.validate_phase3_gates().is_ok());
329
330 metrics.ndcg_at_10 = 0.49; assert!(metrics.validate_phase3_gates().is_err());
333
334 metrics.ndcg_at_10 = 0.53;
335 metrics.latency_p95_ms = 65.0; assert!(metrics.validate_phase3_gates().is_err());
337 }
338}