aiecs 1.5.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (302) hide show
  1. aiecs/__init__.py +72 -0
  2. aiecs/__main__.py +41 -0
  3. aiecs/aiecs_client.py +469 -0
  4. aiecs/application/__init__.py +10 -0
  5. aiecs/application/executors/__init__.py +10 -0
  6. aiecs/application/executors/operation_executor.py +363 -0
  7. aiecs/application/knowledge_graph/__init__.py +7 -0
  8. aiecs/application/knowledge_graph/builder/__init__.py +37 -0
  9. aiecs/application/knowledge_graph/builder/document_builder.py +375 -0
  10. aiecs/application/knowledge_graph/builder/graph_builder.py +356 -0
  11. aiecs/application/knowledge_graph/builder/schema_mapping.py +531 -0
  12. aiecs/application/knowledge_graph/builder/structured_pipeline.py +443 -0
  13. aiecs/application/knowledge_graph/builder/text_chunker.py +319 -0
  14. aiecs/application/knowledge_graph/extractors/__init__.py +27 -0
  15. aiecs/application/knowledge_graph/extractors/base.py +100 -0
  16. aiecs/application/knowledge_graph/extractors/llm_entity_extractor.py +327 -0
  17. aiecs/application/knowledge_graph/extractors/llm_relation_extractor.py +349 -0
  18. aiecs/application/knowledge_graph/extractors/ner_entity_extractor.py +244 -0
  19. aiecs/application/knowledge_graph/fusion/__init__.py +23 -0
  20. aiecs/application/knowledge_graph/fusion/entity_deduplicator.py +387 -0
  21. aiecs/application/knowledge_graph/fusion/entity_linker.py +343 -0
  22. aiecs/application/knowledge_graph/fusion/knowledge_fusion.py +580 -0
  23. aiecs/application/knowledge_graph/fusion/relation_deduplicator.py +189 -0
  24. aiecs/application/knowledge_graph/pattern_matching/__init__.py +21 -0
  25. aiecs/application/knowledge_graph/pattern_matching/pattern_matcher.py +344 -0
  26. aiecs/application/knowledge_graph/pattern_matching/query_executor.py +378 -0
  27. aiecs/application/knowledge_graph/profiling/__init__.py +12 -0
  28. aiecs/application/knowledge_graph/profiling/query_plan_visualizer.py +199 -0
  29. aiecs/application/knowledge_graph/profiling/query_profiler.py +223 -0
  30. aiecs/application/knowledge_graph/reasoning/__init__.py +27 -0
  31. aiecs/application/knowledge_graph/reasoning/evidence_synthesis.py +347 -0
  32. aiecs/application/knowledge_graph/reasoning/inference_engine.py +504 -0
  33. aiecs/application/knowledge_graph/reasoning/logic_form_parser.py +167 -0
  34. aiecs/application/knowledge_graph/reasoning/logic_parser/__init__.py +79 -0
  35. aiecs/application/knowledge_graph/reasoning/logic_parser/ast_builder.py +513 -0
  36. aiecs/application/knowledge_graph/reasoning/logic_parser/ast_nodes.py +630 -0
  37. aiecs/application/knowledge_graph/reasoning/logic_parser/ast_validator.py +654 -0
  38. aiecs/application/knowledge_graph/reasoning/logic_parser/error_handler.py +477 -0
  39. aiecs/application/knowledge_graph/reasoning/logic_parser/parser.py +390 -0
  40. aiecs/application/knowledge_graph/reasoning/logic_parser/query_context.py +217 -0
  41. aiecs/application/knowledge_graph/reasoning/logic_query_integration.py +169 -0
  42. aiecs/application/knowledge_graph/reasoning/query_planner.py +872 -0
  43. aiecs/application/knowledge_graph/reasoning/reasoning_engine.py +554 -0
  44. aiecs/application/knowledge_graph/retrieval/__init__.py +19 -0
  45. aiecs/application/knowledge_graph/retrieval/retrieval_strategies.py +596 -0
  46. aiecs/application/knowledge_graph/search/__init__.py +59 -0
  47. aiecs/application/knowledge_graph/search/hybrid_search.py +423 -0
  48. aiecs/application/knowledge_graph/search/reranker.py +295 -0
  49. aiecs/application/knowledge_graph/search/reranker_strategies.py +553 -0
  50. aiecs/application/knowledge_graph/search/text_similarity.py +398 -0
  51. aiecs/application/knowledge_graph/traversal/__init__.py +15 -0
  52. aiecs/application/knowledge_graph/traversal/enhanced_traversal.py +329 -0
  53. aiecs/application/knowledge_graph/traversal/path_scorer.py +269 -0
  54. aiecs/application/knowledge_graph/validators/__init__.py +13 -0
  55. aiecs/application/knowledge_graph/validators/relation_validator.py +189 -0
  56. aiecs/application/knowledge_graph/visualization/__init__.py +11 -0
  57. aiecs/application/knowledge_graph/visualization/graph_visualizer.py +321 -0
  58. aiecs/common/__init__.py +9 -0
  59. aiecs/common/knowledge_graph/__init__.py +17 -0
  60. aiecs/common/knowledge_graph/runnable.py +484 -0
  61. aiecs/config/__init__.py +16 -0
  62. aiecs/config/config.py +498 -0
  63. aiecs/config/graph_config.py +137 -0
  64. aiecs/config/registry.py +23 -0
  65. aiecs/core/__init__.py +46 -0
  66. aiecs/core/interface/__init__.py +34 -0
  67. aiecs/core/interface/execution_interface.py +152 -0
  68. aiecs/core/interface/storage_interface.py +171 -0
  69. aiecs/domain/__init__.py +289 -0
  70. aiecs/domain/agent/__init__.py +189 -0
  71. aiecs/domain/agent/base_agent.py +697 -0
  72. aiecs/domain/agent/exceptions.py +103 -0
  73. aiecs/domain/agent/graph_aware_mixin.py +559 -0
  74. aiecs/domain/agent/hybrid_agent.py +490 -0
  75. aiecs/domain/agent/integration/__init__.py +26 -0
  76. aiecs/domain/agent/integration/context_compressor.py +222 -0
  77. aiecs/domain/agent/integration/context_engine_adapter.py +252 -0
  78. aiecs/domain/agent/integration/retry_policy.py +219 -0
  79. aiecs/domain/agent/integration/role_config.py +213 -0
  80. aiecs/domain/agent/knowledge_aware_agent.py +646 -0
  81. aiecs/domain/agent/lifecycle.py +296 -0
  82. aiecs/domain/agent/llm_agent.py +300 -0
  83. aiecs/domain/agent/memory/__init__.py +12 -0
  84. aiecs/domain/agent/memory/conversation.py +197 -0
  85. aiecs/domain/agent/migration/__init__.py +14 -0
  86. aiecs/domain/agent/migration/conversion.py +160 -0
  87. aiecs/domain/agent/migration/legacy_wrapper.py +90 -0
  88. aiecs/domain/agent/models.py +317 -0
  89. aiecs/domain/agent/observability.py +407 -0
  90. aiecs/domain/agent/persistence.py +289 -0
  91. aiecs/domain/agent/prompts/__init__.py +29 -0
  92. aiecs/domain/agent/prompts/builder.py +161 -0
  93. aiecs/domain/agent/prompts/formatters.py +189 -0
  94. aiecs/domain/agent/prompts/template.py +255 -0
  95. aiecs/domain/agent/registry.py +260 -0
  96. aiecs/domain/agent/tool_agent.py +257 -0
  97. aiecs/domain/agent/tools/__init__.py +12 -0
  98. aiecs/domain/agent/tools/schema_generator.py +221 -0
  99. aiecs/domain/community/__init__.py +155 -0
  100. aiecs/domain/community/agent_adapter.py +477 -0
  101. aiecs/domain/community/analytics.py +481 -0
  102. aiecs/domain/community/collaborative_workflow.py +642 -0
  103. aiecs/domain/community/communication_hub.py +645 -0
  104. aiecs/domain/community/community_builder.py +320 -0
  105. aiecs/domain/community/community_integration.py +800 -0
  106. aiecs/domain/community/community_manager.py +813 -0
  107. aiecs/domain/community/decision_engine.py +879 -0
  108. aiecs/domain/community/exceptions.py +225 -0
  109. aiecs/domain/community/models/__init__.py +33 -0
  110. aiecs/domain/community/models/community_models.py +268 -0
  111. aiecs/domain/community/resource_manager.py +457 -0
  112. aiecs/domain/community/shared_context_manager.py +603 -0
  113. aiecs/domain/context/__init__.py +58 -0
  114. aiecs/domain/context/context_engine.py +989 -0
  115. aiecs/domain/context/conversation_models.py +354 -0
  116. aiecs/domain/context/graph_memory.py +467 -0
  117. aiecs/domain/execution/__init__.py +12 -0
  118. aiecs/domain/execution/model.py +57 -0
  119. aiecs/domain/knowledge_graph/__init__.py +19 -0
  120. aiecs/domain/knowledge_graph/models/__init__.py +52 -0
  121. aiecs/domain/knowledge_graph/models/entity.py +130 -0
  122. aiecs/domain/knowledge_graph/models/evidence.py +194 -0
  123. aiecs/domain/knowledge_graph/models/inference_rule.py +186 -0
  124. aiecs/domain/knowledge_graph/models/path.py +179 -0
  125. aiecs/domain/knowledge_graph/models/path_pattern.py +173 -0
  126. aiecs/domain/knowledge_graph/models/query.py +272 -0
  127. aiecs/domain/knowledge_graph/models/query_plan.py +187 -0
  128. aiecs/domain/knowledge_graph/models/relation.py +136 -0
  129. aiecs/domain/knowledge_graph/schema/__init__.py +23 -0
  130. aiecs/domain/knowledge_graph/schema/entity_type.py +135 -0
  131. aiecs/domain/knowledge_graph/schema/graph_schema.py +271 -0
  132. aiecs/domain/knowledge_graph/schema/property_schema.py +155 -0
  133. aiecs/domain/knowledge_graph/schema/relation_type.py +171 -0
  134. aiecs/domain/knowledge_graph/schema/schema_manager.py +496 -0
  135. aiecs/domain/knowledge_graph/schema/type_enums.py +205 -0
  136. aiecs/domain/task/__init__.py +13 -0
  137. aiecs/domain/task/dsl_processor.py +613 -0
  138. aiecs/domain/task/model.py +62 -0
  139. aiecs/domain/task/task_context.py +268 -0
  140. aiecs/infrastructure/__init__.py +24 -0
  141. aiecs/infrastructure/graph_storage/__init__.py +11 -0
  142. aiecs/infrastructure/graph_storage/base.py +601 -0
  143. aiecs/infrastructure/graph_storage/batch_operations.py +449 -0
  144. aiecs/infrastructure/graph_storage/cache.py +429 -0
  145. aiecs/infrastructure/graph_storage/distributed.py +226 -0
  146. aiecs/infrastructure/graph_storage/error_handling.py +390 -0
  147. aiecs/infrastructure/graph_storage/graceful_degradation.py +306 -0
  148. aiecs/infrastructure/graph_storage/health_checks.py +378 -0
  149. aiecs/infrastructure/graph_storage/in_memory.py +514 -0
  150. aiecs/infrastructure/graph_storage/index_optimization.py +483 -0
  151. aiecs/infrastructure/graph_storage/lazy_loading.py +410 -0
  152. aiecs/infrastructure/graph_storage/metrics.py +357 -0
  153. aiecs/infrastructure/graph_storage/migration.py +413 -0
  154. aiecs/infrastructure/graph_storage/pagination.py +471 -0
  155. aiecs/infrastructure/graph_storage/performance_monitoring.py +466 -0
  156. aiecs/infrastructure/graph_storage/postgres.py +871 -0
  157. aiecs/infrastructure/graph_storage/query_optimizer.py +635 -0
  158. aiecs/infrastructure/graph_storage/schema_cache.py +290 -0
  159. aiecs/infrastructure/graph_storage/sqlite.py +623 -0
  160. aiecs/infrastructure/graph_storage/streaming.py +495 -0
  161. aiecs/infrastructure/messaging/__init__.py +13 -0
  162. aiecs/infrastructure/messaging/celery_task_manager.py +383 -0
  163. aiecs/infrastructure/messaging/websocket_manager.py +298 -0
  164. aiecs/infrastructure/monitoring/__init__.py +34 -0
  165. aiecs/infrastructure/monitoring/executor_metrics.py +174 -0
  166. aiecs/infrastructure/monitoring/global_metrics_manager.py +213 -0
  167. aiecs/infrastructure/monitoring/structured_logger.py +48 -0
  168. aiecs/infrastructure/monitoring/tracing_manager.py +410 -0
  169. aiecs/infrastructure/persistence/__init__.py +24 -0
  170. aiecs/infrastructure/persistence/context_engine_client.py +187 -0
  171. aiecs/infrastructure/persistence/database_manager.py +333 -0
  172. aiecs/infrastructure/persistence/file_storage.py +754 -0
  173. aiecs/infrastructure/persistence/redis_client.py +220 -0
  174. aiecs/llm/__init__.py +86 -0
  175. aiecs/llm/callbacks/__init__.py +11 -0
  176. aiecs/llm/callbacks/custom_callbacks.py +264 -0
  177. aiecs/llm/client_factory.py +420 -0
  178. aiecs/llm/clients/__init__.py +33 -0
  179. aiecs/llm/clients/base_client.py +193 -0
  180. aiecs/llm/clients/googleai_client.py +181 -0
  181. aiecs/llm/clients/openai_client.py +131 -0
  182. aiecs/llm/clients/vertex_client.py +437 -0
  183. aiecs/llm/clients/xai_client.py +184 -0
  184. aiecs/llm/config/__init__.py +51 -0
  185. aiecs/llm/config/config_loader.py +275 -0
  186. aiecs/llm/config/config_validator.py +236 -0
  187. aiecs/llm/config/model_config.py +151 -0
  188. aiecs/llm/utils/__init__.py +10 -0
  189. aiecs/llm/utils/validate_config.py +91 -0
  190. aiecs/main.py +363 -0
  191. aiecs/scripts/__init__.py +3 -0
  192. aiecs/scripts/aid/VERSION_MANAGEMENT.md +97 -0
  193. aiecs/scripts/aid/__init__.py +19 -0
  194. aiecs/scripts/aid/version_manager.py +215 -0
  195. aiecs/scripts/dependance_check/DEPENDENCY_SYSTEM_SUMMARY.md +242 -0
  196. aiecs/scripts/dependance_check/README_DEPENDENCY_CHECKER.md +310 -0
  197. aiecs/scripts/dependance_check/__init__.py +17 -0
  198. aiecs/scripts/dependance_check/dependency_checker.py +938 -0
  199. aiecs/scripts/dependance_check/dependency_fixer.py +391 -0
  200. aiecs/scripts/dependance_check/download_nlp_data.py +396 -0
  201. aiecs/scripts/dependance_check/quick_dependency_check.py +270 -0
  202. aiecs/scripts/dependance_check/setup_nlp_data.sh +217 -0
  203. aiecs/scripts/dependance_patch/__init__.py +7 -0
  204. aiecs/scripts/dependance_patch/fix_weasel/README_WEASEL_PATCH.md +126 -0
  205. aiecs/scripts/dependance_patch/fix_weasel/__init__.py +11 -0
  206. aiecs/scripts/dependance_patch/fix_weasel/fix_weasel_validator.py +128 -0
  207. aiecs/scripts/dependance_patch/fix_weasel/fix_weasel_validator.sh +82 -0
  208. aiecs/scripts/dependance_patch/fix_weasel/patch_weasel_library.sh +188 -0
  209. aiecs/scripts/dependance_patch/fix_weasel/run_weasel_patch.sh +41 -0
  210. aiecs/scripts/tools_develop/README.md +449 -0
  211. aiecs/scripts/tools_develop/TOOL_AUTO_DISCOVERY.md +234 -0
  212. aiecs/scripts/tools_develop/__init__.py +21 -0
  213. aiecs/scripts/tools_develop/check_type_annotations.py +259 -0
  214. aiecs/scripts/tools_develop/validate_tool_schemas.py +422 -0
  215. aiecs/scripts/tools_develop/verify_tools.py +356 -0
  216. aiecs/tasks/__init__.py +1 -0
  217. aiecs/tasks/worker.py +172 -0
  218. aiecs/tools/__init__.py +299 -0
  219. aiecs/tools/apisource/__init__.py +99 -0
  220. aiecs/tools/apisource/intelligence/__init__.py +19 -0
  221. aiecs/tools/apisource/intelligence/data_fusion.py +381 -0
  222. aiecs/tools/apisource/intelligence/query_analyzer.py +413 -0
  223. aiecs/tools/apisource/intelligence/search_enhancer.py +388 -0
  224. aiecs/tools/apisource/monitoring/__init__.py +9 -0
  225. aiecs/tools/apisource/monitoring/metrics.py +303 -0
  226. aiecs/tools/apisource/providers/__init__.py +115 -0
  227. aiecs/tools/apisource/providers/base.py +664 -0
  228. aiecs/tools/apisource/providers/census.py +401 -0
  229. aiecs/tools/apisource/providers/fred.py +564 -0
  230. aiecs/tools/apisource/providers/newsapi.py +412 -0
  231. aiecs/tools/apisource/providers/worldbank.py +357 -0
  232. aiecs/tools/apisource/reliability/__init__.py +12 -0
  233. aiecs/tools/apisource/reliability/error_handler.py +375 -0
  234. aiecs/tools/apisource/reliability/fallback_strategy.py +391 -0
  235. aiecs/tools/apisource/tool.py +850 -0
  236. aiecs/tools/apisource/utils/__init__.py +9 -0
  237. aiecs/tools/apisource/utils/validators.py +338 -0
  238. aiecs/tools/base_tool.py +201 -0
  239. aiecs/tools/docs/__init__.py +121 -0
  240. aiecs/tools/docs/ai_document_orchestrator.py +599 -0
  241. aiecs/tools/docs/ai_document_writer_orchestrator.py +2403 -0
  242. aiecs/tools/docs/content_insertion_tool.py +1333 -0
  243. aiecs/tools/docs/document_creator_tool.py +1317 -0
  244. aiecs/tools/docs/document_layout_tool.py +1166 -0
  245. aiecs/tools/docs/document_parser_tool.py +994 -0
  246. aiecs/tools/docs/document_writer_tool.py +1818 -0
  247. aiecs/tools/knowledge_graph/__init__.py +17 -0
  248. aiecs/tools/knowledge_graph/graph_reasoning_tool.py +734 -0
  249. aiecs/tools/knowledge_graph/graph_search_tool.py +923 -0
  250. aiecs/tools/knowledge_graph/kg_builder_tool.py +476 -0
  251. aiecs/tools/langchain_adapter.py +542 -0
  252. aiecs/tools/schema_generator.py +275 -0
  253. aiecs/tools/search_tool/__init__.py +100 -0
  254. aiecs/tools/search_tool/analyzers.py +589 -0
  255. aiecs/tools/search_tool/cache.py +260 -0
  256. aiecs/tools/search_tool/constants.py +128 -0
  257. aiecs/tools/search_tool/context.py +216 -0
  258. aiecs/tools/search_tool/core.py +749 -0
  259. aiecs/tools/search_tool/deduplicator.py +123 -0
  260. aiecs/tools/search_tool/error_handler.py +271 -0
  261. aiecs/tools/search_tool/metrics.py +371 -0
  262. aiecs/tools/search_tool/rate_limiter.py +178 -0
  263. aiecs/tools/search_tool/schemas.py +277 -0
  264. aiecs/tools/statistics/__init__.py +80 -0
  265. aiecs/tools/statistics/ai_data_analysis_orchestrator.py +643 -0
  266. aiecs/tools/statistics/ai_insight_generator_tool.py +505 -0
  267. aiecs/tools/statistics/ai_report_orchestrator_tool.py +694 -0
  268. aiecs/tools/statistics/data_loader_tool.py +564 -0
  269. aiecs/tools/statistics/data_profiler_tool.py +658 -0
  270. aiecs/tools/statistics/data_transformer_tool.py +573 -0
  271. aiecs/tools/statistics/data_visualizer_tool.py +495 -0
  272. aiecs/tools/statistics/model_trainer_tool.py +487 -0
  273. aiecs/tools/statistics/statistical_analyzer_tool.py +459 -0
  274. aiecs/tools/task_tools/__init__.py +86 -0
  275. aiecs/tools/task_tools/chart_tool.py +732 -0
  276. aiecs/tools/task_tools/classfire_tool.py +922 -0
  277. aiecs/tools/task_tools/image_tool.py +447 -0
  278. aiecs/tools/task_tools/office_tool.py +684 -0
  279. aiecs/tools/task_tools/pandas_tool.py +635 -0
  280. aiecs/tools/task_tools/report_tool.py +635 -0
  281. aiecs/tools/task_tools/research_tool.py +392 -0
  282. aiecs/tools/task_tools/scraper_tool.py +715 -0
  283. aiecs/tools/task_tools/stats_tool.py +688 -0
  284. aiecs/tools/temp_file_manager.py +130 -0
  285. aiecs/tools/tool_executor/__init__.py +37 -0
  286. aiecs/tools/tool_executor/tool_executor.py +881 -0
  287. aiecs/utils/LLM_output_structor.py +445 -0
  288. aiecs/utils/__init__.py +34 -0
  289. aiecs/utils/base_callback.py +47 -0
  290. aiecs/utils/cache_provider.py +695 -0
  291. aiecs/utils/execution_utils.py +184 -0
  292. aiecs/utils/logging.py +1 -0
  293. aiecs/utils/prompt_loader.py +14 -0
  294. aiecs/utils/token_usage_repository.py +323 -0
  295. aiecs/ws/__init__.py +0 -0
  296. aiecs/ws/socket_server.py +52 -0
  297. aiecs-1.5.1.dist-info/METADATA +608 -0
  298. aiecs-1.5.1.dist-info/RECORD +302 -0
  299. aiecs-1.5.1.dist-info/WHEEL +5 -0
  300. aiecs-1.5.1.dist-info/entry_points.txt +10 -0
  301. aiecs-1.5.1.dist-info/licenses/LICENSE +225 -0
  302. aiecs-1.5.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,260 @@
