Coverage for src/qdrant_loader_mcp_server/search/enhanced/intent/models.py: 95%
58 statements
« prev ^ index » next coverage.py v7.10.6, created at 2025-09-08 06:06 +0000
« prev ^ index » next coverage.py v7.10.6, created at 2025-09-08 06:06 +0000
1"""
2Core data models for intent classification and adaptive search.
4This module defines the fundamental data types used throughout the intent
5classification system, including intent types, search intent containers,
6and adaptive search configurations.
7"""
9from __future__ import annotations
11from dataclasses import dataclass, field
12from enum import Enum
13from typing import TYPE_CHECKING, Any
15if TYPE_CHECKING:
16 from ..knowledge_graph import TraversalStrategy
17else:
18 # Runtime import to avoid circular dependencies
19 try:
20 from ..knowledge_graph import TraversalStrategy
21 except ImportError:
22 # Fallback if knowledge_graph isn't available
23 TraversalStrategy = None
26# Sentinel to distinguish between an explicit None and an omitted argument
27_UNSET = object()
30class IntentType(Enum):
31 """Types of search intents for adaptive search strategies."""
33 TECHNICAL_LOOKUP = "technical_lookup" # API docs, code examples, implementation
34 BUSINESS_CONTEXT = "business_context" # Requirements, objectives, strategy
35 VENDOR_EVALUATION = "vendor_evaluation" # Proposals, comparisons, criteria
36 PROCEDURAL = "procedural" # How-to guides, step-by-step
37 INFORMATIONAL = "informational" # What is, definitions, overviews
38 EXPLORATORY = "exploratory" # Broad discovery, browsing
39 TROUBLESHOOTING = "troubleshooting" # Error solving, debugging
40 GENERAL = "general" # Fallback for unclear intent
43@dataclass
44class SearchIntent:
45 """Container for classified search intent with confidence and context."""
47 intent_type: IntentType
48 confidence: float # 0.0 - 1.0 confidence score
49 secondary_intents: list[tuple[IntentType, float]] = field(default_factory=list)
51 # Linguistic evidence
52 supporting_evidence: dict[str, Any] = field(default_factory=dict)
53 linguistic_features: dict[str, Any] = field(default_factory=dict)
55 # Context information
56 query_complexity: float = 0.0 # From spaCy analysis
57 is_question: bool = False
58 is_technical: bool = False
60 # Behavioral context
61 session_context: dict[str, Any] = field(default_factory=dict)
62 previous_intents: list[IntentType] = field(default_factory=list)
64 # Processing metadata
65 classification_time_ms: float = 0.0
68@dataclass
69class AdaptiveSearchConfig:
70 """Configuration for adaptive search based on intent."""
72 # Core search parameters
73 search_strategy: str = "hybrid" # hybrid, vector, keyword
74 vector_weight: float = 0.7 # Weight for vector search
75 keyword_weight: float = 0.3 # Weight for keyword search
77 # Knowledge graph integration
78 use_knowledge_graph: bool = False
79 # Use Optional[TraversalStrategy] while leveraging a sentinel default to detect omission
80 kg_traversal_strategy: TraversalStrategy | None = field(default=_UNSET)
81 max_graph_hops: int = 2
82 kg_expansion_weight: float = 0.2
84 # Result filtering and ranking
85 result_filters: dict[str, Any] = field(default_factory=dict)
86 ranking_boosts: dict[str, float] = field(default_factory=dict)
87 source_type_preferences: dict[str, float] = field(default_factory=dict)
89 # Query expansion
90 expand_query: bool = True
91 expansion_aggressiveness: float = 0.3 # 0.0 - 1.0
92 semantic_expansion: bool = True
93 entity_expansion: bool = True
95 # Performance tuning
96 max_results: int = 20
97 min_score_threshold: float = 0.1
98 diversity_factor: float = 0.0 # 0.0 = relevance only, 1.0 = max diversity
100 # Contextual parameters
101 temporal_bias: float = 0.0 # Bias toward recent content
102 authority_bias: float = 0.0 # Bias toward authoritative sources
103 personal_bias: float = 0.0 # Bias toward user's previous interests
105 def __post_init__(self):
106 """Assign default TraversalStrategy only when the field was omitted.
108 This preserves explicit None values provided by callers.
109 """
110 if self.kg_traversal_strategy is _UNSET:
111 if TraversalStrategy is not None:
112 self.kg_traversal_strategy = TraversalStrategy.SEMANTIC
113 else:
114 # If TraversalStrategy isn't available at runtime, keep as None
115 self.kg_traversal_strategy = None