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,400 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Graph Storage Migration Utilities
|
|
3
|
+
|
|
4
|
+
Provides tools to migrate graph data between different storage backends,
|
|
5
|
+
particularly from SQLite to PostgreSQL.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import logging
|
|
9
|
+
import asyncio
|
|
10
|
+
from typing import Optional, Dict, Any
|
|
11
|
+
from tqdm import tqdm
|
|
12
|
+
|
|
13
|
+
from aiecs.infrastructure.graph_storage.base import GraphStore
|
|
14
|
+
from aiecs.infrastructure.graph_storage.sqlite import SQLiteGraphStore
|
|
15
|
+
from aiecs.infrastructure.graph_storage.postgres import PostgresGraphStore
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class GraphStorageMigrator:
|
|
21
|
+
"""
|
|
22
|
+
Migrates graph data from one storage backend to another
|
|
23
|
+
|
|
24
|
+
Example:
|
|
25
|
+
```python
|
|
26
|
+
# Migrate from SQLite to PostgreSQL
|
|
27
|
+
source = SQLiteGraphStore("old_graph.db")
|
|
28
|
+
target = PostgresGraphStore(host="localhost", database="new_graph")
|
|
29
|
+
|
|
30
|
+
migrator = GraphStorageMigrator(source, target)
|
|
31
|
+
await migrator.migrate(batch_size=1000, show_progress=True)
|
|
32
|
+
```
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
def __init__(self, source: GraphStore, target: GraphStore):
|
|
36
|
+
"""
|
|
37
|
+
Initialize migrator
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
source: Source graph store to migrate from
|
|
41
|
+
target: Target graph store to migrate to
|
|
42
|
+
"""
|
|
43
|
+
self.source = source
|
|
44
|
+
self.target = target
|
|
45
|
+
|
|
46
|
+
async def migrate(
|
|
47
|
+
self,
|
|
48
|
+
batch_size: int = 1000,
|
|
49
|
+
show_progress: bool = True,
|
|
50
|
+
verify: bool = True,
|
|
51
|
+
) -> Dict[str, Any]:
|
|
52
|
+
"""
|
|
53
|
+
Migrate all graph data from source to target
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
batch_size: Number of entities/relations to migrate per batch
|
|
57
|
+
show_progress: Show progress bar
|
|
58
|
+
verify: Verify migration integrity after completion
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
Migration statistics dictionary
|
|
62
|
+
"""
|
|
63
|
+
logger.info(f"Starting migration from {type(self.source).__name__} to {type(self.target).__name__}")
|
|
64
|
+
|
|
65
|
+
stats: Dict[str, Any] = {
|
|
66
|
+
"entities_migrated": 0,
|
|
67
|
+
"relations_migrated": 0,
|
|
68
|
+
"errors": [],
|
|
69
|
+
"duration_seconds": 0,
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
import time
|
|
73
|
+
|
|
74
|
+
start_time = time.time()
|
|
75
|
+
|
|
76
|
+
try:
|
|
77
|
+
# Initialize both stores
|
|
78
|
+
if not getattr(self.source, "_is_initialized", False):
|
|
79
|
+
await self.source.initialize()
|
|
80
|
+
if not getattr(self.target, "_is_initialized", False):
|
|
81
|
+
await self.target.initialize()
|
|
82
|
+
|
|
83
|
+
# Migrate entities
|
|
84
|
+
logger.info("Migrating entities...")
|
|
85
|
+
stats["entities_migrated"] = await self._migrate_entities(batch_size, show_progress)
|
|
86
|
+
|
|
87
|
+
# Migrate relations
|
|
88
|
+
logger.info("Migrating relations...")
|
|
89
|
+
stats["relations_migrated"] = await self._migrate_relations(batch_size, show_progress)
|
|
90
|
+
|
|
91
|
+
# Verify if requested
|
|
92
|
+
if verify:
|
|
93
|
+
logger.info("Verifying migration...")
|
|
94
|
+
verification = await self._verify_migration()
|
|
95
|
+
stats["verification"] = verification
|
|
96
|
+
|
|
97
|
+
if not verification["success"]:
|
|
98
|
+
logger.warning(f"Migration verification found issues: {verification}")
|
|
99
|
+
|
|
100
|
+
stats["duration_seconds"] = time.time() - start_time
|
|
101
|
+
logger.info(f"Migration completed in {stats['duration_seconds']:.2f}s")
|
|
102
|
+
logger.info(f"Migrated {stats['entities_migrated']} entities and {stats['relations_migrated']} relations")
|
|
103
|
+
|
|
104
|
+
except Exception as e:
|
|
105
|
+
logger.error(f"Migration failed: {e}")
|
|
106
|
+
if isinstance(stats, dict) and "errors" in stats:
|
|
107
|
+
stats["errors"].append(str(e))
|
|
108
|
+
raise
|
|
109
|
+
|
|
110
|
+
return stats
|
|
111
|
+
|
|
112
|
+
async def _migrate_entities(self, batch_size: int, show_progress: bool) -> int:
|
|
113
|
+
"""Migrate all entities from source to target"""
|
|
114
|
+
# Get all entities from source (available via PaginationMixinProtocol)
|
|
115
|
+
entities = await self.source.get_all_entities() # type: ignore[attr-defined]
|
|
116
|
+
total = len(entities)
|
|
117
|
+
|
|
118
|
+
if total == 0:
|
|
119
|
+
logger.warning("No entities to migrate")
|
|
120
|
+
return 0
|
|
121
|
+
|
|
122
|
+
# Use tqdm for progress if requested
|
|
123
|
+
iterator = tqdm(entities, desc="Entities", disable=not show_progress) if show_progress else entities
|
|
124
|
+
|
|
125
|
+
migrated = 0
|
|
126
|
+
errors = []
|
|
127
|
+
|
|
128
|
+
# Migrate in batches using transactions
|
|
129
|
+
for i in range(0, total, batch_size):
|
|
130
|
+
batch = entities[i : i + batch_size]
|
|
131
|
+
|
|
132
|
+
try:
|
|
133
|
+
# transaction() available via TransactionMixinProtocol
|
|
134
|
+
async with self.target.transaction(): # type: ignore[attr-defined]
|
|
135
|
+
for entity in batch:
|
|
136
|
+
try:
|
|
137
|
+
await self.target.add_entity(entity)
|
|
138
|
+
migrated += 1
|
|
139
|
+
if show_progress:
|
|
140
|
+
iterator.update(1)
|
|
141
|
+
except Exception as e:
|
|
142
|
+
error_msg = f"Failed to migrate entity {entity.id}: {e}"
|
|
143
|
+
logger.error(error_msg)
|
|
144
|
+
errors.append(error_msg)
|
|
145
|
+
except Exception as e:
|
|
146
|
+
logger.error(f"Batch transaction failed: {e}")
|
|
147
|
+
# Continue with next batch
|
|
148
|
+
|
|
149
|
+
if errors:
|
|
150
|
+
logger.warning(f"Entity migration completed with {len(errors)} errors")
|
|
151
|
+
|
|
152
|
+
return migrated
|
|
153
|
+
|
|
154
|
+
async def _migrate_relations(self, batch_size: int, show_progress: bool) -> int:
|
|
155
|
+
"""Migrate all relations from source to target"""
|
|
156
|
+
# Get all relations by getting all entities and their neighbors
|
|
157
|
+
# This is a workaround since we don't have a direct get_all_relations
|
|
158
|
+
# method (available via PaginationMixinProtocol)
|
|
159
|
+
all_entities = await self.source.get_all_entities() # type: ignore[attr-defined]
|
|
160
|
+
relations = []
|
|
161
|
+
|
|
162
|
+
# Collect all unique relations
|
|
163
|
+
for entity in all_entities:
|
|
164
|
+
# This is an approximation - we'd need a better way to get all relations
|
|
165
|
+
# For now, we'll use a simpler approach
|
|
166
|
+
pass
|
|
167
|
+
|
|
168
|
+
# Alternative: If the store has a direct way to get relations, use it
|
|
169
|
+
# For SQLite and Postgres, we can query the relations table directly
|
|
170
|
+
if hasattr(self.source, "conn") or hasattr(self.source, "pool"):
|
|
171
|
+
relations = await self._get_all_relations_direct(self.source)
|
|
172
|
+
else:
|
|
173
|
+
logger.warning("Cannot directly access relations, migration may be incomplete")
|
|
174
|
+
return 0
|
|
175
|
+
|
|
176
|
+
total = len(relations)
|
|
177
|
+
|
|
178
|
+
if total == 0:
|
|
179
|
+
logger.warning("No relations to migrate")
|
|
180
|
+
return 0
|
|
181
|
+
|
|
182
|
+
iterator = tqdm(relations, desc="Relations", disable=not show_progress) if show_progress else relations
|
|
183
|
+
|
|
184
|
+
migrated = 0
|
|
185
|
+
errors = []
|
|
186
|
+
|
|
187
|
+
# Migrate in batches
|
|
188
|
+
for i in range(0, total, batch_size):
|
|
189
|
+
batch = relations[i : i + batch_size]
|
|
190
|
+
|
|
191
|
+
try:
|
|
192
|
+
# transaction() available via TransactionMixinProtocol
|
|
193
|
+
async with self.target.transaction(): # type: ignore[attr-defined]
|
|
194
|
+
for relation in batch:
|
|
195
|
+
try:
|
|
196
|
+
await self.target.add_relation(relation)
|
|
197
|
+
migrated += 1
|
|
198
|
+
if show_progress and hasattr(iterator, "update"):
|
|
199
|
+
iterator.update(1)
|
|
200
|
+
except Exception as e:
|
|
201
|
+
error_msg = f"Failed to migrate relation {relation.id}: {e}"
|
|
202
|
+
logger.error(error_msg)
|
|
203
|
+
errors.append(error_msg)
|
|
204
|
+
except Exception as e:
|
|
205
|
+
logger.error(f"Batch transaction failed: {e}")
|
|
206
|
+
|
|
207
|
+
if errors:
|
|
208
|
+
logger.warning(f"Relation migration completed with {len(errors)} errors")
|
|
209
|
+
|
|
210
|
+
return migrated
|
|
211
|
+
|
|
212
|
+
async def _get_all_relations_direct(self, store: GraphStore) -> list:
|
|
213
|
+
"""Get all relations directly from database"""
|
|
214
|
+
from aiecs.domain.knowledge_graph.models.relation import Relation
|
|
215
|
+
|
|
216
|
+
relations = []
|
|
217
|
+
|
|
218
|
+
if isinstance(store, SQLiteGraphStore):
|
|
219
|
+
# SQLite direct query
|
|
220
|
+
if store.conn is None:
|
|
221
|
+
raise RuntimeError("SQLite connection not initialized")
|
|
222
|
+
cursor = await store.conn.execute("SELECT id, relation_type, source_id, target_id, properties, weight FROM relations")
|
|
223
|
+
rows = await cursor.fetchall()
|
|
224
|
+
|
|
225
|
+
for row in rows:
|
|
226
|
+
import json
|
|
227
|
+
|
|
228
|
+
relations.append(
|
|
229
|
+
Relation(
|
|
230
|
+
id=row[0],
|
|
231
|
+
relation_type=row[1],
|
|
232
|
+
source_id=row[2],
|
|
233
|
+
target_id=row[3],
|
|
234
|
+
properties=json.loads(row[4]) if row[4] else {},
|
|
235
|
+
weight=row[5] if row[5] else 1.0,
|
|
236
|
+
)
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
elif isinstance(store, PostgresGraphStore):
|
|
240
|
+
# PostgreSQL direct query
|
|
241
|
+
if store.pool is None:
|
|
242
|
+
raise RuntimeError("PostgreSQL connection pool not initialized")
|
|
243
|
+
async with store.pool.acquire() as conn:
|
|
244
|
+
rows = await conn.fetch(
|
|
245
|
+
"""
|
|
246
|
+
SELECT id, relation_type, source_id, target_id, properties, weight
|
|
247
|
+
FROM graph_relations
|
|
248
|
+
"""
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
for row in rows:
|
|
252
|
+
relations.append(
|
|
253
|
+
Relation(
|
|
254
|
+
id=row["id"],
|
|
255
|
+
relation_type=row["relation_type"],
|
|
256
|
+
source_id=row["source_id"],
|
|
257
|
+
target_id=row["target_id"],
|
|
258
|
+
properties=(row["properties"] if isinstance(row["properties"], dict) else {}),
|
|
259
|
+
weight=(float(row["weight"]) if row["weight"] else 1.0),
|
|
260
|
+
)
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
return relations
|
|
264
|
+
|
|
265
|
+
async def _verify_migration(self) -> Dict[str, Any]:
|
|
266
|
+
"""Verify migration integrity"""
|
|
267
|
+
try:
|
|
268
|
+
# Get counts from both stores (available via StatsMixinProtocol)
|
|
269
|
+
source_stats = await self.source.get_stats() # type: ignore[attr-defined]
|
|
270
|
+
target_stats = await self.target.get_stats() # type: ignore[attr-defined]
|
|
271
|
+
|
|
272
|
+
entity_match = source_stats["entity_count"] == target_stats["entity_count"]
|
|
273
|
+
relation_match = source_stats["relation_count"] == target_stats["relation_count"]
|
|
274
|
+
|
|
275
|
+
return {
|
|
276
|
+
"success": entity_match and relation_match,
|
|
277
|
+
"source_entities": source_stats["entity_count"],
|
|
278
|
+
"target_entities": target_stats["entity_count"],
|
|
279
|
+
"source_relations": source_stats["relation_count"],
|
|
280
|
+
"target_relations": target_stats["relation_count"],
|
|
281
|
+
"entity_match": entity_match,
|
|
282
|
+
"relation_match": relation_match,
|
|
283
|
+
}
|
|
284
|
+
except Exception as e:
|
|
285
|
+
return {"success": False, "error": str(e)}
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
async def migrate_sqlite_to_postgres(
|
|
289
|
+
sqlite_path: str,
|
|
290
|
+
postgres_config: Optional[Dict[str, Any]] = None,
|
|
291
|
+
batch_size: int = 1000,
|
|
292
|
+
show_progress: bool = True,
|
|
293
|
+
) -> Dict[str, Any]:
|
|
294
|
+
"""
|
|
295
|
+
Convenience function to migrate from SQLite to PostgreSQL
|
|
296
|
+
|
|
297
|
+
Args:
|
|
298
|
+
sqlite_path: Path to SQLite database file
|
|
299
|
+
postgres_config: PostgreSQL connection config (or None to use defaults)
|
|
300
|
+
batch_size: Batch size for migration
|
|
301
|
+
show_progress: Show progress bars
|
|
302
|
+
|
|
303
|
+
Returns:
|
|
304
|
+
Migration statistics
|
|
305
|
+
|
|
306
|
+
Example:
|
|
307
|
+
```python
|
|
308
|
+
stats = await migrate_sqlite_to_postgres(
|
|
309
|
+
"knowledge_graph.db",
|
|
310
|
+
postgres_config={
|
|
311
|
+
"host": "localhost",
|
|
312
|
+
"database": "production_kg"
|
|
313
|
+
}
|
|
314
|
+
)
|
|
315
|
+
print(f"Migrated {stats['entities_migrated']} entities")
|
|
316
|
+
```
|
|
317
|
+
"""
|
|
318
|
+
# Create stores
|
|
319
|
+
source = SQLiteGraphStore(sqlite_path)
|
|
320
|
+
|
|
321
|
+
if postgres_config:
|
|
322
|
+
target = PostgresGraphStore(**postgres_config)
|
|
323
|
+
else:
|
|
324
|
+
target = PostgresGraphStore() # Use defaults from config
|
|
325
|
+
|
|
326
|
+
# Migrate
|
|
327
|
+
migrator = GraphStorageMigrator(source, target)
|
|
328
|
+
|
|
329
|
+
try:
|
|
330
|
+
stats = await migrator.migrate(batch_size=batch_size, show_progress=show_progress)
|
|
331
|
+
return stats
|
|
332
|
+
finally:
|
|
333
|
+
await source.close()
|
|
334
|
+
await target.close()
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
# CLI support
|
|
338
|
+
if __name__ == "__main__":
|
|
339
|
+
import argparse
|
|
340
|
+
import sys
|
|
341
|
+
|
|
342
|
+
parser = argparse.ArgumentParser(description="Migrate graph storage between backends")
|
|
343
|
+
parser.add_argument("--source-sqlite", help="Source SQLite database path")
|
|
344
|
+
parser.add_argument("--target-pg-host", default="localhost", help="Target PostgreSQL host")
|
|
345
|
+
parser.add_argument(
|
|
346
|
+
"--target-pg-port",
|
|
347
|
+
type=int,
|
|
348
|
+
default=5432,
|
|
349
|
+
help="Target PostgreSQL port",
|
|
350
|
+
)
|
|
351
|
+
parser.add_argument(
|
|
352
|
+
"--target-pg-database",
|
|
353
|
+
required=True,
|
|
354
|
+
help="Target PostgreSQL database",
|
|
355
|
+
)
|
|
356
|
+
parser.add_argument("--target-pg-user", default="postgres", help="Target PostgreSQL user")
|
|
357
|
+
parser.add_argument("--target-pg-password", help="Target PostgreSQL password")
|
|
358
|
+
parser.add_argument("--batch-size", type=int, default=1000, help="Batch size")
|
|
359
|
+
parser.add_argument("--no-progress", action="store_true", help="Disable progress bars")
|
|
360
|
+
|
|
361
|
+
args = parser.parse_args()
|
|
362
|
+
|
|
363
|
+
if not args.source_sqlite:
|
|
364
|
+
print("Error: --source-sqlite is required")
|
|
365
|
+
sys.exit(1)
|
|
366
|
+
|
|
367
|
+
async def run():
|
|
368
|
+
stats = await migrate_sqlite_to_postgres(
|
|
369
|
+
sqlite_path=args.source_sqlite,
|
|
370
|
+
postgres_config={
|
|
371
|
+
"host": args.target_pg_host,
|
|
372
|
+
"port": args.target_pg_port,
|
|
373
|
+
"database": args.target_pg_database,
|
|
374
|
+
"user": args.target_pg_user,
|
|
375
|
+
"password": args.target_pg_password,
|
|
376
|
+
},
|
|
377
|
+
batch_size=args.batch_size,
|
|
378
|
+
show_progress=not args.no_progress,
|
|
379
|
+
)
|
|
380
|
+
|
|
381
|
+
print("\n" + "=" * 60)
|
|
382
|
+
print("Migration Summary")
|
|
383
|
+
print("=" * 60)
|
|
384
|
+
print(f"Entities migrated: {stats['entities_migrated']}")
|
|
385
|
+
print(f"Relations migrated: {stats['relations_migrated']}")
|
|
386
|
+
print(f"Duration: {stats['duration_seconds']:.2f}s")
|
|
387
|
+
|
|
388
|
+
if stats.get("verification"):
|
|
389
|
+
ver = stats["verification"]
|
|
390
|
+
if ver["success"]:
|
|
391
|
+
print("✅ Verification: PASSED")
|
|
392
|
+
else:
|
|
393
|
+
print("❌ Verification: FAILED")
|
|
394
|
+
print(f" Source entities: {ver['source_entities']}, Target: {ver['target_entities']}")
|
|
395
|
+
print(f" Source relations: {ver['source_relations']}, Target: {ver['target_relations']}")
|
|
396
|
+
|
|
397
|
+
if stats["errors"]:
|
|
398
|
+
print(f"\n⚠️ Errors encountered: {len(stats['errors'])}")
|
|
399
|
+
|
|
400
|
+
asyncio.run(run())
|