aiecs 1.0.1__py3-none-any.whl → 1.7.6__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.
Potentially problematic release.
This version of aiecs might be problematic. Click here for more details.
- aiecs/__init__.py +13 -16
- aiecs/__main__.py +7 -7
- aiecs/aiecs_client.py +269 -75
- aiecs/application/executors/operation_executor.py +79 -54
- aiecs/application/knowledge_graph/__init__.py +7 -0
- aiecs/application/knowledge_graph/builder/__init__.py +37 -0
- aiecs/application/knowledge_graph/builder/data_quality.py +302 -0
- aiecs/application/knowledge_graph/builder/data_reshaping.py +293 -0
- aiecs/application/knowledge_graph/builder/document_builder.py +369 -0
- aiecs/application/knowledge_graph/builder/graph_builder.py +490 -0
- aiecs/application/knowledge_graph/builder/import_optimizer.py +396 -0
- aiecs/application/knowledge_graph/builder/schema_inference.py +462 -0
- aiecs/application/knowledge_graph/builder/schema_mapping.py +563 -0
- aiecs/application/knowledge_graph/builder/structured_pipeline.py +1384 -0
- aiecs/application/knowledge_graph/builder/text_chunker.py +317 -0
- aiecs/application/knowledge_graph/extractors/__init__.py +27 -0
- aiecs/application/knowledge_graph/extractors/base.py +98 -0
- aiecs/application/knowledge_graph/extractors/llm_entity_extractor.py +422 -0
- aiecs/application/knowledge_graph/extractors/llm_relation_extractor.py +347 -0
- aiecs/application/knowledge_graph/extractors/ner_entity_extractor.py +241 -0
- aiecs/application/knowledge_graph/fusion/__init__.py +78 -0
- aiecs/application/knowledge_graph/fusion/ab_testing.py +395 -0
- aiecs/application/knowledge_graph/fusion/abbreviation_expander.py +327 -0
- aiecs/application/knowledge_graph/fusion/alias_index.py +597 -0
- aiecs/application/knowledge_graph/fusion/alias_matcher.py +384 -0
- aiecs/application/knowledge_graph/fusion/cache_coordinator.py +343 -0
- aiecs/application/knowledge_graph/fusion/entity_deduplicator.py +433 -0
- aiecs/application/knowledge_graph/fusion/entity_linker.py +511 -0
- aiecs/application/knowledge_graph/fusion/evaluation_dataset.py +240 -0
- aiecs/application/knowledge_graph/fusion/knowledge_fusion.py +632 -0
- aiecs/application/knowledge_graph/fusion/matching_config.py +489 -0
- aiecs/application/knowledge_graph/fusion/name_normalizer.py +352 -0
- aiecs/application/knowledge_graph/fusion/relation_deduplicator.py +183 -0
- aiecs/application/knowledge_graph/fusion/semantic_name_matcher.py +464 -0
- aiecs/application/knowledge_graph/fusion/similarity_pipeline.py +534 -0
- aiecs/application/knowledge_graph/pattern_matching/__init__.py +21 -0
- aiecs/application/knowledge_graph/pattern_matching/pattern_matcher.py +342 -0
- aiecs/application/knowledge_graph/pattern_matching/query_executor.py +366 -0
- aiecs/application/knowledge_graph/profiling/__init__.py +12 -0
- aiecs/application/knowledge_graph/profiling/query_plan_visualizer.py +195 -0
- aiecs/application/knowledge_graph/profiling/query_profiler.py +223 -0
- aiecs/application/knowledge_graph/reasoning/__init__.py +27 -0
- aiecs/application/knowledge_graph/reasoning/evidence_synthesis.py +341 -0
- aiecs/application/knowledge_graph/reasoning/inference_engine.py +500 -0
- aiecs/application/knowledge_graph/reasoning/logic_form_parser.py +163 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/__init__.py +79 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/ast_builder.py +513 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/ast_nodes.py +913 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/ast_validator.py +866 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/error_handler.py +475 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/parser.py +396 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/query_context.py +208 -0
- aiecs/application/knowledge_graph/reasoning/logic_query_integration.py +170 -0
- aiecs/application/knowledge_graph/reasoning/query_planner.py +855 -0
- aiecs/application/knowledge_graph/reasoning/reasoning_engine.py +518 -0
- aiecs/application/knowledge_graph/retrieval/__init__.py +27 -0
- aiecs/application/knowledge_graph/retrieval/query_intent_classifier.py +211 -0
- aiecs/application/knowledge_graph/retrieval/retrieval_strategies.py +592 -0
- aiecs/application/knowledge_graph/retrieval/strategy_types.py +23 -0
- aiecs/application/knowledge_graph/search/__init__.py +59 -0
- aiecs/application/knowledge_graph/search/hybrid_search.py +457 -0
- aiecs/application/knowledge_graph/search/reranker.py +293 -0
- aiecs/application/knowledge_graph/search/reranker_strategies.py +535 -0
- aiecs/application/knowledge_graph/search/text_similarity.py +392 -0
- aiecs/application/knowledge_graph/traversal/__init__.py +15 -0
- aiecs/application/knowledge_graph/traversal/enhanced_traversal.py +305 -0
- aiecs/application/knowledge_graph/traversal/path_scorer.py +271 -0
- aiecs/application/knowledge_graph/validators/__init__.py +13 -0
- aiecs/application/knowledge_graph/validators/relation_validator.py +239 -0
- aiecs/application/knowledge_graph/visualization/__init__.py +11 -0
- aiecs/application/knowledge_graph/visualization/graph_visualizer.py +313 -0
- aiecs/common/__init__.py +9 -0
- aiecs/common/knowledge_graph/__init__.py +17 -0
- aiecs/common/knowledge_graph/runnable.py +471 -0
- aiecs/config/__init__.py +20 -5
- aiecs/config/config.py +762 -31
- aiecs/config/graph_config.py +131 -0
- aiecs/config/tool_config.py +399 -0
- aiecs/core/__init__.py +29 -13
- aiecs/core/interface/__init__.py +2 -2
- aiecs/core/interface/execution_interface.py +22 -22
- aiecs/core/interface/storage_interface.py +37 -88
- aiecs/core/registry/__init__.py +31 -0
- aiecs/core/registry/service_registry.py +92 -0
- aiecs/domain/__init__.py +270 -1
- aiecs/domain/agent/__init__.py +191 -0
- aiecs/domain/agent/base_agent.py +3870 -0
- aiecs/domain/agent/exceptions.py +99 -0
- aiecs/domain/agent/graph_aware_mixin.py +569 -0
- aiecs/domain/agent/hybrid_agent.py +1435 -0
- aiecs/domain/agent/integration/__init__.py +29 -0
- aiecs/domain/agent/integration/context_compressor.py +216 -0
- aiecs/domain/agent/integration/context_engine_adapter.py +587 -0
- aiecs/domain/agent/integration/protocols.py +281 -0
- aiecs/domain/agent/integration/retry_policy.py +218 -0
- aiecs/domain/agent/integration/role_config.py +213 -0
- aiecs/domain/agent/knowledge_aware_agent.py +1892 -0
- aiecs/domain/agent/lifecycle.py +291 -0
- aiecs/domain/agent/llm_agent.py +692 -0
- aiecs/domain/agent/memory/__init__.py +12 -0
- aiecs/domain/agent/memory/conversation.py +1124 -0
- aiecs/domain/agent/migration/__init__.py +14 -0
- aiecs/domain/agent/migration/conversion.py +163 -0
- aiecs/domain/agent/migration/legacy_wrapper.py +86 -0
- aiecs/domain/agent/models.py +884 -0
- aiecs/domain/agent/observability.py +479 -0
- aiecs/domain/agent/persistence.py +449 -0
- aiecs/domain/agent/prompts/__init__.py +29 -0
- aiecs/domain/agent/prompts/builder.py +159 -0
- aiecs/domain/agent/prompts/formatters.py +187 -0
- aiecs/domain/agent/prompts/template.py +255 -0
- aiecs/domain/agent/registry.py +253 -0
- aiecs/domain/agent/tool_agent.py +444 -0
- aiecs/domain/agent/tools/__init__.py +15 -0
- aiecs/domain/agent/tools/schema_generator.py +364 -0
- aiecs/domain/community/__init__.py +155 -0
- aiecs/domain/community/agent_adapter.py +469 -0
- aiecs/domain/community/analytics.py +432 -0
- aiecs/domain/community/collaborative_workflow.py +648 -0
- aiecs/domain/community/communication_hub.py +634 -0
- aiecs/domain/community/community_builder.py +320 -0
- aiecs/domain/community/community_integration.py +796 -0
- aiecs/domain/community/community_manager.py +803 -0
- aiecs/domain/community/decision_engine.py +849 -0
- aiecs/domain/community/exceptions.py +231 -0
- aiecs/domain/community/models/__init__.py +33 -0
- aiecs/domain/community/models/community_models.py +234 -0
- aiecs/domain/community/resource_manager.py +461 -0
- aiecs/domain/community/shared_context_manager.py +589 -0
- aiecs/domain/context/__init__.py +40 -10
- aiecs/domain/context/context_engine.py +1910 -0
- aiecs/domain/context/conversation_models.py +87 -53
- aiecs/domain/context/graph_memory.py +582 -0
- aiecs/domain/execution/model.py +12 -4
- aiecs/domain/knowledge_graph/__init__.py +19 -0
- aiecs/domain/knowledge_graph/models/__init__.py +52 -0
- aiecs/domain/knowledge_graph/models/entity.py +148 -0
- aiecs/domain/knowledge_graph/models/evidence.py +178 -0
- aiecs/domain/knowledge_graph/models/inference_rule.py +184 -0
- aiecs/domain/knowledge_graph/models/path.py +171 -0
- aiecs/domain/knowledge_graph/models/path_pattern.py +171 -0
- aiecs/domain/knowledge_graph/models/query.py +261 -0
- aiecs/domain/knowledge_graph/models/query_plan.py +181 -0
- aiecs/domain/knowledge_graph/models/relation.py +202 -0
- aiecs/domain/knowledge_graph/schema/__init__.py +23 -0
- aiecs/domain/knowledge_graph/schema/entity_type.py +131 -0
- aiecs/domain/knowledge_graph/schema/graph_schema.py +253 -0
- aiecs/domain/knowledge_graph/schema/property_schema.py +143 -0
- aiecs/domain/knowledge_graph/schema/relation_type.py +163 -0
- aiecs/domain/knowledge_graph/schema/schema_manager.py +691 -0
- aiecs/domain/knowledge_graph/schema/type_enums.py +209 -0
- aiecs/domain/task/dsl_processor.py +172 -56
- aiecs/domain/task/model.py +20 -8
- aiecs/domain/task/task_context.py +27 -24
- aiecs/infrastructure/__init__.py +0 -2
- aiecs/infrastructure/graph_storage/__init__.py +11 -0
- aiecs/infrastructure/graph_storage/base.py +837 -0
- aiecs/infrastructure/graph_storage/batch_operations.py +458 -0
- aiecs/infrastructure/graph_storage/cache.py +424 -0
- aiecs/infrastructure/graph_storage/distributed.py +223 -0
- aiecs/infrastructure/graph_storage/error_handling.py +380 -0
- aiecs/infrastructure/graph_storage/graceful_degradation.py +294 -0
- aiecs/infrastructure/graph_storage/health_checks.py +378 -0
- aiecs/infrastructure/graph_storage/in_memory.py +1197 -0
- aiecs/infrastructure/graph_storage/index_optimization.py +446 -0
- aiecs/infrastructure/graph_storage/lazy_loading.py +431 -0
- aiecs/infrastructure/graph_storage/metrics.py +344 -0
- aiecs/infrastructure/graph_storage/migration.py +400 -0
- aiecs/infrastructure/graph_storage/pagination.py +483 -0
- aiecs/infrastructure/graph_storage/performance_monitoring.py +456 -0
- aiecs/infrastructure/graph_storage/postgres.py +1563 -0
- aiecs/infrastructure/graph_storage/property_storage.py +353 -0
- aiecs/infrastructure/graph_storage/protocols.py +76 -0
- aiecs/infrastructure/graph_storage/query_optimizer.py +642 -0
- aiecs/infrastructure/graph_storage/schema_cache.py +290 -0
- aiecs/infrastructure/graph_storage/sqlite.py +1373 -0
- aiecs/infrastructure/graph_storage/streaming.py +487 -0
- aiecs/infrastructure/graph_storage/tenant.py +412 -0
- aiecs/infrastructure/messaging/celery_task_manager.py +92 -54
- aiecs/infrastructure/messaging/websocket_manager.py +51 -35
- aiecs/infrastructure/monitoring/__init__.py +22 -0
- aiecs/infrastructure/monitoring/executor_metrics.py +45 -11
- aiecs/infrastructure/monitoring/global_metrics_manager.py +212 -0
- aiecs/infrastructure/monitoring/structured_logger.py +3 -7
- aiecs/infrastructure/monitoring/tracing_manager.py +63 -35
- aiecs/infrastructure/persistence/__init__.py +14 -1
- aiecs/infrastructure/persistence/context_engine_client.py +184 -0
- aiecs/infrastructure/persistence/database_manager.py +67 -43
- aiecs/infrastructure/persistence/file_storage.py +180 -103
- aiecs/infrastructure/persistence/redis_client.py +74 -21
- aiecs/llm/__init__.py +73 -25
- aiecs/llm/callbacks/__init__.py +11 -0
- aiecs/llm/{custom_callbacks.py → callbacks/custom_callbacks.py} +26 -19
- aiecs/llm/client_factory.py +224 -36
- aiecs/llm/client_resolver.py +155 -0
- aiecs/llm/clients/__init__.py +38 -0
- aiecs/llm/clients/base_client.py +324 -0
- aiecs/llm/clients/google_function_calling_mixin.py +457 -0
- aiecs/llm/clients/googleai_client.py +241 -0
- aiecs/llm/clients/openai_client.py +158 -0
- aiecs/llm/clients/openai_compatible_mixin.py +367 -0
- aiecs/llm/clients/vertex_client.py +897 -0
- aiecs/llm/clients/xai_client.py +201 -0
- aiecs/llm/config/__init__.py +51 -0
- aiecs/llm/config/config_loader.py +272 -0
- aiecs/llm/config/config_validator.py +206 -0
- aiecs/llm/config/model_config.py +143 -0
- aiecs/llm/protocols.py +149 -0
- aiecs/llm/utils/__init__.py +10 -0
- aiecs/llm/utils/validate_config.py +89 -0
- aiecs/main.py +140 -121
- aiecs/scripts/aid/VERSION_MANAGEMENT.md +138 -0
- aiecs/scripts/aid/__init__.py +19 -0
- aiecs/scripts/aid/module_checker.py +499 -0
- aiecs/scripts/aid/version_manager.py +235 -0
- aiecs/scripts/{DEPENDENCY_SYSTEM_SUMMARY.md → dependance_check/DEPENDENCY_SYSTEM_SUMMARY.md} +1 -0
- aiecs/scripts/{README_DEPENDENCY_CHECKER.md → dependance_check/README_DEPENDENCY_CHECKER.md} +1 -0
- aiecs/scripts/dependance_check/__init__.py +15 -0
- aiecs/scripts/dependance_check/dependency_checker.py +1835 -0
- aiecs/scripts/{dependency_fixer.py → dependance_check/dependency_fixer.py} +192 -90
- aiecs/scripts/{download_nlp_data.py → dependance_check/download_nlp_data.py} +203 -71
- aiecs/scripts/dependance_patch/__init__.py +7 -0
- aiecs/scripts/dependance_patch/fix_weasel/__init__.py +11 -0
- aiecs/scripts/{fix_weasel_validator.py → dependance_patch/fix_weasel/fix_weasel_validator.py} +21 -14
- aiecs/scripts/{patch_weasel_library.sh → dependance_patch/fix_weasel/patch_weasel_library.sh} +1 -1
- aiecs/scripts/knowledge_graph/__init__.py +3 -0
- aiecs/scripts/knowledge_graph/run_threshold_experiments.py +212 -0
- aiecs/scripts/migrations/multi_tenancy/README.md +142 -0
- aiecs/scripts/tools_develop/README.md +671 -0
- aiecs/scripts/tools_develop/README_CONFIG_CHECKER.md +273 -0
- aiecs/scripts/tools_develop/TOOLS_CONFIG_GUIDE.md +1287 -0
- aiecs/scripts/tools_develop/TOOL_AUTO_DISCOVERY.md +234 -0
- aiecs/scripts/tools_develop/__init__.py +21 -0
- aiecs/scripts/tools_develop/check_all_tools_config.py +548 -0
- aiecs/scripts/tools_develop/check_type_annotations.py +257 -0
- aiecs/scripts/tools_develop/pre-commit-schema-coverage.sh +66 -0
- aiecs/scripts/tools_develop/schema_coverage.py +511 -0
- aiecs/scripts/tools_develop/validate_tool_schemas.py +475 -0
- aiecs/scripts/tools_develop/verify_executor_config_fix.py +98 -0
- aiecs/scripts/tools_develop/verify_tools.py +352 -0
- aiecs/tasks/__init__.py +0 -1
- aiecs/tasks/worker.py +115 -47
- aiecs/tools/__init__.py +194 -72
- aiecs/tools/apisource/__init__.py +99 -0
- aiecs/tools/apisource/intelligence/__init__.py +19 -0
- aiecs/tools/apisource/intelligence/data_fusion.py +632 -0
- aiecs/tools/apisource/intelligence/query_analyzer.py +417 -0
- aiecs/tools/apisource/intelligence/search_enhancer.py +385 -0
- aiecs/tools/apisource/monitoring/__init__.py +9 -0
- aiecs/tools/apisource/monitoring/metrics.py +330 -0
- aiecs/tools/apisource/providers/__init__.py +112 -0
- aiecs/tools/apisource/providers/base.py +671 -0
- aiecs/tools/apisource/providers/census.py +397 -0
- aiecs/tools/apisource/providers/fred.py +535 -0
- aiecs/tools/apisource/providers/newsapi.py +409 -0
- aiecs/tools/apisource/providers/worldbank.py +352 -0
- aiecs/tools/apisource/reliability/__init__.py +12 -0
- aiecs/tools/apisource/reliability/error_handler.py +363 -0
- aiecs/tools/apisource/reliability/fallback_strategy.py +376 -0
- aiecs/tools/apisource/tool.py +832 -0
- aiecs/tools/apisource/utils/__init__.py +9 -0
- aiecs/tools/apisource/utils/validators.py +334 -0
- aiecs/tools/base_tool.py +415 -21
- aiecs/tools/docs/__init__.py +121 -0
- aiecs/tools/docs/ai_document_orchestrator.py +607 -0
- aiecs/tools/docs/ai_document_writer_orchestrator.py +2350 -0
- aiecs/tools/docs/content_insertion_tool.py +1320 -0
- aiecs/tools/docs/document_creator_tool.py +1323 -0
- aiecs/tools/docs/document_layout_tool.py +1160 -0
- aiecs/tools/docs/document_parser_tool.py +1011 -0
- aiecs/tools/docs/document_writer_tool.py +1829 -0
- aiecs/tools/knowledge_graph/__init__.py +17 -0
- aiecs/tools/knowledge_graph/graph_reasoning_tool.py +807 -0
- aiecs/tools/knowledge_graph/graph_search_tool.py +944 -0
- aiecs/tools/knowledge_graph/kg_builder_tool.py +524 -0
- aiecs/tools/langchain_adapter.py +300 -138
- aiecs/tools/schema_generator.py +455 -0
- aiecs/tools/search_tool/__init__.py +100 -0
- aiecs/tools/search_tool/analyzers.py +581 -0
- aiecs/tools/search_tool/cache.py +264 -0
- aiecs/tools/search_tool/constants.py +128 -0
- aiecs/tools/search_tool/context.py +224 -0
- aiecs/tools/search_tool/core.py +778 -0
- aiecs/tools/search_tool/deduplicator.py +119 -0
- aiecs/tools/search_tool/error_handler.py +242 -0
- aiecs/tools/search_tool/metrics.py +343 -0
- aiecs/tools/search_tool/rate_limiter.py +172 -0
- aiecs/tools/search_tool/schemas.py +275 -0
- aiecs/tools/statistics/__init__.py +80 -0
- aiecs/tools/statistics/ai_data_analysis_orchestrator.py +646 -0
- aiecs/tools/statistics/ai_insight_generator_tool.py +508 -0
- aiecs/tools/statistics/ai_report_orchestrator_tool.py +684 -0
- aiecs/tools/statistics/data_loader_tool.py +555 -0
- aiecs/tools/statistics/data_profiler_tool.py +638 -0
- aiecs/tools/statistics/data_transformer_tool.py +580 -0
- aiecs/tools/statistics/data_visualizer_tool.py +498 -0
- aiecs/tools/statistics/model_trainer_tool.py +507 -0
- aiecs/tools/statistics/statistical_analyzer_tool.py +472 -0
- aiecs/tools/task_tools/__init__.py +49 -36
- aiecs/tools/task_tools/chart_tool.py +200 -184
- aiecs/tools/task_tools/classfire_tool.py +268 -267
- aiecs/tools/task_tools/image_tool.py +175 -131
- aiecs/tools/task_tools/office_tool.py +226 -146
- aiecs/tools/task_tools/pandas_tool.py +477 -121
- aiecs/tools/task_tools/report_tool.py +390 -142
- aiecs/tools/task_tools/research_tool.py +149 -79
- aiecs/tools/task_tools/scraper_tool.py +339 -145
- aiecs/tools/task_tools/stats_tool.py +448 -209
- aiecs/tools/temp_file_manager.py +26 -24
- aiecs/tools/tool_executor/__init__.py +18 -16
- aiecs/tools/tool_executor/tool_executor.py +364 -52
- aiecs/utils/LLM_output_structor.py +74 -48
- aiecs/utils/__init__.py +14 -3
- aiecs/utils/base_callback.py +0 -3
- aiecs/utils/cache_provider.py +696 -0
- aiecs/utils/execution_utils.py +50 -31
- aiecs/utils/prompt_loader.py +1 -0
- aiecs/utils/token_usage_repository.py +37 -11
- aiecs/ws/socket_server.py +14 -4
- {aiecs-1.0.1.dist-info → aiecs-1.7.6.dist-info}/METADATA +52 -15
- aiecs-1.7.6.dist-info/RECORD +337 -0
- aiecs-1.7.6.dist-info/entry_points.txt +13 -0
- aiecs/config/registry.py +0 -19
- aiecs/domain/context/content_engine.py +0 -982
- aiecs/llm/base_client.py +0 -99
- aiecs/llm/openai_client.py +0 -125
- aiecs/llm/vertex_client.py +0 -186
- aiecs/llm/xai_client.py +0 -184
- aiecs/scripts/dependency_checker.py +0 -857
- aiecs/scripts/quick_dependency_check.py +0 -269
- aiecs/tools/task_tools/search_api.py +0 -7
- aiecs-1.0.1.dist-info/RECORD +0 -90
- aiecs-1.0.1.dist-info/entry_points.txt +0 -7
- /aiecs/scripts/{setup_nlp_data.sh → dependance_check/setup_nlp_data.sh} +0 -0
- /aiecs/scripts/{README_WEASEL_PATCH.md → dependance_patch/fix_weasel/README_WEASEL_PATCH.md} +0 -0
- /aiecs/scripts/{fix_weasel_validator.sh → dependance_patch/fix_weasel/fix_weasel_validator.sh} +0 -0
- /aiecs/scripts/{run_weasel_patch.sh → dependance_patch/fix_weasel/run_weasel_patch.sh} +0 -0
- {aiecs-1.0.1.dist-info → aiecs-1.7.6.dist-info}/WHEEL +0 -0
- {aiecs-1.0.1.dist-info → aiecs-1.7.6.dist-info}/licenses/LICENSE +0 -0
- {aiecs-1.0.1.dist-info → aiecs-1.7.6.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Path Scoring and Ranking
|
|
3
|
+
|
|
4
|
+
Provides utilities for scoring and ranking graph paths based on various criteria.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import List, Callable, Optional, Dict, Any, Tuple
|
|
8
|
+
from aiecs.domain.knowledge_graph.models.path import Path
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class PathScorer:
|
|
12
|
+
"""
|
|
13
|
+
Path Scoring Utility
|
|
14
|
+
|
|
15
|
+
Scores and ranks paths based on configurable criteria:
|
|
16
|
+
- Path length (shorter/longer)
|
|
17
|
+
- Relation types (preferred types)
|
|
18
|
+
- Entity types (preferred types)
|
|
19
|
+
- Relation weights (accumulated)
|
|
20
|
+
- Custom scoring functions
|
|
21
|
+
|
|
22
|
+
Example:
|
|
23
|
+
```python
|
|
24
|
+
scorer = PathScorer()
|
|
25
|
+
|
|
26
|
+
# Score by path length (shorter is better)
|
|
27
|
+
scored_paths = scorer.score_by_length(paths, prefer_shorter=True)
|
|
28
|
+
|
|
29
|
+
# Score by relation weights
|
|
30
|
+
scored_paths = scorer.score_by_weights(paths)
|
|
31
|
+
|
|
32
|
+
# Custom scoring
|
|
33
|
+
scored_paths = scorer.score_custom(paths, lambda p: compute_score(p))
|
|
34
|
+
|
|
35
|
+
# Rank and return top paths
|
|
36
|
+
top_paths = scorer.rank_paths(scored_paths, top_k=10)
|
|
37
|
+
```
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
def score_by_length(
|
|
41
|
+
self,
|
|
42
|
+
paths: List[Path],
|
|
43
|
+
prefer_shorter: bool = True,
|
|
44
|
+
normalize: bool = True,
|
|
45
|
+
) -> List[Path]:
|
|
46
|
+
"""
|
|
47
|
+
Score paths by their length
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
paths: List of paths to score
|
|
51
|
+
prefer_shorter: If True, shorter paths get higher scores
|
|
52
|
+
normalize: If True, normalize scores to 0-1 range
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
List of paths with scores assigned
|
|
56
|
+
"""
|
|
57
|
+
if not paths:
|
|
58
|
+
return []
|
|
59
|
+
|
|
60
|
+
# Get length range
|
|
61
|
+
lengths = [p.length for p in paths]
|
|
62
|
+
min_len = min(lengths)
|
|
63
|
+
max_len = max(lengths)
|
|
64
|
+
|
|
65
|
+
scored_paths = []
|
|
66
|
+
for path in paths:
|
|
67
|
+
if max_len == min_len:
|
|
68
|
+
# All paths same length
|
|
69
|
+
score = 1.0
|
|
70
|
+
elif prefer_shorter:
|
|
71
|
+
# Shorter paths get higher scores
|
|
72
|
+
if normalize:
|
|
73
|
+
score = 1.0 - ((path.length - min_len) / (max_len - min_len))
|
|
74
|
+
else:
|
|
75
|
+
score = 1.0 / (path.length + 1)
|
|
76
|
+
else:
|
|
77
|
+
# Longer paths get higher scores
|
|
78
|
+
if normalize:
|
|
79
|
+
score = (path.length - min_len) / (max_len - min_len)
|
|
80
|
+
else:
|
|
81
|
+
score = path.length / (max_len + 1)
|
|
82
|
+
|
|
83
|
+
# Create new path with score
|
|
84
|
+
scored_path = Path(nodes=path.nodes, edges=path.edges, score=score)
|
|
85
|
+
scored_paths.append(scored_path)
|
|
86
|
+
|
|
87
|
+
return scored_paths
|
|
88
|
+
|
|
89
|
+
def score_by_weights(self, paths: List[Path], aggregation: str = "mean") -> List[Path]:
|
|
90
|
+
"""
|
|
91
|
+
Score paths by relation weights
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
paths: List of paths to score
|
|
95
|
+
aggregation: How to aggregate weights ("mean", "sum", "min", "max")
|
|
96
|
+
|
|
97
|
+
Returns:
|
|
98
|
+
List of paths with scores based on relation weights
|
|
99
|
+
"""
|
|
100
|
+
scored_paths = []
|
|
101
|
+
|
|
102
|
+
for path in paths:
|
|
103
|
+
if not path.edges:
|
|
104
|
+
score = 1.0
|
|
105
|
+
else:
|
|
106
|
+
weights = [edge.weight for edge in path.edges]
|
|
107
|
+
|
|
108
|
+
if aggregation == "mean":
|
|
109
|
+
score = sum(weights) / len(weights)
|
|
110
|
+
elif aggregation == "sum":
|
|
111
|
+
score = sum(weights) / len(weights) # Normalized by length
|
|
112
|
+
elif aggregation == "min":
|
|
113
|
+
score = min(weights)
|
|
114
|
+
elif aggregation == "max":
|
|
115
|
+
score = max(weights)
|
|
116
|
+
else:
|
|
117
|
+
score = sum(weights) / len(weights) # Default to mean
|
|
118
|
+
|
|
119
|
+
scored_path = Path(nodes=path.nodes, edges=path.edges, score=score)
|
|
120
|
+
scored_paths.append(scored_path)
|
|
121
|
+
|
|
122
|
+
return scored_paths
|
|
123
|
+
|
|
124
|
+
def score_by_relation_types(
|
|
125
|
+
self,
|
|
126
|
+
paths: List[Path],
|
|
127
|
+
preferred_types: List[str],
|
|
128
|
+
penalty: float = 0.5,
|
|
129
|
+
) -> List[Path]:
|
|
130
|
+
"""
|
|
131
|
+
Score paths by preferred relation types
|
|
132
|
+
|
|
133
|
+
Args:
|
|
134
|
+
paths: List of paths to score
|
|
135
|
+
preferred_types: List of preferred relation types
|
|
136
|
+
penalty: Score multiplier for non-preferred relations
|
|
137
|
+
|
|
138
|
+
Returns:
|
|
139
|
+
List of paths scored by relation type preferences
|
|
140
|
+
"""
|
|
141
|
+
scored_paths = []
|
|
142
|
+
|
|
143
|
+
for path in paths:
|
|
144
|
+
if not path.edges:
|
|
145
|
+
score = 1.0
|
|
146
|
+
else:
|
|
147
|
+
# Calculate score based on preferred types
|
|
148
|
+
type_scores = []
|
|
149
|
+
for edge in path.edges:
|
|
150
|
+
if edge.relation_type in preferred_types:
|
|
151
|
+
type_scores.append(1.0)
|
|
152
|
+
else:
|
|
153
|
+
type_scores.append(penalty)
|
|
154
|
+
|
|
155
|
+
score = sum(type_scores) / len(type_scores)
|
|
156
|
+
|
|
157
|
+
scored_path = Path(nodes=path.nodes, edges=path.edges, score=score)
|
|
158
|
+
scored_paths.append(scored_path)
|
|
159
|
+
|
|
160
|
+
return scored_paths
|
|
161
|
+
|
|
162
|
+
def score_custom(self, paths: List[Path], scoring_fn: Callable[[Path], float]) -> List[Path]:
|
|
163
|
+
"""
|
|
164
|
+
Score paths using a custom scoring function
|
|
165
|
+
|
|
166
|
+
Args:
|
|
167
|
+
paths: List of paths to score
|
|
168
|
+
scoring_fn: Function that takes a Path and returns a score (0.0-1.0)
|
|
169
|
+
|
|
170
|
+
Returns:
|
|
171
|
+
List of paths with custom scores
|
|
172
|
+
"""
|
|
173
|
+
scored_paths = []
|
|
174
|
+
|
|
175
|
+
for path in paths:
|
|
176
|
+
score = scoring_fn(path)
|
|
177
|
+
# Clamp score to valid range
|
|
178
|
+
score = max(0.0, min(1.0, score))
|
|
179
|
+
|
|
180
|
+
scored_path = Path(nodes=path.nodes, edges=path.edges, score=score)
|
|
181
|
+
scored_paths.append(scored_path)
|
|
182
|
+
|
|
183
|
+
return scored_paths
|
|
184
|
+
|
|
185
|
+
def combine_scores(
|
|
186
|
+
self,
|
|
187
|
+
paths_lists: List[List[Path]],
|
|
188
|
+
weights: Optional[List[float]] = None,
|
|
189
|
+
) -> List[Path]:
|
|
190
|
+
"""
|
|
191
|
+
Combine scores from multiple scoring methods
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
paths_lists: List of path lists (each with different scores)
|
|
195
|
+
weights: Optional weights for each scoring method
|
|
196
|
+
|
|
197
|
+
Returns:
|
|
198
|
+
List of paths with combined scores
|
|
199
|
+
"""
|
|
200
|
+
if not paths_lists:
|
|
201
|
+
return []
|
|
202
|
+
|
|
203
|
+
if weights is None:
|
|
204
|
+
weights = [1.0] * len(paths_lists)
|
|
205
|
+
|
|
206
|
+
# Normalize weights
|
|
207
|
+
total_weight = sum(weights)
|
|
208
|
+
weights = [w / total_weight for w in weights]
|
|
209
|
+
|
|
210
|
+
# Build path ID to combined score mapping
|
|
211
|
+
path_scores: Dict[Tuple[str, ...], Dict[str, Any]] = {}
|
|
212
|
+
|
|
213
|
+
for paths, weight in zip(paths_lists, weights):
|
|
214
|
+
for path in paths:
|
|
215
|
+
# Use path node IDs as key
|
|
216
|
+
path_key = tuple(p.id for p in path.nodes)
|
|
217
|
+
|
|
218
|
+
if path_key not in path_scores:
|
|
219
|
+
path_scores[path_key] = {"path": path, "score": 0.0}
|
|
220
|
+
|
|
221
|
+
# Add weighted score
|
|
222
|
+
if path.score is not None:
|
|
223
|
+
score = path_scores[path_key]["score"]
|
|
224
|
+
if isinstance(score, (int, float)):
|
|
225
|
+
path_scores[path_key]["score"] = score + path.score * weight
|
|
226
|
+
|
|
227
|
+
# Create scored paths
|
|
228
|
+
combined_paths = []
|
|
229
|
+
for data in path_scores.values():
|
|
230
|
+
scored_path = Path(
|
|
231
|
+
nodes=data["path"].nodes,
|
|
232
|
+
edges=data["path"].edges,
|
|
233
|
+
score=data["score"],
|
|
234
|
+
)
|
|
235
|
+
combined_paths.append(scored_path)
|
|
236
|
+
|
|
237
|
+
return combined_paths
|
|
238
|
+
|
|
239
|
+
def rank_paths(
|
|
240
|
+
self,
|
|
241
|
+
paths: List[Path],
|
|
242
|
+
top_k: Optional[int] = None,
|
|
243
|
+
min_score: Optional[float] = None,
|
|
244
|
+
) -> List[Path]:
|
|
245
|
+
"""
|
|
246
|
+
Rank paths by score and return top results
|
|
247
|
+
|
|
248
|
+
Args:
|
|
249
|
+
paths: List of paths to rank
|
|
250
|
+
top_k: Number of top paths to return (None = all)
|
|
251
|
+
min_score: Minimum score threshold (None = no threshold)
|
|
252
|
+
|
|
253
|
+
Returns:
|
|
254
|
+
Sorted list of paths (highest score first)
|
|
255
|
+
"""
|
|
256
|
+
# Filter by minimum score if specified
|
|
257
|
+
if min_score is not None:
|
|
258
|
+
paths = [p for p in paths if p.score is not None and p.score >= min_score]
|
|
259
|
+
|
|
260
|
+
# Sort by score (descending)
|
|
261
|
+
sorted_paths = sorted(
|
|
262
|
+
paths,
|
|
263
|
+
key=lambda p: p.score if p.score is not None else 0.0,
|
|
264
|
+
reverse=True,
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
# Return top k if specified
|
|
268
|
+
if top_k is not None:
|
|
269
|
+
return sorted_paths[:top_k]
|
|
270
|
+
|
|
271
|
+
return sorted_paths
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Relation Validator
|
|
3
|
+
|
|
4
|
+
Validates relations against knowledge graph schema.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import List, Optional, Tuple
|
|
8
|
+
from aiecs.domain.knowledge_graph.models.entity import Entity
|
|
9
|
+
from aiecs.domain.knowledge_graph.models.relation import Relation
|
|
10
|
+
from aiecs.domain.knowledge_graph.schema.graph_schema import GraphSchema
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class RelationValidator:
|
|
14
|
+
"""
|
|
15
|
+
Validate relations against schema rules
|
|
16
|
+
|
|
17
|
+
Ensures that:
|
|
18
|
+
- Relation type exists in schema
|
|
19
|
+
- Source and target entity types are compatible
|
|
20
|
+
- Relation properties match schema
|
|
21
|
+
- Required properties are present
|
|
22
|
+
|
|
23
|
+
Example:
|
|
24
|
+
```python
|
|
25
|
+
validator = RelationValidator(schema)
|
|
26
|
+
|
|
27
|
+
is_valid, errors = validator.validate_relation(
|
|
28
|
+
relation,
|
|
29
|
+
source_entity,
|
|
30
|
+
target_entity
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
if not is_valid:
|
|
34
|
+
print(f"Invalid relation: {errors}")
|
|
35
|
+
```
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
def __init__(self, schema: Optional[GraphSchema] = None, strict: bool = False):
|
|
39
|
+
"""
|
|
40
|
+
Initialize relation validator
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
schema: GraphSchema to validate against (optional)
|
|
44
|
+
strict: If True, reject relations not in schema; if False, allow unknown types
|
|
45
|
+
"""
|
|
46
|
+
self.schema = schema
|
|
47
|
+
self.strict = strict
|
|
48
|
+
|
|
49
|
+
def validate_relation(self, relation: Relation, source_entity: Entity, target_entity: Entity) -> Tuple[bool, List[str]]:
|
|
50
|
+
"""
|
|
51
|
+
Validate a relation against schema
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
relation: Relation to validate
|
|
55
|
+
source_entity: Source entity
|
|
56
|
+
target_entity: Target entity
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
Tuple of (is_valid, error_messages)
|
|
60
|
+
"""
|
|
61
|
+
errors = []
|
|
62
|
+
|
|
63
|
+
# Basic validation (always performed)
|
|
64
|
+
if not relation.source_id:
|
|
65
|
+
errors.append("Relation missing source_id")
|
|
66
|
+
if not relation.target_id:
|
|
67
|
+
errors.append("Relation missing target_id")
|
|
68
|
+
if not relation.relation_type:
|
|
69
|
+
errors.append("Relation missing relation_type")
|
|
70
|
+
|
|
71
|
+
# Check entity IDs match
|
|
72
|
+
if relation.source_id != source_entity.id:
|
|
73
|
+
errors.append(f"Relation source_id '{relation.source_id}' does not match " f"source_entity id '{source_entity.id}'")
|
|
74
|
+
if relation.target_id != target_entity.id:
|
|
75
|
+
errors.append(f"Relation target_id '{relation.target_id}' does not match " f"target_entity id '{target_entity.id}'")
|
|
76
|
+
|
|
77
|
+
# Schema-based validation (if schema provided)
|
|
78
|
+
if self.schema:
|
|
79
|
+
schema_errors = self._validate_against_schema(relation, source_entity, target_entity)
|
|
80
|
+
errors.extend(schema_errors)
|
|
81
|
+
|
|
82
|
+
return (len(errors) == 0, errors)
|
|
83
|
+
|
|
84
|
+
def validate_relations(self, relations: List[Relation], entities: List[Entity]) -> List[Tuple[Relation, bool, List[str]]]:
|
|
85
|
+
"""
|
|
86
|
+
Validate multiple relations
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
relations: List of relations to validate
|
|
90
|
+
entities: List of entities (source and targets)
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
List of (relation, is_valid, errors) tuples
|
|
94
|
+
"""
|
|
95
|
+
# Build entity lookup
|
|
96
|
+
entity_lookup = {e.id: e for e in entities}
|
|
97
|
+
|
|
98
|
+
results = []
|
|
99
|
+
for relation in relations:
|
|
100
|
+
source = entity_lookup.get(relation.source_id)
|
|
101
|
+
target = entity_lookup.get(relation.target_id)
|
|
102
|
+
|
|
103
|
+
if not source or not target:
|
|
104
|
+
is_valid = False
|
|
105
|
+
errors = [f"Source or target entity not found for relation {relation.id}"]
|
|
106
|
+
else:
|
|
107
|
+
is_valid, errors = self.validate_relation(relation, source, target)
|
|
108
|
+
|
|
109
|
+
results.append((relation, is_valid, errors))
|
|
110
|
+
|
|
111
|
+
return results
|
|
112
|
+
|
|
113
|
+
def filter_valid_relations(self, relations: List[Relation], entities: List[Entity]) -> List[Relation]:
|
|
114
|
+
"""
|
|
115
|
+
Filter relations to only valid ones
|
|
116
|
+
|
|
117
|
+
Args:
|
|
118
|
+
relations: List of relations
|
|
119
|
+
entities: List of entities
|
|
120
|
+
|
|
121
|
+
Returns:
|
|
122
|
+
List of valid relations
|
|
123
|
+
"""
|
|
124
|
+
validation_results = self.validate_relations(relations, entities)
|
|
125
|
+
return [relation for relation, is_valid, errors in validation_results if is_valid]
|
|
126
|
+
|
|
127
|
+
def _validate_against_schema(self, relation: Relation, source_entity: Entity, target_entity: Entity) -> List[str]:
|
|
128
|
+
"""
|
|
129
|
+
Validate relation against schema rules
|
|
130
|
+
|
|
131
|
+
Args:
|
|
132
|
+
relation: Relation to validate
|
|
133
|
+
source_entity: Source entity
|
|
134
|
+
target_entity: Target entity
|
|
135
|
+
|
|
136
|
+
Returns:
|
|
137
|
+
List of error messages (empty if valid)
|
|
138
|
+
"""
|
|
139
|
+
errors = []
|
|
140
|
+
|
|
141
|
+
# Check if schema is available
|
|
142
|
+
if self.schema is None:
|
|
143
|
+
if self.strict:
|
|
144
|
+
errors.append("Schema is required for strict validation")
|
|
145
|
+
return errors
|
|
146
|
+
|
|
147
|
+
# Check if relation type exists in schema
|
|
148
|
+
if not self.schema.has_relation_type(relation.relation_type):
|
|
149
|
+
if self.strict:
|
|
150
|
+
errors.append(f"Relation type '{relation.relation_type}' not found in schema")
|
|
151
|
+
# In non-strict mode, allow unknown relation types
|
|
152
|
+
return errors
|
|
153
|
+
|
|
154
|
+
# Get relation type schema
|
|
155
|
+
rel_type_schema = self.schema.get_relation_type(relation.relation_type)
|
|
156
|
+
|
|
157
|
+
# Skip validation if relation type schema not found
|
|
158
|
+
if rel_type_schema is None:
|
|
159
|
+
return errors
|
|
160
|
+
|
|
161
|
+
# Validate source entity type
|
|
162
|
+
if rel_type_schema.source_entity_types:
|
|
163
|
+
if source_entity.entity_type not in rel_type_schema.source_entity_types:
|
|
164
|
+
errors.append(f"Source entity type '{source_entity.entity_type}' not allowed for " f"relation '{relation.relation_type}'. " f"Allowed types: {rel_type_schema.source_entity_types}")
|
|
165
|
+
|
|
166
|
+
# Validate target entity type
|
|
167
|
+
if rel_type_schema.target_entity_types:
|
|
168
|
+
if target_entity.entity_type not in rel_type_schema.target_entity_types:
|
|
169
|
+
errors.append(f"Target entity type '{target_entity.entity_type}' not allowed for " f"relation '{relation.relation_type}'. " f"Allowed types: {rel_type_schema.target_entity_types}")
|
|
170
|
+
|
|
171
|
+
# Validate relation properties against schema
|
|
172
|
+
property_errors = self._validate_relation_properties(relation, rel_type_schema)
|
|
173
|
+
errors.extend(property_errors)
|
|
174
|
+
|
|
175
|
+
return errors
|
|
176
|
+
|
|
177
|
+
def _validate_relation_properties(self, relation: Relation, rel_type_schema) -> List[str]:
|
|
178
|
+
"""
|
|
179
|
+
Validate relation properties against schema
|
|
180
|
+
|
|
181
|
+
Checks:
|
|
182
|
+
- Required properties are present
|
|
183
|
+
- Property types match schema definitions
|
|
184
|
+
- Property values are within allowed ranges/values
|
|
185
|
+
- Unknown properties are not present (in strict mode)
|
|
186
|
+
|
|
187
|
+
Args:
|
|
188
|
+
relation: Relation to validate
|
|
189
|
+
rel_type_schema: RelationType schema to validate against
|
|
190
|
+
|
|
191
|
+
Returns:
|
|
192
|
+
List of error messages (empty if valid)
|
|
193
|
+
"""
|
|
194
|
+
errors = []
|
|
195
|
+
relation_properties = relation.properties or {}
|
|
196
|
+
|
|
197
|
+
# Check required properties are present
|
|
198
|
+
for prop_name, prop_schema in rel_type_schema.properties.items():
|
|
199
|
+
if prop_schema.required and prop_name not in relation_properties:
|
|
200
|
+
available_props = list(rel_type_schema.properties.keys())
|
|
201
|
+
errors.append(
|
|
202
|
+
f"Required property '{prop_name}' missing for relation type '{relation.relation_type}'. "
|
|
203
|
+
f"Available properties: {', '.join(available_props)}"
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
# Validate each provided property
|
|
207
|
+
for prop_name, prop_value in relation_properties.items():
|
|
208
|
+
# Check if property exists in schema
|
|
209
|
+
if prop_name not in rel_type_schema.properties:
|
|
210
|
+
if self.strict:
|
|
211
|
+
available_props = list(rel_type_schema.properties.keys())
|
|
212
|
+
errors.append(
|
|
213
|
+
f"Unknown property '{prop_name}' for relation type '{relation.relation_type}'. "
|
|
214
|
+
f"Available properties: {', '.join(available_props) if available_props else 'none'}"
|
|
215
|
+
)
|
|
216
|
+
# In non-strict mode, allow unknown properties
|
|
217
|
+
continue
|
|
218
|
+
|
|
219
|
+
# Get property schema
|
|
220
|
+
prop_schema = rel_type_schema.properties[prop_name]
|
|
221
|
+
|
|
222
|
+
# Validate property value against schema
|
|
223
|
+
try:
|
|
224
|
+
prop_schema.validate_value(prop_value)
|
|
225
|
+
except ValueError as e:
|
|
226
|
+
# Convert ValueError to helpful error message
|
|
227
|
+
error_msg = str(e)
|
|
228
|
+
# Enhance error message with relation context
|
|
229
|
+
if "Property" in error_msg and "'" in error_msg:
|
|
230
|
+
# Error already includes property name, just add relation context
|
|
231
|
+
errors.append(
|
|
232
|
+
f"Property validation failed for relation '{relation.relation_type}': {error_msg}"
|
|
233
|
+
)
|
|
234
|
+
else:
|
|
235
|
+
errors.append(
|
|
236
|
+
f"Property '{prop_name}' validation failed for relation '{relation.relation_type}': {error_msg}"
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
return errors
|