1
+ """
2
+ Intelligent Caching with Redis
3
+
4
+ This module implements intelligent caching with intent-aware TTL strategies
5
+ using Redis as the backend.
6
+ """
7
+
8
+ import hashlib
9
+ import json
10
+ import logging
11
+ from datetime import datetime
12
+ from typing import Any, Dict, List, Optional
13
+
14
+ from .constants import QueryIntentType
15
+
16
+ logger = logging.getLogger(__name__)
17
+
18
+
19
+ class IntelligentCache:
20
+ """Redis-based intelligent cache with intent-aware TTL"""
21
+
22
+ # TTL strategies by intent type (in seconds)
23
+ TTL_STRATEGIES = {
24
+ # 30 days (rarely changes)
25
+ QueryIntentType.DEFINITION.value: 86400 * 30,
26
+ QueryIntentType.HOW_TO.value: 86400 * 7, # 7 days
27
+ QueryIntentType.FACTUAL.value: 86400 * 7, # 7 days
28
+ # 30 days (papers don't change)
29
+ QueryIntentType.ACADEMIC.value: 86400 * 30,
30
+ # 1 hour (fast-changing)
31
+ QueryIntentType.RECENT_NEWS.value: 3600,
32
+ QueryIntentType.PRODUCT.value: 86400, # 1 day
33
+ QueryIntentType.COMPARISON.value: 86400 * 3, # 3 days
34
+ QueryIntentType.GENERAL.value: 3600, # 1 hour default
35
+ }
36
+
37
+ def __init__(self, redis_client: Optional[Any] = None, enabled: bool = True):
38
+ """
39
+ Initialize intelligent cache.
40
+
41
+ Args:
42
+ redis_client: Redis client instance (optional)
43
+ enabled: Whether caching is enabled
44
+ """
45
+ self.redis_client = redis_client
46
+ self.enabled = enabled and redis_client is not None
47
+ self.cache_prefix = "search_tool:"
48
+
49
+ if not self.enabled:
50
+ logger.info("Intelligent cache is disabled (no Redis client)")
51
+
52
+ async def get(self, query: str, params: Dict[str, Any]) -> Optional[Dict[str, Any]]:
53
+ """
54
+ Get cached search results.
55
+
56
+ Args:
57
+ query: Search query
58
+ params: Search parameters
59
+
60
+ Returns:
61
+ Cached results dictionary or None if not found
62
+ """
63
+ if not self.enabled:
64
+ return None
65
+
66
+ try:
67
+ cache_key = self._generate_cache_key(query, params)
68
+ redis = await self.redis_client.get_client()
69
+ cached_data = await redis.get(cache_key)
70
+
71
+ if cached_data:
72
+ logger.debug(f"Cache hit for query: {query}")
73
+ return json.loads(cached_data)
74
+
75
+ logger.debug(f"Cache miss for query: {query}")
76
+ return None
77
+
78
+ except Exception as e:
79
+ logger.warning(f"Cache get error: {e}")
80
+ return None
81
+
82
+ async def set(
83
+ self,
84
+ query: str,
85
+ params: Dict[str, Any],
86
+ results: List[Dict[str, Any]],
87
+ intent_type: str = QueryIntentType.GENERAL.value,
88
+ metadata: Optional[Dict[str, Any]] = None,
89
+ ):
90
+ """
91
+ Cache search results with intelligent TTL.
92
+
93
+ Args:
94
+ query: Search query
95
+ params: Search parameters
96
+ results: Search results to cache
97
+ intent_type: Query intent type for TTL calculation
98
+ metadata: Optional metadata about the search
99
+ """
100
+ if not self.enabled:
101
+ return
102
+
103
+ try:
104
+ cache_key = self._generate_cache_key(query, params)
105
+
106
+ # Calculate intelligent TTL
107
+ ttl = self.calculate_ttl(query, intent_type, results)
108
+
109
+ # Prepare cache data
110
+ cache_data = {
111
+ "query": query,
112
+ "params": params,
113
+ "results": results,
114
+ "intent_type": intent_type,
115
+ "metadata": metadata or {},
116
+ "cached_at": datetime.utcnow().isoformat(),
117
+ "ttl": ttl,
118
+ }
119
+
120
+ # Store in Redis
121
+ redis = await self.redis_client.get_client()
122
+ await redis.set(cache_key, json.dumps(cache_data), ex=ttl)
123
+
124
+ logger.debug(f"Cached results for query: {query} (TTL: {ttl}s)")
125
+
126
+ except Exception as e:
127
+ logger.warning(f"Cache set error: {e}")
128
+
129
+ def calculate_ttl(self, query: str, intent_type: str, results: List[Dict[str, Any]]) -> int:
130
+ """
131
+ Calculate intelligent TTL based on intent and result quality.
132
+
133
+ Args:
134
+ query: Search query
135
+ intent_type: Query intent type
136
+ results: Search results
137
+
138
+ Returns:
139
+ TTL in seconds
140
+ """
141
+ # Base TTL from intent type
142
+ base_ttl = self.TTL_STRATEGIES.get(
143
+ intent_type, self.TTL_STRATEGIES[QueryIntentType.GENERAL.value]
144
+ )
145
+
146
+ if not results:
147
+ # No results: shorter cache time
148
+ return base_ttl // 2
149
+
150
+ # Adjust based on result freshness
151
+ try:
152
+ avg_freshness = sum(
153
+ r.get("_quality", {}).get("freshness_score", 0.5) for r in results
154
+ ) / len(results)
155
+
156
+ # Very fresh results can be cached longer
157
+ if avg_freshness > 0.9:
158
+ base_ttl = int(base_ttl * 2)
159
+ # Old results should have shorter cache
160
+ elif avg_freshness < 0.3:
161
+ base_ttl = base_ttl // 2
162
+ except Exception:
163
+ pass
164
+
165
+ # Adjust based on result quality
166
+ try:
167
+ avg_quality = sum(
168
+ r.get("_quality", {}).get("quality_score", 0.5) for r in results
169
+ ) / len(results)
170
+
171
+ # High quality results can be cached longer
172
+ if avg_quality > 0.8:
173
+ base_ttl = int(base_ttl * 1.5)
174
+ except Exception:
175
+ pass
176
+
177
+ return base_ttl
178
+
179
+ async def invalidate(self, query: str, params: Dict[str, Any]):
180
+ """
181
+ Invalidate cached results.
182
+
183
+ Args:
184
+ query: Search query
185
+ params: Search parameters
186
+ """
187
+ if not self.enabled:
188
+ return
189
+
190
+ try:
191
+ cache_key = self._generate_cache_key(query, params)
192
+ redis = await self.redis_client.get_client()
193
+ await redis.delete(cache_key)
194
+ logger.debug(f"Invalidated cache for query: {query}")
195
+ except Exception as e:
196
+ logger.warning(f"Cache invalidate error: {e}")
197
+
198
+ async def clear_all(self):
199
+ """Clear all cached search results"""
200
+ if not self.enabled:
201
+ return
202
+
203
+ try:
204
+ redis = await self.redis_client.get_client()
205
+ # Find all search_tool cache keys
206
+ pattern = f"{self.cache_prefix}*"
207
+ keys = []
208
+ async for key in redis.scan_iter(match=pattern):
209
+ keys.append(key)
210
+
211
+ if keys:
212
+ await redis.delete(*keys)
213
+ logger.info(f"Cleared {len(keys)} cached entries")
214
+ except Exception as e:
215
+ logger.warning(f"Cache clear error: {e}")
216
+
217
+ def _generate_cache_key(self, query: str, params: Dict[str, Any]) -> str:
218
+ """
219
+ Generate unique cache key from query and parameters.
220
+
221
+ Args:
222
+ query: Search query
223
+ params: Search parameters
224
+
225
+ Returns:
226
+ Cache key string
227
+ """
228
+ # Create deterministic string from query and params
229
+ param_str = json.dumps(params, sort_keys=True)
230
+ key_data = f"{query}:{param_str}"
231
+ key_hash = hashlib.sha256(key_data.encode()).hexdigest()[:16]
232
+
233
+ return f"{self.cache_prefix}{key_hash}"
234
+
235
+ async def get_stats(self) -> Dict[str, Any]:
236
+ """
237
+ Get cache statistics.
238
+
239
+ Returns:
240
+ Cache statistics dictionary
241
+ """
242
+ if not self.enabled:
243
+ return {"enabled": False, "total_keys": 0}
244
+
245
+ try:
246
+ redis = await self.redis_client.get_client()
247
+ # Count cache keys
248
+ pattern = f"{self.cache_prefix}*"
249
+ key_count = 0
250
+ async for _ in redis.scan_iter(match=pattern):
251
+ key_count += 1
252
+
253
+ return {
254
+ "enabled": True,
255
+ "total_keys": key_count,
256
+ "prefix": self.cache_prefix,
257
+ }
258
+ except Exception as e:
259
+ logger.warning(f"Cache stats error: {e}")
260
+ return {"enabled": True, "error": str(e)}
@@ -0,0 +1,128 @@
1
+ """
2
+ Constants, Enums, and Exception Classes for Search Tool
3
+
4
+ This module contains all the shared constants, enumeration types, and
5
+ custom exception classes used across the search tool package.
6
+ """
7
+
8
+ from enum import Enum
9
+
10
+
11
+ # ============================================================================
12
+ # Enums
13
+ # ============================================================================
14
+
15
+
16
+ class SearchType(str, Enum):
17
+ """Supported search types"""
18
+
19
+ WEB = "web"
20
+ IMAGE = "image"
21
+ NEWS = "news"
22
+ VIDEO = "video"
23
+
24
+
25
+ class SafeSearch(str, Enum):
26
+ """Safe search levels"""
27
+
28
+ OFF = "off"
29
+ MEDIUM = "medium"
30
+ HIGH = "high"
31
+
32
+
33
+ class ImageSize(str, Enum):
34
+ """Image size filters"""
35
+
36
+ ICON = "icon"
37
+ SMALL = "small"
38
+ MEDIUM = "medium"
39
+ LARGE = "large"
40
+ XLARGE = "xlarge"
41
+ XXLARGE = "xxlarge"
42
+ HUGE = "huge"
43
+
44
+
45
+ class ImageType(str, Enum):
46
+ """Image type filters"""
47
+
48
+ CLIPART = "clipart"
49
+ FACE = "face"
50
+ LINEART = "lineart"
51
+ STOCK = "stock"
52
+ PHOTO = "photo"
53
+ ANIMATED = "animated"
54
+
55
+
56
+ class ImageColorType(str, Enum):
57
+ """Image color type filters"""
58
+
59
+ COLOR = "color"
60
+ GRAY = "gray"
61
+ MONO = "mono"
62
+ TRANS = "trans"
63
+
64
+
65
+ class CircuitState(str, Enum):
66
+ """Circuit breaker states"""
67
+
68
+ CLOSED = "closed"
69
+ OPEN = "open"
70
+ HALF_OPEN = "half_open"
71
+
72
+
73
+ class QueryIntentType(str, Enum):
74
+ """Query intent types"""
75
+
76
+ DEFINITION = "definition"
77
+ HOW_TO = "how_to"
78
+ COMPARISON = "comparison"
79
+ FACTUAL = "factual"
80
+ RECENT_NEWS = "recent_news"
81
+ ACADEMIC = "academic"
82
+ PRODUCT = "product"
83
+ GENERAL = "general"
84
+
85
+
86
+ class CredibilityLevel(str, Enum):
87
+ """Result credibility levels"""
88
+
89
+ HIGH = "high"
90
+ MEDIUM = "medium"
91
+ LOW = "low"
92
+
93
+
94
+ # ============================================================================
95
+ # Exception Hierarchy
96
+ # ============================================================================
97
+
98
+
99
+ class SearchToolError(Exception):
100
+ """Base exception for SearchTool errors"""
101
+
102
+
103
+ class AuthenticationError(SearchToolError):
104
+ """Authentication-related errors"""
105
+
106
+
107
+ class QuotaExceededError(SearchToolError):
108
+ """API quota exceeded"""
109
+
110
+
111
+ class RateLimitError(SearchToolError):
112
+ """Rate limit exceeded"""
113
+
114
+
115
+ class CircuitBreakerOpenError(SearchToolError):
116
+ """Circuit breaker is open"""
117
+
118
+
119
+ class SearchAPIError(SearchToolError):
120
+ """Search API errors"""
121
+
122
+
123
+ class ValidationError(SearchToolError):
124
+ """Input validation errors"""
125
+
126
+
127
+ class CacheError(SearchToolError):
128
+ """Cache-related errors"""
@@ -0,0 +1,216 @@
1
+ """
2
+ Search Context Management
3
+
4
+ This module tracks search history, learns user preferences, and provides
5
+ contextual suggestions for better search results.
6
+ """
7
+
8
+ from datetime import datetime
9
+ from typing import Any, Dict, List, Optional
10
+
11
+
12
+ class SearchContext:
13
+ """Manages search history and context for improved results"""
14
+
15
+ def __init__(self, max_history: int = 10):
16
+ """
17
+ Initialize search context.
18
+
19
+ Args:
20
+ max_history: Maximum number of searches to keep in history
21
+ """
22
+ self.search_history: List[Dict[str, Any]] = []
23
+ self.max_history = max_history
24
+ self.topic_context: Optional[List[str]] = None
25
+ self.user_preferences = {
26
+ "preferred_domains": set(),
27
+ "avoided_domains": set(),
28
+ "preferred_content_types": [],
29
+ "language": "en",
30
+ }
31
+
32
+ def add_search(
33
+ self,
34
+ query: str,
35
+ results: List[Dict[str, Any]],
36
+ user_feedback: Optional[Dict[str, Any]] = None,
37
+ ):
38
+ """
39
+ Add search to history and update context.
40
+
41
+ Args:
42
+ query: Search query
43
+ results: Search results
44
+ user_feedback: Optional user feedback for learning
45
+ """
46
+ search_record = {
47
+ "timestamp": datetime.utcnow().isoformat(),
48
+ "query": query,
49
+ "result_count": len(results),
50
+ "clicked_results": [],
51
+ "feedback": user_feedback,
52
+ }
53
+
54
+ self.search_history.append(search_record)
55
+
56
+ # Maintain history size limit
57
+ if len(self.search_history) > self.max_history:
58
+ self.search_history.pop(0)
59
+
60
+ # Update topic context
61
+ self._update_topic_context(query, results)
62
+
63
+ # Learn from feedback if provided
64
+ if user_feedback:
65
+ self._learn_preferences(results, user_feedback)
66
+
67
+ def get_contextual_suggestions(self, current_query: str) -> Dict[str, Any]:
68
+ """
69
+ Generate context-aware suggestions for the current query.
70
+
71
+ Args:
72
+ current_query: Current search query
73
+
74
+ Returns:
75
+ Suggestions dictionary with related queries and parameters
76
+ """
77
+ suggestions = {
78
+ "related_queries": [],
79
+ "refinement_suggestions": [],
80
+ "context_aware_params": {},
81
+ }
82
+
83
+ if not self.search_history:
84
+ return suggestions
85
+
86
+ # Find related historical queries
87
+ for record in reversed(self.search_history[-5:]):
88
+ prev_query = record["query"]
89
+ similarity = self._calculate_query_similarity(current_query, prev_query)
90
+
91
+ if similarity > 0.5:
92
+ suggestions["related_queries"].append(
93
+ {
94
+ "query": prev_query,
95
+ "similarity": similarity,
96
+ "timestamp": record["timestamp"],
97
+ }
98
+ )
99
+
100
+ # Suggest preferred sites if available
101
+ if self.user_preferences["preferred_domains"]:
102
+ suggestions["context_aware_params"]["preferred_sites"] = list(
103
+ self.user_preferences["preferred_domains"]
104
+ )
105
+
106
+ return suggestions
107
+
108
+ def get_history(self, limit: Optional[int] = None) -> List[Dict[str, Any]]:
109
+ """
110
+ Get search history.
111
+
112
+ Args:
113
+ limit: Maximum number of records to return
114
+
115
+ Returns:
116
+ List of search history records
117
+ """
118
+ if limit:
119
+ return self.search_history[-limit:]
120
+ return self.search_history.copy()
121
+
122
+ def clear_history(self):
123
+ """Clear search history"""
124
+ self.search_history.clear()
125
+ self.topic_context = None
126
+
127
+ def get_preferences(self) -> Dict[str, Any]:
128
+ """
129
+ Get current user preferences.
130
+
131
+ Returns:
132
+ User preferences dictionary
133
+ """
134
+ return {
135
+ "preferred_domains": list(self.user_preferences["preferred_domains"]),
136
+ "avoided_domains": list(self.user_preferences["avoided_domains"]),
137
+ "preferred_content_types": self.user_preferences["preferred_content_types"].copy(),
138
+ "language": self.user_preferences["language"],
139
+ }
140
+
141
+ def set_preference(self, key: str, value: Any):
142
+ """
143
+ Set a user preference.
144
+
145
+ Args:
146
+ key: Preference key
147
+ value: Preference value
148
+ """
149
+ if key in self.user_preferences:
150
+ if isinstance(self.user_preferences[key], set):
151
+ if isinstance(value, (list, set)):
152
+ self.user_preferences[key] = set(value)
153
+ else:
154
+ self.user_preferences[key].add(value)
155
+ else:
156
+ self.user_preferences[key] = value
157
+
158
+ def _update_topic_context(self, query: str, results: List[Dict[str, Any]]):
159
+ """
160
+ Update topic context from query and results.
161
+
162
+ Args:
163
+ query: Search query
164
+ results: Search results
165
+ """
166
+ # Simple implementation: extract common words
167
+ words = query.lower().split()
168
+ self.topic_context = words
169
+
170
+ def _learn_preferences(self, results: List[Dict[str, Any]], feedback: Dict[str, Any]):
171
+ """
172
+ Learn user preferences from feedback.
173
+
174
+ Args:
175
+ results: Search results
176
+ feedback: User feedback
177
+ """
178
+ # Learn from clicked/used results
179
+ if "clicked_indices" in feedback:
180
+ for idx in feedback["clicked_indices"]:
181
+ if 0 <= idx < len(results):
182
+ result = results[idx]
183
+ domain = result.get("displayLink", "")
184
+ if domain:
185
+ self.user_preferences["preferred_domains"].add(domain)
186
+
187
+ # Learn from disliked results
188
+ if "disliked_indices" in feedback:
189
+ for idx in feedback["disliked_indices"]:
190
+ if 0 <= idx < len(results):
191
+ result = results[idx]
192
+ domain = result.get("displayLink", "")
193
+ if domain:
194
+ self.user_preferences["avoided_domains"].add(domain)
195
+
196
+ def _calculate_query_similarity(self, query1: str, query2: str) -> float:
197
+ """
198
+ Calculate similarity between two queries using Jaccard index.
199
+
200
+ Args:
201
+ query1: First query
202
+ query2: Second query
203
+
204
+ Returns:
205
+ Similarity score (0-1)
206
+ """
207
+ words1 = set(query1.lower().split())
208
+ words2 = set(query2.lower().split())
209
+
210
+ if not words1 or not words2:
211
+ return 0.0
212
+
213
+ intersection = words1 & words2
214
+ union = words1 | words2
215
+
216
+ return len(intersection) / len(union) if union else 0.0