1use serde::{Deserialize, Serialize};
11
12#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct AdaptiveRoutingConfig {
15 pub enabled: bool,
17
18 pub default_level: usize,
20
21 pub max_level: usize,
23
24 pub keyword_weight: f32,
26
27 pub length_weight: f32,
29
30 pub entity_weight: f32,
32}
33
34impl Default for AdaptiveRoutingConfig {
35 fn default() -> Self {
36 Self {
37 enabled: true,
38 default_level: 1,
39 max_level: 3,
40 keyword_weight: 0.5,
41 length_weight: 0.3,
42 entity_weight: 0.2,
43 }
44 }
45}
46
47#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
49pub enum QueryComplexity {
50 VeryBroad,
52 Broad,
54 Medium,
56 Specific,
58 VerySpecific,
60}
61
62impl QueryComplexity {
63 pub fn to_level(self, max_level: usize) -> usize {
65 match self {
66 QueryComplexity::VeryBroad => max_level.max(2),
67 QueryComplexity::Broad => (max_level - 1).max(1),
68 QueryComplexity::Medium => 1,
69 QueryComplexity::Specific => 0,
70 QueryComplexity::VerySpecific => 0,
71 }
72 }
73}
74
75#[derive(Debug)]
77pub struct QueryComplexityAnalyzer {
78 config: AdaptiveRoutingConfig,
79
80 broad_keywords: Vec<&'static str>,
82 specific_keywords: Vec<&'static str>,
83}
84
85impl QueryComplexityAnalyzer {
86 pub fn new(config: AdaptiveRoutingConfig) -> Self {
88 Self {
89 config,
90 broad_keywords: vec![
91 "overview",
92 "summary",
93 "summarize",
94 "main",
95 "general",
96 "all",
97 "themes",
98 "topics",
99 "overall",
100 "broadly",
101 "big picture",
102 "what are",
103 "list all",
104 "show me all",
105 ],
106 specific_keywords: vec![
107 "relationship between",
108 "how does",
109 "why does",
110 "specific",
111 "detail",
112 "exactly",
113 "precisely",
114 "what is the connection",
115 "explain how",
116 "describe the",
117 "between",
118 "and",
119 ],
120 }
121 }
122
123 pub fn analyze(&self, query: &str) -> QueryComplexity {
125 let query_lower = query.to_lowercase();
126
127 let keyword_score = self.analyze_keywords(&query_lower);
129 let length_score = self.analyze_length(query);
130 let entity_score = self.analyze_entity_mentions(&query_lower);
131
132 let total_score = keyword_score * self.config.keyword_weight
134 + length_score * self.config.length_weight
135 + entity_score * self.config.entity_weight;
136
137 if total_score >= 0.7 {
139 QueryComplexity::VeryBroad
140 } else if total_score >= 0.4 {
141 QueryComplexity::Broad
142 } else if total_score >= -0.2 {
143 QueryComplexity::Medium
144 } else if total_score >= -0.5 {
145 QueryComplexity::Specific
146 } else {
147 QueryComplexity::VerySpecific
148 }
149 }
150
151 fn analyze_keywords(&self, query_lower: &str) -> f32 {
153 let mut score = 0.0;
154 let mut matches = 0;
155
156 for keyword in &self.broad_keywords {
158 if query_lower.contains(keyword) {
159 score += 1.0;
160 matches += 1;
161 }
162 }
163
164 for keyword in &self.specific_keywords {
166 if query_lower.contains(keyword) {
167 score -= 1.0;
168 matches += 1;
169 }
170 }
171
172 if matches > 0 {
174 score / matches as f32
175 } else {
176 0.0 }
178 }
179
180 fn analyze_length(&self, query: &str) -> f32 {
182 let words: Vec<&str> = query.split_whitespace().collect();
183 let word_count = words.len();
184
185 match word_count {
188 1..=3 => 0.5, 4..=5 => 0.2, 6..=7 => 0.0, 8..=10 => -0.3, _ => -0.5, }
194 }
195
196 fn analyze_entity_mentions(&self, query_lower: &str) -> f32 {
198 let quoted_count = query_lower.matches('"').count() / 2;
201 let and_between = query_lower.matches(" and ").count();
202 let between_count = query_lower.matches("between").count();
203
204 let entity_indicators = quoted_count + and_between + between_count;
205
206 match entity_indicators {
208 0 => 0.3, 1 => 0.0, 2 => -0.4, _ => -0.7, }
213 }
214
215 pub fn suggest_level(&self, query: &str) -> usize {
217 let complexity = self.analyze(query);
218 complexity.to_level(self.config.max_level)
219 }
220
221 pub fn analyze_detailed(&self, query: &str) -> QueryAnalysis {
223 let query_lower = query.to_lowercase();
224
225 let keyword_score = self.analyze_keywords(&query_lower);
226 let length_score = self.analyze_length(query);
227 let entity_score = self.analyze_entity_mentions(&query_lower);
228
229 let complexity = self.analyze(query);
230 let suggested_level = complexity.to_level(self.config.max_level);
231
232 QueryAnalysis {
233 query: query.to_string(),
234 complexity,
235 suggested_level,
236 keyword_score,
237 length_score,
238 entity_score,
239 explanation: self.generate_explanation(complexity, suggested_level),
240 }
241 }
242
243 fn generate_explanation(&self, complexity: QueryComplexity, level: usize) -> String {
245 match complexity {
246 QueryComplexity::VeryBroad => format!(
247 "Very broad query detected → using level {} for high-level overview",
248 level
249 ),
250 QueryComplexity::Broad => format!(
251 "Broad query detected → using level {} for general understanding",
252 level
253 ),
254 QueryComplexity::Medium => format!(
255 "Medium complexity query → using level {} for balanced detail",
256 level
257 ),
258 QueryComplexity::Specific => format!(
259 "Specific query detected → using level {} for detailed information",
260 level
261 ),
262 QueryComplexity::VerySpecific => format!(
263 "Very specific query detected → using level {} for precise relationships",
264 level
265 ),
266 }
267 }
268}
269
270#[derive(Debug, Clone, Serialize, Deserialize)]
272pub struct QueryAnalysis {
273 pub query: String,
275 pub complexity: QueryComplexity,
277 pub suggested_level: usize,
279 pub keyword_score: f32,
281 pub length_score: f32,
283 pub entity_score: f32,
285 pub explanation: String,
287}
288
289impl QueryAnalysis {
290 pub fn print(&self) {
292 println!("Query Analysis:");
293 println!(" Query: \"{}\"", self.query);
294 println!(" Complexity: {:?}", self.complexity);
295 println!(" Suggested Level: {}", self.suggested_level);
296 println!(" Scores:");
297 println!(" - Keywords: {:.2}", self.keyword_score);
298 println!(" - Length: {:.2}", self.length_score);
299 println!(" - Entities: {:.2}", self.entity_score);
300 println!(" {}", self.explanation);
301 }
302}
303
304#[cfg(test)]
305mod tests {
306 use super::*;
307
308 #[test]
309 fn test_broad_query() {
310 let config = AdaptiveRoutingConfig::default();
311 let analyzer = QueryComplexityAnalyzer::new(config);
312
313 let query = "Give me an overview of AI technologies";
314 let complexity = analyzer.analyze(query);
315 let level = analyzer.suggest_level(query);
316
317 assert!(matches!(
319 complexity,
320 QueryComplexity::VeryBroad | QueryComplexity::Broad
321 ));
322 assert!(level >= 1);
323 }
324
325 #[test]
326 fn test_specific_query() {
327 let config = AdaptiveRoutingConfig::default();
328 let analyzer = QueryComplexityAnalyzer::new(config);
329
330 let query = "What is the relationship between Transformers and GPT?";
331 let complexity = analyzer.analyze(query);
332 let level = analyzer.suggest_level(query);
333
334 assert!(matches!(
336 complexity,
337 QueryComplexity::Specific | QueryComplexity::VerySpecific
338 ));
339 assert_eq!(level, 0);
340 }
341
342 #[test]
343 fn test_medium_query() {
344 let config = AdaptiveRoutingConfig::default();
345 let analyzer = QueryComplexityAnalyzer::new(config);
346
347 let query = "How does machine learning work?";
348 let level = analyzer.suggest_level(query);
349
350 assert!(level <= 1);
352 }
353
354 #[test]
355 fn test_detailed_analysis() {
356 let config = AdaptiveRoutingConfig::default();
357 let analyzer = QueryComplexityAnalyzer::new(config);
358
359 let query = "Summarize the main themes";
360 let analysis = analyzer.analyze_detailed(query);
361
362 assert!(analysis.keyword_score > 0.0); assert!(!analysis.explanation.is_empty());
364 }
365}