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.
- aiecs/__init__.py +72 -0
- aiecs/__main__.py +41 -0
- aiecs/aiecs_client.py +469 -0
- aiecs/application/__init__.py +10 -0
- aiecs/application/executors/__init__.py +10 -0
- aiecs/application/executors/operation_executor.py +363 -0
- aiecs/application/knowledge_graph/__init__.py +7 -0
- aiecs/application/knowledge_graph/builder/__init__.py +37 -0
- aiecs/application/knowledge_graph/builder/document_builder.py +375 -0
- aiecs/application/knowledge_graph/builder/graph_builder.py +356 -0
- aiecs/application/knowledge_graph/builder/schema_mapping.py +531 -0
- aiecs/application/knowledge_graph/builder/structured_pipeline.py +443 -0
- aiecs/application/knowledge_graph/builder/text_chunker.py +319 -0
- aiecs/application/knowledge_graph/extractors/__init__.py +27 -0
- aiecs/application/knowledge_graph/extractors/base.py +100 -0
- aiecs/application/knowledge_graph/extractors/llm_entity_extractor.py +327 -0
- aiecs/application/knowledge_graph/extractors/llm_relation_extractor.py +349 -0
- aiecs/application/knowledge_graph/extractors/ner_entity_extractor.py +244 -0
- aiecs/application/knowledge_graph/fusion/__init__.py +23 -0
- aiecs/application/knowledge_graph/fusion/entity_deduplicator.py +387 -0
- aiecs/application/knowledge_graph/fusion/entity_linker.py +343 -0
- aiecs/application/knowledge_graph/fusion/knowledge_fusion.py +580 -0
- aiecs/application/knowledge_graph/fusion/relation_deduplicator.py +189 -0
- aiecs/application/knowledge_graph/pattern_matching/__init__.py +21 -0
- aiecs/application/knowledge_graph/pattern_matching/pattern_matcher.py +344 -0
- aiecs/application/knowledge_graph/pattern_matching/query_executor.py +378 -0
- aiecs/application/knowledge_graph/profiling/__init__.py +12 -0
- aiecs/application/knowledge_graph/profiling/query_plan_visualizer.py +199 -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 +347 -0
- aiecs/application/knowledge_graph/reasoning/inference_engine.py +504 -0
- aiecs/application/knowledge_graph/reasoning/logic_form_parser.py +167 -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 +630 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/ast_validator.py +654 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/error_handler.py +477 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/parser.py +390 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/query_context.py +217 -0
- aiecs/application/knowledge_graph/reasoning/logic_query_integration.py +169 -0
- aiecs/application/knowledge_graph/reasoning/query_planner.py +872 -0
- aiecs/application/knowledge_graph/reasoning/reasoning_engine.py +554 -0
- aiecs/application/knowledge_graph/retrieval/__init__.py +19 -0
- aiecs/application/knowledge_graph/retrieval/retrieval_strategies.py +596 -0
- aiecs/application/knowledge_graph/search/__init__.py +59 -0
- aiecs/application/knowledge_graph/search/hybrid_search.py +423 -0
- aiecs/application/knowledge_graph/search/reranker.py +295 -0
- aiecs/application/knowledge_graph/search/reranker_strategies.py +553 -0
- aiecs/application/knowledge_graph/search/text_similarity.py +398 -0
- aiecs/application/knowledge_graph/traversal/__init__.py +15 -0
- aiecs/application/knowledge_graph/traversal/enhanced_traversal.py +329 -0
- aiecs/application/knowledge_graph/traversal/path_scorer.py +269 -0
- aiecs/application/knowledge_graph/validators/__init__.py +13 -0
- aiecs/application/knowledge_graph/validators/relation_validator.py +189 -0
- aiecs/application/knowledge_graph/visualization/__init__.py +11 -0
- aiecs/application/knowledge_graph/visualization/graph_visualizer.py +321 -0
- aiecs/common/__init__.py +9 -0
- aiecs/common/knowledge_graph/__init__.py +17 -0
- aiecs/common/knowledge_graph/runnable.py +484 -0
- aiecs/config/__init__.py +16 -0
- aiecs/config/config.py +498 -0
- aiecs/config/graph_config.py +137 -0
- aiecs/config/registry.py +23 -0
- aiecs/core/__init__.py +46 -0
- aiecs/core/interface/__init__.py +34 -0
- aiecs/core/interface/execution_interface.py +152 -0
- aiecs/core/interface/storage_interface.py +171 -0
- aiecs/domain/__init__.py +289 -0
- aiecs/domain/agent/__init__.py +189 -0
- aiecs/domain/agent/base_agent.py +697 -0
- aiecs/domain/agent/exceptions.py +103 -0
- aiecs/domain/agent/graph_aware_mixin.py +559 -0
- aiecs/domain/agent/hybrid_agent.py +490 -0
- aiecs/domain/agent/integration/__init__.py +26 -0
- aiecs/domain/agent/integration/context_compressor.py +222 -0
- aiecs/domain/agent/integration/context_engine_adapter.py +252 -0
- aiecs/domain/agent/integration/retry_policy.py +219 -0
- aiecs/domain/agent/integration/role_config.py +213 -0
- aiecs/domain/agent/knowledge_aware_agent.py +646 -0
- aiecs/domain/agent/lifecycle.py +296 -0
- aiecs/domain/agent/llm_agent.py +300 -0
- aiecs/domain/agent/memory/__init__.py +12 -0
- aiecs/domain/agent/memory/conversation.py +197 -0
- aiecs/domain/agent/migration/__init__.py +14 -0
- aiecs/domain/agent/migration/conversion.py +160 -0
- aiecs/domain/agent/migration/legacy_wrapper.py +90 -0
- aiecs/domain/agent/models.py +317 -0
- aiecs/domain/agent/observability.py +407 -0
- aiecs/domain/agent/persistence.py +289 -0
- aiecs/domain/agent/prompts/__init__.py +29 -0
- aiecs/domain/agent/prompts/builder.py +161 -0
- aiecs/domain/agent/prompts/formatters.py +189 -0
- aiecs/domain/agent/prompts/template.py +255 -0
- aiecs/domain/agent/registry.py +260 -0
- aiecs/domain/agent/tool_agent.py +257 -0
- aiecs/domain/agent/tools/__init__.py +12 -0
- aiecs/domain/agent/tools/schema_generator.py +221 -0
- aiecs/domain/community/__init__.py +155 -0
- aiecs/domain/community/agent_adapter.py +477 -0
- aiecs/domain/community/analytics.py +481 -0
- aiecs/domain/community/collaborative_workflow.py +642 -0
- aiecs/domain/community/communication_hub.py +645 -0
- aiecs/domain/community/community_builder.py +320 -0
- aiecs/domain/community/community_integration.py +800 -0
- aiecs/domain/community/community_manager.py +813 -0
- aiecs/domain/community/decision_engine.py +879 -0
- aiecs/domain/community/exceptions.py +225 -0
- aiecs/domain/community/models/__init__.py +33 -0
- aiecs/domain/community/models/community_models.py +268 -0
- aiecs/domain/community/resource_manager.py +457 -0
- aiecs/domain/community/shared_context_manager.py +603 -0
- aiecs/domain/context/__init__.py +58 -0
- aiecs/domain/context/context_engine.py +989 -0
- aiecs/domain/context/conversation_models.py +354 -0
- aiecs/domain/context/graph_memory.py +467 -0
- aiecs/domain/execution/__init__.py +12 -0
- aiecs/domain/execution/model.py +57 -0
- aiecs/domain/knowledge_graph/__init__.py +19 -0
- aiecs/domain/knowledge_graph/models/__init__.py +52 -0
- aiecs/domain/knowledge_graph/models/entity.py +130 -0
- aiecs/domain/knowledge_graph/models/evidence.py +194 -0
- aiecs/domain/knowledge_graph/models/inference_rule.py +186 -0
- aiecs/domain/knowledge_graph/models/path.py +179 -0
- aiecs/domain/knowledge_graph/models/path_pattern.py +173 -0
- aiecs/domain/knowledge_graph/models/query.py +272 -0
- aiecs/domain/knowledge_graph/models/query_plan.py +187 -0
- aiecs/domain/knowledge_graph/models/relation.py +136 -0
- aiecs/domain/knowledge_graph/schema/__init__.py +23 -0
- aiecs/domain/knowledge_graph/schema/entity_type.py +135 -0
- aiecs/domain/knowledge_graph/schema/graph_schema.py +271 -0
- aiecs/domain/knowledge_graph/schema/property_schema.py +155 -0
- aiecs/domain/knowledge_graph/schema/relation_type.py +171 -0
- aiecs/domain/knowledge_graph/schema/schema_manager.py +496 -0
- aiecs/domain/knowledge_graph/schema/type_enums.py +205 -0
- aiecs/domain/task/__init__.py +13 -0
- aiecs/domain/task/dsl_processor.py +613 -0
- aiecs/domain/task/model.py +62 -0
- aiecs/domain/task/task_context.py +268 -0
- aiecs/infrastructure/__init__.py +24 -0
- aiecs/infrastructure/graph_storage/__init__.py +11 -0
- aiecs/infrastructure/graph_storage/base.py +601 -0
- aiecs/infrastructure/graph_storage/batch_operations.py +449 -0
- aiecs/infrastructure/graph_storage/cache.py +429 -0
- aiecs/infrastructure/graph_storage/distributed.py +226 -0
- aiecs/infrastructure/graph_storage/error_handling.py +390 -0
- aiecs/infrastructure/graph_storage/graceful_degradation.py +306 -0
- aiecs/infrastructure/graph_storage/health_checks.py +378 -0
- aiecs/infrastructure/graph_storage/in_memory.py +514 -0
- aiecs/infrastructure/graph_storage/index_optimization.py +483 -0
- aiecs/infrastructure/graph_storage/lazy_loading.py +410 -0
- aiecs/infrastructure/graph_storage/metrics.py +357 -0
- aiecs/infrastructure/graph_storage/migration.py +413 -0
- aiecs/infrastructure/graph_storage/pagination.py +471 -0
- aiecs/infrastructure/graph_storage/performance_monitoring.py +466 -0
- aiecs/infrastructure/graph_storage/postgres.py +871 -0
- aiecs/infrastructure/graph_storage/query_optimizer.py +635 -0
- aiecs/infrastructure/graph_storage/schema_cache.py +290 -0
- aiecs/infrastructure/graph_storage/sqlite.py +623 -0
- aiecs/infrastructure/graph_storage/streaming.py +495 -0
- aiecs/infrastructure/messaging/__init__.py +13 -0
- aiecs/infrastructure/messaging/celery_task_manager.py +383 -0
- aiecs/infrastructure/messaging/websocket_manager.py +298 -0
- aiecs/infrastructure/monitoring/__init__.py +34 -0
- aiecs/infrastructure/monitoring/executor_metrics.py +174 -0
- aiecs/infrastructure/monitoring/global_metrics_manager.py +213 -0
- aiecs/infrastructure/monitoring/structured_logger.py +48 -0
- aiecs/infrastructure/monitoring/tracing_manager.py +410 -0
- aiecs/infrastructure/persistence/__init__.py +24 -0
- aiecs/infrastructure/persistence/context_engine_client.py +187 -0
- aiecs/infrastructure/persistence/database_manager.py +333 -0
- aiecs/infrastructure/persistence/file_storage.py +754 -0
- aiecs/infrastructure/persistence/redis_client.py +220 -0
- aiecs/llm/__init__.py +86 -0
- aiecs/llm/callbacks/__init__.py +11 -0
- aiecs/llm/callbacks/custom_callbacks.py +264 -0
- aiecs/llm/client_factory.py +420 -0
- aiecs/llm/clients/__init__.py +33 -0
- aiecs/llm/clients/base_client.py +193 -0
- aiecs/llm/clients/googleai_client.py +181 -0
- aiecs/llm/clients/openai_client.py +131 -0
- aiecs/llm/clients/vertex_client.py +437 -0
- aiecs/llm/clients/xai_client.py +184 -0
- aiecs/llm/config/__init__.py +51 -0
- aiecs/llm/config/config_loader.py +275 -0
- aiecs/llm/config/config_validator.py +236 -0
- aiecs/llm/config/model_config.py +151 -0
- aiecs/llm/utils/__init__.py +10 -0
- aiecs/llm/utils/validate_config.py +91 -0
- aiecs/main.py +363 -0
- aiecs/scripts/__init__.py +3 -0
- aiecs/scripts/aid/VERSION_MANAGEMENT.md +97 -0
- aiecs/scripts/aid/__init__.py +19 -0
- aiecs/scripts/aid/version_manager.py +215 -0
- aiecs/scripts/dependance_check/DEPENDENCY_SYSTEM_SUMMARY.md +242 -0
- aiecs/scripts/dependance_check/README_DEPENDENCY_CHECKER.md +310 -0
- aiecs/scripts/dependance_check/__init__.py +17 -0
- aiecs/scripts/dependance_check/dependency_checker.py +938 -0
- aiecs/scripts/dependance_check/dependency_fixer.py +391 -0
- aiecs/scripts/dependance_check/download_nlp_data.py +396 -0
- aiecs/scripts/dependance_check/quick_dependency_check.py +270 -0
- aiecs/scripts/dependance_check/setup_nlp_data.sh +217 -0
- aiecs/scripts/dependance_patch/__init__.py +7 -0
- aiecs/scripts/dependance_patch/fix_weasel/README_WEASEL_PATCH.md +126 -0
- aiecs/scripts/dependance_patch/fix_weasel/__init__.py +11 -0
- aiecs/scripts/dependance_patch/fix_weasel/fix_weasel_validator.py +128 -0
- aiecs/scripts/dependance_patch/fix_weasel/fix_weasel_validator.sh +82 -0
- aiecs/scripts/dependance_patch/fix_weasel/patch_weasel_library.sh +188 -0
- aiecs/scripts/dependance_patch/fix_weasel/run_weasel_patch.sh +41 -0
- aiecs/scripts/tools_develop/README.md +449 -0
- aiecs/scripts/tools_develop/TOOL_AUTO_DISCOVERY.md +234 -0
- aiecs/scripts/tools_develop/__init__.py +21 -0
- aiecs/scripts/tools_develop/check_type_annotations.py +259 -0
- aiecs/scripts/tools_develop/validate_tool_schemas.py +422 -0
- aiecs/scripts/tools_develop/verify_tools.py +356 -0
- aiecs/tasks/__init__.py +1 -0
- aiecs/tasks/worker.py +172 -0
- aiecs/tools/__init__.py +299 -0
- aiecs/tools/apisource/__init__.py +99 -0
- aiecs/tools/apisource/intelligence/__init__.py +19 -0
- aiecs/tools/apisource/intelligence/data_fusion.py +381 -0
- aiecs/tools/apisource/intelligence/query_analyzer.py +413 -0
- aiecs/tools/apisource/intelligence/search_enhancer.py +388 -0
- aiecs/tools/apisource/monitoring/__init__.py +9 -0
- aiecs/tools/apisource/monitoring/metrics.py +303 -0
- aiecs/tools/apisource/providers/__init__.py +115 -0
- aiecs/tools/apisource/providers/base.py +664 -0
- aiecs/tools/apisource/providers/census.py +401 -0
- aiecs/tools/apisource/providers/fred.py +564 -0
- aiecs/tools/apisource/providers/newsapi.py +412 -0
- aiecs/tools/apisource/providers/worldbank.py +357 -0
- aiecs/tools/apisource/reliability/__init__.py +12 -0
- aiecs/tools/apisource/reliability/error_handler.py +375 -0
- aiecs/tools/apisource/reliability/fallback_strategy.py +391 -0
- aiecs/tools/apisource/tool.py +850 -0
- aiecs/tools/apisource/utils/__init__.py +9 -0
- aiecs/tools/apisource/utils/validators.py +338 -0
- aiecs/tools/base_tool.py +201 -0
- aiecs/tools/docs/__init__.py +121 -0
- aiecs/tools/docs/ai_document_orchestrator.py +599 -0
- aiecs/tools/docs/ai_document_writer_orchestrator.py +2403 -0
- aiecs/tools/docs/content_insertion_tool.py +1333 -0
- aiecs/tools/docs/document_creator_tool.py +1317 -0
- aiecs/tools/docs/document_layout_tool.py +1166 -0
- aiecs/tools/docs/document_parser_tool.py +994 -0
- aiecs/tools/docs/document_writer_tool.py +1818 -0
- aiecs/tools/knowledge_graph/__init__.py +17 -0
- aiecs/tools/knowledge_graph/graph_reasoning_tool.py +734 -0
- aiecs/tools/knowledge_graph/graph_search_tool.py +923 -0
- aiecs/tools/knowledge_graph/kg_builder_tool.py +476 -0
- aiecs/tools/langchain_adapter.py +542 -0
- aiecs/tools/schema_generator.py +275 -0
- aiecs/tools/search_tool/__init__.py +100 -0
- aiecs/tools/search_tool/analyzers.py +589 -0
- aiecs/tools/search_tool/cache.py +260 -0
- aiecs/tools/search_tool/constants.py +128 -0
- aiecs/tools/search_tool/context.py +216 -0
- aiecs/tools/search_tool/core.py +749 -0
- aiecs/tools/search_tool/deduplicator.py +123 -0
- aiecs/tools/search_tool/error_handler.py +271 -0
- aiecs/tools/search_tool/metrics.py +371 -0
- aiecs/tools/search_tool/rate_limiter.py +178 -0
- aiecs/tools/search_tool/schemas.py +277 -0
- aiecs/tools/statistics/__init__.py +80 -0
- aiecs/tools/statistics/ai_data_analysis_orchestrator.py +643 -0
- aiecs/tools/statistics/ai_insight_generator_tool.py +505 -0
- aiecs/tools/statistics/ai_report_orchestrator_tool.py +694 -0
- aiecs/tools/statistics/data_loader_tool.py +564 -0
- aiecs/tools/statistics/data_profiler_tool.py +658 -0
- aiecs/tools/statistics/data_transformer_tool.py +573 -0
- aiecs/tools/statistics/data_visualizer_tool.py +495 -0
- aiecs/tools/statistics/model_trainer_tool.py +487 -0
- aiecs/tools/statistics/statistical_analyzer_tool.py +459 -0
- aiecs/tools/task_tools/__init__.py +86 -0
- aiecs/tools/task_tools/chart_tool.py +732 -0
- aiecs/tools/task_tools/classfire_tool.py +922 -0
- aiecs/tools/task_tools/image_tool.py +447 -0
- aiecs/tools/task_tools/office_tool.py +684 -0
- aiecs/tools/task_tools/pandas_tool.py +635 -0
- aiecs/tools/task_tools/report_tool.py +635 -0
- aiecs/tools/task_tools/research_tool.py +392 -0
- aiecs/tools/task_tools/scraper_tool.py +715 -0
- aiecs/tools/task_tools/stats_tool.py +688 -0
- aiecs/tools/temp_file_manager.py +130 -0
- aiecs/tools/tool_executor/__init__.py +37 -0
- aiecs/tools/tool_executor/tool_executor.py +881 -0
- aiecs/utils/LLM_output_structor.py +445 -0
- aiecs/utils/__init__.py +34 -0
- aiecs/utils/base_callback.py +47 -0
- aiecs/utils/cache_provider.py +695 -0
- aiecs/utils/execution_utils.py +184 -0
- aiecs/utils/logging.py +1 -0
- aiecs/utils/prompt_loader.py +14 -0
- aiecs/utils/token_usage_repository.py +323 -0
- aiecs/ws/__init__.py +0 -0
- aiecs/ws/socket_server.py +52 -0
- aiecs-1.5.1.dist-info/METADATA +608 -0
- aiecs-1.5.1.dist-info/RECORD +302 -0
- aiecs-1.5.1.dist-info/WHEEL +5 -0
- aiecs-1.5.1.dist-info/entry_points.txt +10 -0
- aiecs-1.5.1.dist-info/licenses/LICENSE +225 -0
- aiecs-1.5.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,481 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Community Analytics
|
|
3
|
+
|
|
4
|
+
Tracks decision patterns, member participation, community health metrics,
|
|
5
|
+
and collaboration effectiveness.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import logging
|
|
9
|
+
from datetime import datetime, timedelta
|
|
10
|
+
from typing import Dict, Any
|
|
11
|
+
from collections import defaultdict
|
|
12
|
+
|
|
13
|
+
from .models.community_models import DecisionStatus
|
|
14
|
+
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class CommunityAnalytics:
|
|
19
|
+
"""
|
|
20
|
+
Analytics engine for tracking community health and effectiveness.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
def __init__(self, community_manager=None):
|
|
24
|
+
"""
|
|
25
|
+
Initialize community analytics.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
community_manager: Reference to the community manager
|
|
29
|
+
"""
|
|
30
|
+
self.community_manager = community_manager
|
|
31
|
+
|
|
32
|
+
# Analytics caches
|
|
33
|
+
self._decision_patterns_cache: Dict[str, Any] = {}
|
|
34
|
+
self._participation_cache: Dict[str, Any] = {}
|
|
35
|
+
self._health_metrics_cache: Dict[str, Any] = {}
|
|
36
|
+
|
|
37
|
+
logger.info("Community analytics initialized")
|
|
38
|
+
|
|
39
|
+
def get_decision_analytics(
|
|
40
|
+
self, community_id: str, time_range_days: int = 30
|
|
41
|
+
) -> Dict[str, Any]:
|
|
42
|
+
"""
|
|
43
|
+
Get decision analytics for a community.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
community_id: ID of the community
|
|
47
|
+
time_range_days: Time range for analytics in days
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
Decision analytics data
|
|
51
|
+
"""
|
|
52
|
+
if not self.community_manager:
|
|
53
|
+
return {}
|
|
54
|
+
|
|
55
|
+
community = self.community_manager.communities.get(community_id)
|
|
56
|
+
if not community:
|
|
57
|
+
return {}
|
|
58
|
+
|
|
59
|
+
cutoff_date = datetime.utcnow() - timedelta(days=time_range_days)
|
|
60
|
+
|
|
61
|
+
# Collect decisions within time range
|
|
62
|
+
decisions = []
|
|
63
|
+
for decision in self.community_manager.decisions.values():
|
|
64
|
+
if decision.created_at >= cutoff_date:
|
|
65
|
+
# Check if decision belongs to this community
|
|
66
|
+
if decision.proposer_id in community.members:
|
|
67
|
+
decisions.append(decision)
|
|
68
|
+
|
|
69
|
+
# Calculate decision metrics
|
|
70
|
+
total_decisions = len(decisions)
|
|
71
|
+
approved = sum(1 for d in decisions if d.status == DecisionStatus.APPROVED)
|
|
72
|
+
rejected = sum(1 for d in decisions if d.status == DecisionStatus.REJECTED)
|
|
73
|
+
pending = sum(
|
|
74
|
+
1 for d in decisions if d.status in [DecisionStatus.PROPOSED, DecisionStatus.VOTING]
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
# Calculate average time to decision
|
|
78
|
+
decision_times = []
|
|
79
|
+
for decision in decisions:
|
|
80
|
+
if decision.status in [
|
|
81
|
+
DecisionStatus.APPROVED,
|
|
82
|
+
DecisionStatus.REJECTED,
|
|
83
|
+
]:
|
|
84
|
+
if decision.implemented_at or decision.created_at:
|
|
85
|
+
end_time = decision.implemented_at or datetime.utcnow()
|
|
86
|
+
duration = (end_time - decision.created_at).total_seconds() / 3600 # hours
|
|
87
|
+
decision_times.append(duration)
|
|
88
|
+
|
|
89
|
+
avg_decision_time = sum(decision_times) / len(decision_times) if decision_times else 0
|
|
90
|
+
|
|
91
|
+
# Decision types distribution
|
|
92
|
+
decision_types = defaultdict(int)
|
|
93
|
+
for decision in decisions:
|
|
94
|
+
decision_types[decision.decision_type] += 1
|
|
95
|
+
|
|
96
|
+
# Approval rate by type
|
|
97
|
+
approval_by_type = {}
|
|
98
|
+
for dtype in decision_types.keys():
|
|
99
|
+
type_decisions = [d for d in decisions if d.decision_type == dtype]
|
|
100
|
+
type_approved = sum(1 for d in type_decisions if d.status == DecisionStatus.APPROVED)
|
|
101
|
+
approval_by_type[dtype] = type_approved / len(type_decisions) if type_decisions else 0
|
|
102
|
+
|
|
103
|
+
analytics = {
|
|
104
|
+
"community_id": community_id,
|
|
105
|
+
"time_range_days": time_range_days,
|
|
106
|
+
"total_decisions": total_decisions,
|
|
107
|
+
"approved": approved,
|
|
108
|
+
"rejected": rejected,
|
|
109
|
+
"pending": pending,
|
|
110
|
+
"approval_rate": (approved / total_decisions if total_decisions > 0 else 0),
|
|
111
|
+
"rejection_rate": (rejected / total_decisions if total_decisions > 0 else 0),
|
|
112
|
+
"average_decision_time_hours": avg_decision_time,
|
|
113
|
+
"decision_types": dict(decision_types),
|
|
114
|
+
"approval_rate_by_type": approval_by_type,
|
|
115
|
+
"decision_velocity": (total_decisions / time_range_days if time_range_days > 0 else 0),
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return analytics
|
|
119
|
+
|
|
120
|
+
def get_member_participation_analytics(
|
|
121
|
+
self, community_id: str, time_range_days: int = 30
|
|
122
|
+
) -> Dict[str, Any]:
|
|
123
|
+
"""
|
|
124
|
+
Get member participation analytics.
|
|
125
|
+
|
|
126
|
+
Args:
|
|
127
|
+
community_id: ID of the community
|
|
128
|
+
time_range_days: Time range for analytics in days
|
|
129
|
+
|
|
130
|
+
Returns:
|
|
131
|
+
Participation analytics data
|
|
132
|
+
"""
|
|
133
|
+
if not self.community_manager:
|
|
134
|
+
return {}
|
|
135
|
+
|
|
136
|
+
community = self.community_manager.communities.get(community_id)
|
|
137
|
+
if not community:
|
|
138
|
+
return {}
|
|
139
|
+
|
|
140
|
+
cutoff_date = datetime.utcnow() - timedelta(days=time_range_days)
|
|
141
|
+
|
|
142
|
+
# Member participation metrics
|
|
143
|
+
member_metrics = {}
|
|
144
|
+
for member_id in community.members:
|
|
145
|
+
member = self.community_manager.members.get(member_id)
|
|
146
|
+
if not member:
|
|
147
|
+
continue
|
|
148
|
+
|
|
149
|
+
# Count votes
|
|
150
|
+
votes_cast = 0
|
|
151
|
+
proposals_made = 0
|
|
152
|
+
|
|
153
|
+
for decision in self.community_manager.decisions.values():
|
|
154
|
+
if decision.created_at >= cutoff_date:
|
|
155
|
+
if (
|
|
156
|
+
member_id in decision.votes_for
|
|
157
|
+
or member_id in decision.votes_against
|
|
158
|
+
or member_id in decision.abstentions
|
|
159
|
+
):
|
|
160
|
+
votes_cast += 1
|
|
161
|
+
if decision.proposer_id == member_id:
|
|
162
|
+
proposals_made += 1
|
|
163
|
+
|
|
164
|
+
# Count resources contributed
|
|
165
|
+
resources_created = sum(
|
|
166
|
+
1
|
|
167
|
+
for resource in self.community_manager.resources.values()
|
|
168
|
+
if resource.owner_id == member_id and resource.created_at >= cutoff_date
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
member_metrics[member_id] = {
|
|
172
|
+
"agent_id": member.agent_id,
|
|
173
|
+
"community_role": member.community_role.value,
|
|
174
|
+
"votes_cast": votes_cast,
|
|
175
|
+
"proposals_made": proposals_made,
|
|
176
|
+
"resources_created": resources_created,
|
|
177
|
+
"contribution_score": member.contribution_score,
|
|
178
|
+
"reputation": member.reputation,
|
|
179
|
+
"is_active": member.is_active,
|
|
180
|
+
"participation_level": member.participation_level,
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
# Calculate aggregate metrics
|
|
184
|
+
total_members = len(member_metrics)
|
|
185
|
+
active_members = sum(1 for m in member_metrics.values() if m["is_active"])
|
|
186
|
+
total_votes = sum(m["votes_cast"] for m in member_metrics.values())
|
|
187
|
+
total_proposals = sum(m["proposals_made"] for m in member_metrics.values())
|
|
188
|
+
total_resources = sum(m["resources_created"] for m in member_metrics.values())
|
|
189
|
+
|
|
190
|
+
# Identify top contributors
|
|
191
|
+
top_voters = sorted(
|
|
192
|
+
member_metrics.items(),
|
|
193
|
+
key=lambda x: x[1]["votes_cast"],
|
|
194
|
+
reverse=True,
|
|
195
|
+
)[:5]
|
|
196
|
+
|
|
197
|
+
top_proposers = sorted(
|
|
198
|
+
member_metrics.items(),
|
|
199
|
+
key=lambda x: x[1]["proposals_made"],
|
|
200
|
+
reverse=True,
|
|
201
|
+
)[:5]
|
|
202
|
+
|
|
203
|
+
top_contributors = sorted(
|
|
204
|
+
member_metrics.items(),
|
|
205
|
+
key=lambda x: x[1]["contribution_score"],
|
|
206
|
+
reverse=True,
|
|
207
|
+
)[:5]
|
|
208
|
+
|
|
209
|
+
analytics = {
|
|
210
|
+
"community_id": community_id,
|
|
211
|
+
"time_range_days": time_range_days,
|
|
212
|
+
"total_members": total_members,
|
|
213
|
+
"active_members": active_members,
|
|
214
|
+
"activity_rate": (active_members / total_members if total_members > 0 else 0),
|
|
215
|
+
"total_votes_cast": total_votes,
|
|
216
|
+
"total_proposals_made": total_proposals,
|
|
217
|
+
"total_resources_created": total_resources,
|
|
218
|
+
"average_votes_per_member": (total_votes / total_members if total_members > 0 else 0),
|
|
219
|
+
"average_proposals_per_member": (
|
|
220
|
+
total_proposals / total_members if total_members > 0 else 0
|
|
221
|
+
),
|
|
222
|
+
"member_metrics": member_metrics,
|
|
223
|
+
"top_voters": [{"member_id": mid, **metrics} for mid, metrics in top_voters],
|
|
224
|
+
"top_proposers": [{"member_id": mid, **metrics} for mid, metrics in top_proposers],
|
|
225
|
+
"top_contributors": [
|
|
226
|
+
{"member_id": mid, **metrics} for mid, metrics in top_contributors
|
|
227
|
+
],
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
return analytics
|
|
231
|
+
|
|
232
|
+
def get_community_health_metrics(self, community_id: str) -> Dict[str, Any]:
|
|
233
|
+
"""
|
|
234
|
+
Get comprehensive community health metrics.
|
|
235
|
+
|
|
236
|
+
Args:
|
|
237
|
+
community_id: ID of the community
|
|
238
|
+
|
|
239
|
+
Returns:
|
|
240
|
+
Health metrics data
|
|
241
|
+
"""
|
|
242
|
+
if not self.community_manager:
|
|
243
|
+
return {}
|
|
244
|
+
|
|
245
|
+
community = self.community_manager.communities.get(community_id)
|
|
246
|
+
if not community:
|
|
247
|
+
return {}
|
|
248
|
+
|
|
249
|
+
# Member health
|
|
250
|
+
total_members = len(community.members)
|
|
251
|
+
active_members = sum(
|
|
252
|
+
1
|
|
253
|
+
for mid in community.members
|
|
254
|
+
if self.community_manager.members.get(mid)
|
|
255
|
+
and self.community_manager.members[mid].is_active
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
# Leadership health
|
|
259
|
+
has_leaders = len(community.leaders) > 0
|
|
260
|
+
has_coordinators = len(community.coordinators) > 0
|
|
261
|
+
(
|
|
262
|
+
(len(community.leaders) + len(community.coordinators)) / total_members
|
|
263
|
+
if total_members > 0
|
|
264
|
+
else 0
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
# Activity health
|
|
268
|
+
recent_activity_days = 7
|
|
269
|
+
recent_cutoff = datetime.utcnow() - timedelta(days=recent_activity_days)
|
|
270
|
+
|
|
271
|
+
recent_decisions = sum(
|
|
272
|
+
1
|
|
273
|
+
for d in self.community_manager.decisions.values()
|
|
274
|
+
if d.created_at >= recent_cutoff and d.proposer_id in community.members
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
recent_resources = sum(
|
|
278
|
+
1
|
|
279
|
+
for rid in community.shared_resources
|
|
280
|
+
if self.community_manager.resources.get(rid)
|
|
281
|
+
and self.community_manager.resources[rid].created_at >= recent_cutoff
|
|
282
|
+
)
|
|
283
|
+
|
|
284
|
+
# Diversity metrics
|
|
285
|
+
role_distribution = defaultdict(int)
|
|
286
|
+
for member_id in community.members:
|
|
287
|
+
member = self.community_manager.members.get(member_id)
|
|
288
|
+
if member:
|
|
289
|
+
role_distribution[member.community_role.value] += 1
|
|
290
|
+
|
|
291
|
+
role_diversity = len(role_distribution) / 5 # Max 5 role types
|
|
292
|
+
|
|
293
|
+
# Collaboration score (from community model)
|
|
294
|
+
collaboration_score = community.collaboration_score
|
|
295
|
+
|
|
296
|
+
# Calculate overall health score (0-100)
|
|
297
|
+
health_components = {
|
|
298
|
+
"member_activity": ((active_members / total_members * 100) if total_members > 0 else 0),
|
|
299
|
+
"leadership": (
|
|
300
|
+
100
|
|
301
|
+
if has_leaders and has_coordinators
|
|
302
|
+
else 50 if has_leaders or has_coordinators else 0
|
|
303
|
+
),
|
|
304
|
+
"recent_activity": min((recent_decisions + recent_resources) * 10, 100),
|
|
305
|
+
"role_diversity": role_diversity * 100,
|
|
306
|
+
"collaboration": collaboration_score * 100,
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
overall_health = sum(health_components.values()) / len(health_components)
|
|
310
|
+
|
|
311
|
+
# Determine health status
|
|
312
|
+
if overall_health >= 80:
|
|
313
|
+
health_status = "excellent"
|
|
314
|
+
elif overall_health >= 60:
|
|
315
|
+
health_status = "good"
|
|
316
|
+
elif overall_health >= 40:
|
|
317
|
+
health_status = "fair"
|
|
318
|
+
elif overall_health >= 20:
|
|
319
|
+
health_status = "poor"
|
|
320
|
+
else:
|
|
321
|
+
health_status = "critical"
|
|
322
|
+
|
|
323
|
+
# Recommendations
|
|
324
|
+
recommendations = []
|
|
325
|
+
if total_members == 0:
|
|
326
|
+
recommendations.append("Add members to the community to begin collaboration")
|
|
327
|
+
elif active_members / total_members < 0.5:
|
|
328
|
+
recommendations.append("Increase member engagement through targeted activities")
|
|
329
|
+
if not has_leaders:
|
|
330
|
+
recommendations.append("Assign community leaders for better coordination")
|
|
331
|
+
if recent_decisions + recent_resources < 3:
|
|
332
|
+
recommendations.append("Encourage more community activity and collaboration")
|
|
333
|
+
if role_diversity < 0.6:
|
|
334
|
+
recommendations.append("Improve role diversity by adding members with different roles")
|
|
335
|
+
|
|
336
|
+
metrics = {
|
|
337
|
+
"community_id": community_id,
|
|
338
|
+
"community_name": community.name,
|
|
339
|
+
"overall_health_score": round(overall_health, 2),
|
|
340
|
+
"health_status": health_status,
|
|
341
|
+
"health_components": health_components,
|
|
342
|
+
"member_statistics": {
|
|
343
|
+
"total": total_members,
|
|
344
|
+
"active": active_members,
|
|
345
|
+
"inactive": total_members - active_members,
|
|
346
|
+
"leaders": len(community.leaders),
|
|
347
|
+
"coordinators": len(community.coordinators),
|
|
348
|
+
},
|
|
349
|
+
"activity_statistics": {
|
|
350
|
+
"recent_decisions": recent_decisions,
|
|
351
|
+
"recent_resources": recent_resources,
|
|
352
|
+
"total_decisions": community.decision_count,
|
|
353
|
+
"total_resources": community.resource_count,
|
|
354
|
+
},
|
|
355
|
+
"diversity_metrics": {
|
|
356
|
+
"role_distribution": dict(role_distribution),
|
|
357
|
+
"role_diversity_score": round(role_diversity, 2),
|
|
358
|
+
},
|
|
359
|
+
"collaboration_score": collaboration_score,
|
|
360
|
+
"recommendations": recommendations,
|
|
361
|
+
"timestamp": datetime.utcnow().isoformat(),
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
return metrics
|
|
365
|
+
|
|
366
|
+
def get_collaboration_effectiveness(
|
|
367
|
+
self, community_id: str, time_range_days: int = 30
|
|
368
|
+
) -> Dict[str, Any]:
|
|
369
|
+
"""
|
|
370
|
+
Get collaboration effectiveness metrics.
|
|
371
|
+
|
|
372
|
+
Args:
|
|
373
|
+
community_id: ID of the community
|
|
374
|
+
time_range_days: Time range for analytics in days
|
|
375
|
+
|
|
376
|
+
Returns:
|
|
377
|
+
Collaboration effectiveness data
|
|
378
|
+
"""
|
|
379
|
+
if not self.community_manager:
|
|
380
|
+
return {}
|
|
381
|
+
|
|
382
|
+
# Get decision and participation analytics
|
|
383
|
+
decision_analytics = self.get_decision_analytics(community_id, time_range_days)
|
|
384
|
+
participation_analytics = self.get_member_participation_analytics(
|
|
385
|
+
community_id, time_range_days
|
|
386
|
+
)
|
|
387
|
+
|
|
388
|
+
# Calculate effectiveness metrics
|
|
389
|
+
decision_efficiency = decision_analytics.get("decision_velocity", 0) * 10
|
|
390
|
+
approval_effectiveness = decision_analytics.get("approval_rate", 0) * 100
|
|
391
|
+
participation_rate = participation_analytics.get("activity_rate", 0) * 100
|
|
392
|
+
|
|
393
|
+
# Combined effectiveness score
|
|
394
|
+
effectiveness_score = (
|
|
395
|
+
decision_efficiency * 0.3 + approval_effectiveness * 0.4 + participation_rate * 0.3
|
|
396
|
+
)
|
|
397
|
+
|
|
398
|
+
# Determine effectiveness level
|
|
399
|
+
if effectiveness_score >= 80:
|
|
400
|
+
effectiveness_level = "highly_effective"
|
|
401
|
+
elif effectiveness_score >= 60:
|
|
402
|
+
effectiveness_level = "effective"
|
|
403
|
+
elif effectiveness_score >= 40:
|
|
404
|
+
effectiveness_level = "moderately_effective"
|
|
405
|
+
else:
|
|
406
|
+
effectiveness_level = "needs_improvement"
|
|
407
|
+
|
|
408
|
+
# Identify strengths and weaknesses
|
|
409
|
+
strengths = []
|
|
410
|
+
weaknesses = []
|
|
411
|
+
|
|
412
|
+
if decision_efficiency >= 8:
|
|
413
|
+
strengths.append("High decision velocity")
|
|
414
|
+
else:
|
|
415
|
+
weaknesses.append("Low decision-making speed")
|
|
416
|
+
|
|
417
|
+
if approval_effectiveness >= 70:
|
|
418
|
+
strengths.append("High approval rate")
|
|
419
|
+
else:
|
|
420
|
+
weaknesses.append("Low approval rate - may indicate alignment issues")
|
|
421
|
+
|
|
422
|
+
if participation_rate >= 70:
|
|
423
|
+
strengths.append("Strong member participation")
|
|
424
|
+
else:
|
|
425
|
+
weaknesses.append("Low member participation")
|
|
426
|
+
|
|
427
|
+
metrics = {
|
|
428
|
+
"community_id": community_id,
|
|
429
|
+
"time_range_days": time_range_days,
|
|
430
|
+
"effectiveness_score": round(effectiveness_score, 2),
|
|
431
|
+
"effectiveness_level": effectiveness_level,
|
|
432
|
+
"component_scores": {
|
|
433
|
+
"decision_efficiency": round(decision_efficiency, 2),
|
|
434
|
+
"approval_effectiveness": round(approval_effectiveness, 2),
|
|
435
|
+
"participation_rate": round(participation_rate, 2),
|
|
436
|
+
},
|
|
437
|
+
"strengths": strengths,
|
|
438
|
+
"weaknesses": weaknesses,
|
|
439
|
+
"decision_summary": {
|
|
440
|
+
"velocity": decision_analytics.get("decision_velocity", 0),
|
|
441
|
+
"approval_rate": decision_analytics.get("approval_rate", 0),
|
|
442
|
+
"avg_time_hours": decision_analytics.get("average_decision_time_hours", 0),
|
|
443
|
+
},
|
|
444
|
+
"participation_summary": {
|
|
445
|
+
"active_members": participation_analytics.get("active_members", 0),
|
|
446
|
+
"total_members": participation_analytics.get("total_members", 0),
|
|
447
|
+
"avg_votes_per_member": participation_analytics.get("average_votes_per_member", 0),
|
|
448
|
+
},
|
|
449
|
+
"timestamp": datetime.utcnow().isoformat(),
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
return metrics
|
|
453
|
+
|
|
454
|
+
def get_comprehensive_report(
|
|
455
|
+
self, community_id: str, time_range_days: int = 30
|
|
456
|
+
) -> Dict[str, Any]:
|
|
457
|
+
"""
|
|
458
|
+
Get comprehensive analytics report for a community.
|
|
459
|
+
|
|
460
|
+
Args:
|
|
461
|
+
community_id: ID of the community
|
|
462
|
+
time_range_days: Time range for analytics in days
|
|
463
|
+
|
|
464
|
+
Returns:
|
|
465
|
+
Comprehensive analytics report
|
|
466
|
+
"""
|
|
467
|
+
report = {
|
|
468
|
+
"community_id": community_id,
|
|
469
|
+
"report_date": datetime.utcnow().isoformat(),
|
|
470
|
+
"time_range_days": time_range_days,
|
|
471
|
+
"decision_analytics": self.get_decision_analytics(community_id, time_range_days),
|
|
472
|
+
"participation_analytics": self.get_member_participation_analytics(
|
|
473
|
+
community_id, time_range_days
|
|
474
|
+
),
|
|
475
|
+
"health_metrics": self.get_community_health_metrics(community_id),
|
|
476
|
+
"collaboration_effectiveness": self.get_collaboration_effectiveness(
|
|
477
|
+
community_id, time_range_days
|
|
478
|
+
),
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
return report
|