aiecs 1.1.0__py3-none-any.whl → 1.2.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.
Potentially problematic release.
This version of aiecs might be problematic. Click here for more details.
- aiecs/__init__.py +1 -1
- aiecs/aiecs_client.py +1 -1
- aiecs/config/config.py +38 -0
- aiecs/domain/__init__.py +95 -0
- aiecs/domain/community/__init__.py +159 -0
- aiecs/domain/community/agent_adapter.py +516 -0
- aiecs/domain/community/analytics.py +465 -0
- aiecs/domain/community/collaborative_workflow.py +99 -7
- aiecs/domain/community/communication_hub.py +649 -0
- aiecs/domain/community/community_builder.py +322 -0
- aiecs/domain/community/community_integration.py +365 -12
- aiecs/domain/community/community_manager.py +481 -5
- aiecs/domain/community/decision_engine.py +459 -13
- aiecs/domain/community/exceptions.py +238 -0
- aiecs/domain/community/models/__init__.py +36 -0
- aiecs/domain/community/resource_manager.py +1 -1
- aiecs/domain/community/shared_context_manager.py +621 -0
- aiecs/domain/context/context_engine.py +37 -33
- aiecs/infrastructure/monitoring/__init__.py +22 -0
- aiecs/infrastructure/monitoring/global_metrics_manager.py +207 -0
- aiecs/infrastructure/persistence/file_storage.py +41 -28
- aiecs/llm/__init__.py +44 -7
- aiecs/llm/callbacks/__init__.py +12 -0
- aiecs/llm/{custom_callbacks.py → callbacks/custom_callbacks.py} +1 -1
- aiecs/llm/client_factory.py +23 -6
- aiecs/llm/clients/__init__.py +35 -0
- aiecs/llm/{base_client.py → clients/base_client.py} +73 -1
- aiecs/llm/{googleai_client.py → clients/googleai_client.py} +19 -15
- aiecs/llm/{openai_client.py → clients/openai_client.py} +9 -14
- aiecs/llm/{vertex_client.py → clients/vertex_client.py} +15 -15
- aiecs/llm/{xai_client.py → clients/xai_client.py} +36 -50
- aiecs/llm/config/__init__.py +54 -0
- aiecs/llm/config/config_loader.py +275 -0
- aiecs/llm/config/config_validator.py +237 -0
- aiecs/llm/config/model_config.py +132 -0
- aiecs/llm/utils/__init__.py +11 -0
- aiecs/llm/utils/validate_config.py +91 -0
- aiecs/main.py +32 -2
- aiecs/scripts/aid/VERSION_MANAGEMENT.md +97 -0
- aiecs/scripts/aid/__init__.py +15 -0
- aiecs/scripts/aid/version_manager.py +224 -0
- aiecs/scripts/dependance_check/download_nlp_data.py +1 -0
- aiecs/tools/__init__.py +23 -23
- aiecs/tools/docs/__init__.py +5 -2
- aiecs/tools/docs/ai_document_orchestrator.py +39 -26
- aiecs/tools/docs/ai_document_writer_orchestrator.py +61 -38
- aiecs/tools/docs/content_insertion_tool.py +48 -28
- aiecs/tools/docs/document_creator_tool.py +47 -29
- aiecs/tools/docs/document_layout_tool.py +35 -20
- aiecs/tools/docs/document_parser_tool.py +56 -36
- aiecs/tools/docs/document_writer_tool.py +115 -62
- aiecs/tools/schema_generator.py +56 -56
- aiecs/tools/statistics/__init__.py +82 -0
- aiecs/tools/statistics/ai_data_analysis_orchestrator.py +581 -0
- aiecs/tools/statistics/ai_insight_generator_tool.py +473 -0
- aiecs/tools/statistics/ai_report_orchestrator_tool.py +629 -0
- aiecs/tools/statistics/data_loader_tool.py +518 -0
- aiecs/tools/statistics/data_profiler_tool.py +599 -0
- aiecs/tools/statistics/data_transformer_tool.py +531 -0
- aiecs/tools/statistics/data_visualizer_tool.py +460 -0
- aiecs/tools/statistics/model_trainer_tool.py +470 -0
- aiecs/tools/statistics/statistical_analyzer_tool.py +426 -0
- aiecs/tools/task_tools/chart_tool.py +2 -1
- aiecs/tools/task_tools/image_tool.py +43 -43
- aiecs/tools/task_tools/office_tool.py +39 -36
- aiecs/tools/task_tools/pandas_tool.py +37 -33
- aiecs/tools/task_tools/report_tool.py +67 -56
- aiecs/tools/task_tools/research_tool.py +32 -31
- aiecs/tools/task_tools/scraper_tool.py +53 -46
- aiecs/tools/task_tools/search_tool.py +1123 -0
- aiecs/tools/task_tools/stats_tool.py +20 -15
- aiecs/tools/tool_executor/__init__.py +2 -2
- aiecs/tools/tool_executor/tool_executor.py +3 -3
- {aiecs-1.1.0.dist-info → aiecs-1.2.1.dist-info}/METADATA +5 -1
- aiecs-1.2.1.dist-info/RECORD +144 -0
- {aiecs-1.1.0.dist-info → aiecs-1.2.1.dist-info}/entry_points.txt +1 -0
- aiecs/tools/task_tools/search_api.py +0 -7
- aiecs-1.1.0.dist-info/RECORD +0 -114
- {aiecs-1.1.0.dist-info → aiecs-1.2.1.dist-info}/WHEEL +0 -0
- {aiecs-1.1.0.dist-info → aiecs-1.2.1.dist-info}/licenses/LICENSE +0 -0
- {aiecs-1.1.0.dist-info → aiecs-1.2.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,465 @@
|
|
|
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, List, Any, Optional
|
|
11
|
+
from collections import defaultdict
|
|
12
|
+
|
|
13
|
+
from .models.community_models import (
|
|
14
|
+
AgentCommunity, CommunityMember, CommunityDecision, DecisionStatus
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class CommunityAnalytics:
|
|
21
|
+
"""
|
|
22
|
+
Analytics engine for tracking community health and effectiveness.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(self, community_manager=None):
|
|
26
|
+
"""
|
|
27
|
+
Initialize community analytics.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
community_manager: Reference to the community manager
|
|
31
|
+
"""
|
|
32
|
+
self.community_manager = community_manager
|
|
33
|
+
|
|
34
|
+
# Analytics caches
|
|
35
|
+
self._decision_patterns_cache: Dict[str, Any] = {}
|
|
36
|
+
self._participation_cache: Dict[str, Any] = {}
|
|
37
|
+
self._health_metrics_cache: Dict[str, Any] = {}
|
|
38
|
+
|
|
39
|
+
logger.info("Community analytics initialized")
|
|
40
|
+
|
|
41
|
+
def get_decision_analytics(
|
|
42
|
+
self,
|
|
43
|
+
community_id: str,
|
|
44
|
+
time_range_days: int = 30
|
|
45
|
+
) -> Dict[str, Any]:
|
|
46
|
+
"""
|
|
47
|
+
Get decision analytics for a community.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
community_id: ID of the community
|
|
51
|
+
time_range_days: Time range for analytics in days
|
|
52
|
+
|
|
53
|
+
Returns:
|
|
54
|
+
Decision analytics data
|
|
55
|
+
"""
|
|
56
|
+
if not self.community_manager:
|
|
57
|
+
return {}
|
|
58
|
+
|
|
59
|
+
community = self.community_manager.communities.get(community_id)
|
|
60
|
+
if not community:
|
|
61
|
+
return {}
|
|
62
|
+
|
|
63
|
+
cutoff_date = datetime.utcnow() - timedelta(days=time_range_days)
|
|
64
|
+
|
|
65
|
+
# Collect decisions within time range
|
|
66
|
+
decisions = []
|
|
67
|
+
for decision in self.community_manager.decisions.values():
|
|
68
|
+
if decision.created_at >= cutoff_date:
|
|
69
|
+
# Check if decision belongs to this community
|
|
70
|
+
if decision.proposer_id in community.members:
|
|
71
|
+
decisions.append(decision)
|
|
72
|
+
|
|
73
|
+
# Calculate decision metrics
|
|
74
|
+
total_decisions = len(decisions)
|
|
75
|
+
approved = sum(1 for d in decisions if d.status == DecisionStatus.APPROVED)
|
|
76
|
+
rejected = sum(1 for d in decisions if d.status == DecisionStatus.REJECTED)
|
|
77
|
+
pending = sum(1 for d in decisions if d.status in [DecisionStatus.PROPOSED, DecisionStatus.VOTING])
|
|
78
|
+
|
|
79
|
+
# Calculate average time to decision
|
|
80
|
+
decision_times = []
|
|
81
|
+
for decision in decisions:
|
|
82
|
+
if decision.status in [DecisionStatus.APPROVED, DecisionStatus.REJECTED]:
|
|
83
|
+
if decision.implemented_at or decision.created_at:
|
|
84
|
+
end_time = decision.implemented_at or datetime.utcnow()
|
|
85
|
+
duration = (end_time - decision.created_at).total_seconds() / 3600 # hours
|
|
86
|
+
decision_times.append(duration)
|
|
87
|
+
|
|
88
|
+
avg_decision_time = sum(decision_times) / len(decision_times) if decision_times else 0
|
|
89
|
+
|
|
90
|
+
# Decision types distribution
|
|
91
|
+
decision_types = defaultdict(int)
|
|
92
|
+
for decision in decisions:
|
|
93
|
+
decision_types[decision.decision_type] += 1
|
|
94
|
+
|
|
95
|
+
# Approval rate by type
|
|
96
|
+
approval_by_type = {}
|
|
97
|
+
for dtype in decision_types.keys():
|
|
98
|
+
type_decisions = [d for d in decisions if d.decision_type == dtype]
|
|
99
|
+
type_approved = sum(1 for d in type_decisions if d.status == DecisionStatus.APPROVED)
|
|
100
|
+
approval_by_type[dtype] = type_approved / len(type_decisions) if type_decisions else 0
|
|
101
|
+
|
|
102
|
+
analytics = {
|
|
103
|
+
"community_id": community_id,
|
|
104
|
+
"time_range_days": time_range_days,
|
|
105
|
+
"total_decisions": total_decisions,
|
|
106
|
+
"approved": approved,
|
|
107
|
+
"rejected": rejected,
|
|
108
|
+
"pending": pending,
|
|
109
|
+
"approval_rate": approved / total_decisions if total_decisions > 0 else 0,
|
|
110
|
+
"rejection_rate": rejected / total_decisions if total_decisions > 0 else 0,
|
|
111
|
+
"average_decision_time_hours": avg_decision_time,
|
|
112
|
+
"decision_types": dict(decision_types),
|
|
113
|
+
"approval_rate_by_type": approval_by_type,
|
|
114
|
+
"decision_velocity": total_decisions / time_range_days if time_range_days > 0 else 0
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return analytics
|
|
118
|
+
|
|
119
|
+
def get_member_participation_analytics(
|
|
120
|
+
self,
|
|
121
|
+
community_id: str,
|
|
122
|
+
time_range_days: int = 30
|
|
123
|
+
) -> Dict[str, Any]:
|
|
124
|
+
"""
|
|
125
|
+
Get member participation analytics.
|
|
126
|
+
|
|
127
|
+
Args:
|
|
128
|
+
community_id: ID of the community
|
|
129
|
+
time_range_days: Time range for analytics in days
|
|
130
|
+
|
|
131
|
+
Returns:
|
|
132
|
+
Participation analytics data
|
|
133
|
+
"""
|
|
134
|
+
if not self.community_manager:
|
|
135
|
+
return {}
|
|
136
|
+
|
|
137
|
+
community = self.community_manager.communities.get(community_id)
|
|
138
|
+
if not community:
|
|
139
|
+
return {}
|
|
140
|
+
|
|
141
|
+
cutoff_date = datetime.utcnow() - timedelta(days=time_range_days)
|
|
142
|
+
|
|
143
|
+
# Member participation metrics
|
|
144
|
+
member_metrics = {}
|
|
145
|
+
for member_id in community.members:
|
|
146
|
+
member = self.community_manager.members.get(member_id)
|
|
147
|
+
if not member:
|
|
148
|
+
continue
|
|
149
|
+
|
|
150
|
+
# Count votes
|
|
151
|
+
votes_cast = 0
|
|
152
|
+
proposals_made = 0
|
|
153
|
+
|
|
154
|
+
for decision in self.community_manager.decisions.values():
|
|
155
|
+
if decision.created_at >= cutoff_date:
|
|
156
|
+
if member_id in decision.votes_for or member_id in decision.votes_against or member_id in decision.abstentions:
|
|
157
|
+
votes_cast += 1
|
|
158
|
+
if decision.proposer_id == member_id:
|
|
159
|
+
proposals_made += 1
|
|
160
|
+
|
|
161
|
+
# Count resources contributed
|
|
162
|
+
resources_created = sum(
|
|
163
|
+
1 for resource in self.community_manager.resources.values()
|
|
164
|
+
if resource.owner_id == member_id and resource.created_at >= cutoff_date
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
member_metrics[member_id] = {
|
|
168
|
+
"agent_id": member.agent_id,
|
|
169
|
+
"community_role": member.community_role.value,
|
|
170
|
+
"votes_cast": votes_cast,
|
|
171
|
+
"proposals_made": proposals_made,
|
|
172
|
+
"resources_created": resources_created,
|
|
173
|
+
"contribution_score": member.contribution_score,
|
|
174
|
+
"reputation": member.reputation,
|
|
175
|
+
"is_active": member.is_active,
|
|
176
|
+
"participation_level": member.participation_level
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
# Calculate aggregate metrics
|
|
180
|
+
total_members = len(member_metrics)
|
|
181
|
+
active_members = sum(1 for m in member_metrics.values() if m["is_active"])
|
|
182
|
+
total_votes = sum(m["votes_cast"] for m in member_metrics.values())
|
|
183
|
+
total_proposals = sum(m["proposals_made"] for m in member_metrics.values())
|
|
184
|
+
total_resources = sum(m["resources_created"] for m in member_metrics.values())
|
|
185
|
+
|
|
186
|
+
# Identify top contributors
|
|
187
|
+
top_voters = sorted(
|
|
188
|
+
member_metrics.items(),
|
|
189
|
+
key=lambda x: x[1]["votes_cast"],
|
|
190
|
+
reverse=True
|
|
191
|
+
)[:5]
|
|
192
|
+
|
|
193
|
+
top_proposers = sorted(
|
|
194
|
+
member_metrics.items(),
|
|
195
|
+
key=lambda x: x[1]["proposals_made"],
|
|
196
|
+
reverse=True
|
|
197
|
+
)[:5]
|
|
198
|
+
|
|
199
|
+
top_contributors = sorted(
|
|
200
|
+
member_metrics.items(),
|
|
201
|
+
key=lambda x: x[1]["contribution_score"],
|
|
202
|
+
reverse=True
|
|
203
|
+
)[:5]
|
|
204
|
+
|
|
205
|
+
analytics = {
|
|
206
|
+
"community_id": community_id,
|
|
207
|
+
"time_range_days": time_range_days,
|
|
208
|
+
"total_members": total_members,
|
|
209
|
+
"active_members": active_members,
|
|
210
|
+
"activity_rate": active_members / total_members if total_members > 0 else 0,
|
|
211
|
+
"total_votes_cast": total_votes,
|
|
212
|
+
"total_proposals_made": total_proposals,
|
|
213
|
+
"total_resources_created": total_resources,
|
|
214
|
+
"average_votes_per_member": total_votes / total_members if total_members > 0 else 0,
|
|
215
|
+
"average_proposals_per_member": total_proposals / total_members if total_members > 0 else 0,
|
|
216
|
+
"member_metrics": member_metrics,
|
|
217
|
+
"top_voters": [{"member_id": mid, **metrics} for mid, metrics in top_voters],
|
|
218
|
+
"top_proposers": [{"member_id": mid, **metrics} for mid, metrics in top_proposers],
|
|
219
|
+
"top_contributors": [{"member_id": mid, **metrics} for mid, metrics in top_contributors]
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return analytics
|
|
223
|
+
|
|
224
|
+
def get_community_health_metrics(
|
|
225
|
+
self,
|
|
226
|
+
community_id: str
|
|
227
|
+
) -> Dict[str, Any]:
|
|
228
|
+
"""
|
|
229
|
+
Get comprehensive community health metrics.
|
|
230
|
+
|
|
231
|
+
Args:
|
|
232
|
+
community_id: ID of the community
|
|
233
|
+
|
|
234
|
+
Returns:
|
|
235
|
+
Health metrics data
|
|
236
|
+
"""
|
|
237
|
+
if not self.community_manager:
|
|
238
|
+
return {}
|
|
239
|
+
|
|
240
|
+
community = self.community_manager.communities.get(community_id)
|
|
241
|
+
if not community:
|
|
242
|
+
return {}
|
|
243
|
+
|
|
244
|
+
# Member health
|
|
245
|
+
total_members = len(community.members)
|
|
246
|
+
active_members = sum(
|
|
247
|
+
1 for mid in community.members
|
|
248
|
+
if self.community_manager.members.get(mid) and self.community_manager.members[mid].is_active
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
# Leadership health
|
|
252
|
+
has_leaders = len(community.leaders) > 0
|
|
253
|
+
has_coordinators = len(community.coordinators) > 0
|
|
254
|
+
leadership_ratio = (len(community.leaders) + len(community.coordinators)) / total_members if total_members > 0 else 0
|
|
255
|
+
|
|
256
|
+
# Activity health
|
|
257
|
+
recent_activity_days = 7
|
|
258
|
+
recent_cutoff = datetime.utcnow() - timedelta(days=recent_activity_days)
|
|
259
|
+
|
|
260
|
+
recent_decisions = sum(
|
|
261
|
+
1 for d in self.community_manager.decisions.values()
|
|
262
|
+
if d.created_at >= recent_cutoff and d.proposer_id in community.members
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
recent_resources = sum(
|
|
266
|
+
1 for rid in community.shared_resources
|
|
267
|
+
if self.community_manager.resources.get(rid) and
|
|
268
|
+
self.community_manager.resources[rid].created_at >= recent_cutoff
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
# Diversity metrics
|
|
272
|
+
role_distribution = defaultdict(int)
|
|
273
|
+
for member_id in community.members:
|
|
274
|
+
member = self.community_manager.members.get(member_id)
|
|
275
|
+
if member:
|
|
276
|
+
role_distribution[member.community_role.value] += 1
|
|
277
|
+
|
|
278
|
+
role_diversity = len(role_distribution) / 5 # Max 5 role types
|
|
279
|
+
|
|
280
|
+
# Collaboration score (from community model)
|
|
281
|
+
collaboration_score = community.collaboration_score
|
|
282
|
+
|
|
283
|
+
# Calculate overall health score (0-100)
|
|
284
|
+
health_components = {
|
|
285
|
+
"member_activity": (active_members / total_members * 100) if total_members > 0 else 0,
|
|
286
|
+
"leadership": (100 if has_leaders and has_coordinators else 50 if has_leaders or has_coordinators else 0),
|
|
287
|
+
"recent_activity": min((recent_decisions + recent_resources) * 10, 100),
|
|
288
|
+
"role_diversity": role_diversity * 100,
|
|
289
|
+
"collaboration": collaboration_score * 100
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
overall_health = sum(health_components.values()) / len(health_components)
|
|
293
|
+
|
|
294
|
+
# Determine health status
|
|
295
|
+
if overall_health >= 80:
|
|
296
|
+
health_status = "excellent"
|
|
297
|
+
elif overall_health >= 60:
|
|
298
|
+
health_status = "good"
|
|
299
|
+
elif overall_health >= 40:
|
|
300
|
+
health_status = "fair"
|
|
301
|
+
elif overall_health >= 20:
|
|
302
|
+
health_status = "poor"
|
|
303
|
+
else:
|
|
304
|
+
health_status = "critical"
|
|
305
|
+
|
|
306
|
+
# Recommendations
|
|
307
|
+
recommendations = []
|
|
308
|
+
if total_members == 0:
|
|
309
|
+
recommendations.append("Add members to the community to begin collaboration")
|
|
310
|
+
elif active_members / total_members < 0.5:
|
|
311
|
+
recommendations.append("Increase member engagement through targeted activities")
|
|
312
|
+
if not has_leaders:
|
|
313
|
+
recommendations.append("Assign community leaders for better coordination")
|
|
314
|
+
if recent_decisions + recent_resources < 3:
|
|
315
|
+
recommendations.append("Encourage more community activity and collaboration")
|
|
316
|
+
if role_diversity < 0.6:
|
|
317
|
+
recommendations.append("Improve role diversity by adding members with different roles")
|
|
318
|
+
|
|
319
|
+
metrics = {
|
|
320
|
+
"community_id": community_id,
|
|
321
|
+
"community_name": community.name,
|
|
322
|
+
"overall_health_score": round(overall_health, 2),
|
|
323
|
+
"health_status": health_status,
|
|
324
|
+
"health_components": health_components,
|
|
325
|
+
"member_statistics": {
|
|
326
|
+
"total": total_members,
|
|
327
|
+
"active": active_members,
|
|
328
|
+
"inactive": total_members - active_members,
|
|
329
|
+
"leaders": len(community.leaders),
|
|
330
|
+
"coordinators": len(community.coordinators)
|
|
331
|
+
},
|
|
332
|
+
"activity_statistics": {
|
|
333
|
+
"recent_decisions": recent_decisions,
|
|
334
|
+
"recent_resources": recent_resources,
|
|
335
|
+
"total_decisions": community.decision_count,
|
|
336
|
+
"total_resources": community.resource_count
|
|
337
|
+
},
|
|
338
|
+
"diversity_metrics": {
|
|
339
|
+
"role_distribution": dict(role_distribution),
|
|
340
|
+
"role_diversity_score": round(role_diversity, 2)
|
|
341
|
+
},
|
|
342
|
+
"collaboration_score": collaboration_score,
|
|
343
|
+
"recommendations": recommendations,
|
|
344
|
+
"timestamp": datetime.utcnow().isoformat()
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
return metrics
|
|
348
|
+
|
|
349
|
+
def get_collaboration_effectiveness(
|
|
350
|
+
self,
|
|
351
|
+
community_id: str,
|
|
352
|
+
time_range_days: int = 30
|
|
353
|
+
) -> Dict[str, Any]:
|
|
354
|
+
"""
|
|
355
|
+
Get collaboration effectiveness metrics.
|
|
356
|
+
|
|
357
|
+
Args:
|
|
358
|
+
community_id: ID of the community
|
|
359
|
+
time_range_days: Time range for analytics in days
|
|
360
|
+
|
|
361
|
+
Returns:
|
|
362
|
+
Collaboration effectiveness data
|
|
363
|
+
"""
|
|
364
|
+
if not self.community_manager:
|
|
365
|
+
return {}
|
|
366
|
+
|
|
367
|
+
# Get decision and participation analytics
|
|
368
|
+
decision_analytics = self.get_decision_analytics(community_id, time_range_days)
|
|
369
|
+
participation_analytics = self.get_member_participation_analytics(community_id, time_range_days)
|
|
370
|
+
|
|
371
|
+
# Calculate effectiveness metrics
|
|
372
|
+
decision_efficiency = decision_analytics.get("decision_velocity", 0) * 10
|
|
373
|
+
approval_effectiveness = decision_analytics.get("approval_rate", 0) * 100
|
|
374
|
+
participation_rate = participation_analytics.get("activity_rate", 0) * 100
|
|
375
|
+
|
|
376
|
+
# Combined effectiveness score
|
|
377
|
+
effectiveness_score = (
|
|
378
|
+
decision_efficiency * 0.3 +
|
|
379
|
+
approval_effectiveness * 0.4 +
|
|
380
|
+
participation_rate * 0.3
|
|
381
|
+
)
|
|
382
|
+
|
|
383
|
+
# Determine effectiveness level
|
|
384
|
+
if effectiveness_score >= 80:
|
|
385
|
+
effectiveness_level = "highly_effective"
|
|
386
|
+
elif effectiveness_score >= 60:
|
|
387
|
+
effectiveness_level = "effective"
|
|
388
|
+
elif effectiveness_score >= 40:
|
|
389
|
+
effectiveness_level = "moderately_effective"
|
|
390
|
+
else:
|
|
391
|
+
effectiveness_level = "needs_improvement"
|
|
392
|
+
|
|
393
|
+
# Identify strengths and weaknesses
|
|
394
|
+
strengths = []
|
|
395
|
+
weaknesses = []
|
|
396
|
+
|
|
397
|
+
if decision_efficiency >= 8:
|
|
398
|
+
strengths.append("High decision velocity")
|
|
399
|
+
else:
|
|
400
|
+
weaknesses.append("Low decision-making speed")
|
|
401
|
+
|
|
402
|
+
if approval_effectiveness >= 70:
|
|
403
|
+
strengths.append("High approval rate")
|
|
404
|
+
else:
|
|
405
|
+
weaknesses.append("Low approval rate - may indicate alignment issues")
|
|
406
|
+
|
|
407
|
+
if participation_rate >= 70:
|
|
408
|
+
strengths.append("Strong member participation")
|
|
409
|
+
else:
|
|
410
|
+
weaknesses.append("Low member participation")
|
|
411
|
+
|
|
412
|
+
metrics = {
|
|
413
|
+
"community_id": community_id,
|
|
414
|
+
"time_range_days": time_range_days,
|
|
415
|
+
"effectiveness_score": round(effectiveness_score, 2),
|
|
416
|
+
"effectiveness_level": effectiveness_level,
|
|
417
|
+
"component_scores": {
|
|
418
|
+
"decision_efficiency": round(decision_efficiency, 2),
|
|
419
|
+
"approval_effectiveness": round(approval_effectiveness, 2),
|
|
420
|
+
"participation_rate": round(participation_rate, 2)
|
|
421
|
+
},
|
|
422
|
+
"strengths": strengths,
|
|
423
|
+
"weaknesses": weaknesses,
|
|
424
|
+
"decision_summary": {
|
|
425
|
+
"velocity": decision_analytics.get("decision_velocity", 0),
|
|
426
|
+
"approval_rate": decision_analytics.get("approval_rate", 0),
|
|
427
|
+
"avg_time_hours": decision_analytics.get("average_decision_time_hours", 0)
|
|
428
|
+
},
|
|
429
|
+
"participation_summary": {
|
|
430
|
+
"active_members": participation_analytics.get("active_members", 0),
|
|
431
|
+
"total_members": participation_analytics.get("total_members", 0),
|
|
432
|
+
"avg_votes_per_member": participation_analytics.get("average_votes_per_member", 0)
|
|
433
|
+
},
|
|
434
|
+
"timestamp": datetime.utcnow().isoformat()
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
return metrics
|
|
438
|
+
|
|
439
|
+
def get_comprehensive_report(
|
|
440
|
+
self,
|
|
441
|
+
community_id: str,
|
|
442
|
+
time_range_days: int = 30
|
|
443
|
+
) -> Dict[str, Any]:
|
|
444
|
+
"""
|
|
445
|
+
Get comprehensive analytics report for a community.
|
|
446
|
+
|
|
447
|
+
Args:
|
|
448
|
+
community_id: ID of the community
|
|
449
|
+
time_range_days: Time range for analytics in days
|
|
450
|
+
|
|
451
|
+
Returns:
|
|
452
|
+
Comprehensive analytics report
|
|
453
|
+
"""
|
|
454
|
+
report = {
|
|
455
|
+
"community_id": community_id,
|
|
456
|
+
"report_date": datetime.utcnow().isoformat(),
|
|
457
|
+
"time_range_days": time_range_days,
|
|
458
|
+
"decision_analytics": self.get_decision_analytics(community_id, time_range_days),
|
|
459
|
+
"participation_analytics": self.get_member_participation_analytics(community_id, time_range_days),
|
|
460
|
+
"health_metrics": self.get_community_health_metrics(community_id),
|
|
461
|
+
"collaboration_effectiveness": self.get_collaboration_effectiveness(community_id, time_range_days)
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
return report
|
|
465
|
+
|
|
@@ -12,7 +12,7 @@ import uuid
|
|
|
12
12
|
import asyncio
|
|
13
13
|
|
|
14
14
|
from .models.community_models import CollaborationSession
|
|
15
|
-
from
|
|
15
|
+
from .exceptions import CommunityValidationError as TaskValidationError
|
|
16
16
|
|
|
17
17
|
logger = logging.getLogger(__name__)
|
|
18
18
|
|
|
@@ -317,18 +317,110 @@ class CollaborativeWorkflowEngine:
|
|
|
317
317
|
})
|
|
318
318
|
|
|
319
319
|
async def _peer_review_workflow(self, session: CollaborationSession) -> None:
|
|
320
|
-
"""
|
|
320
|
+
"""
|
|
321
|
+
Execute peer review workflow.
|
|
322
|
+
|
|
323
|
+
Phases:
|
|
324
|
+
1. Reviewer assignment
|
|
325
|
+
2. Individual review
|
|
326
|
+
3. Review collection and synthesis
|
|
327
|
+
4. Feedback integration
|
|
328
|
+
5. Final approval
|
|
329
|
+
"""
|
|
321
330
|
logger.info(f"Starting peer review workflow for session {session.session_id}")
|
|
322
331
|
|
|
323
|
-
#
|
|
324
|
-
|
|
332
|
+
# Phase 1: Reviewer Assignment
|
|
333
|
+
await self._execute_phase(session, "reviewer_assignment", {
|
|
334
|
+
"instructions": "Assign reviewers based on expertise and availability",
|
|
335
|
+
"time_limit_minutes": 5,
|
|
336
|
+
"min_reviewers": 2,
|
|
337
|
+
"max_reviewers": 5
|
|
338
|
+
})
|
|
339
|
+
|
|
340
|
+
# Phase 2: Individual Review
|
|
341
|
+
await self._execute_phase(session, "individual_review", {
|
|
342
|
+
"instructions": "Conduct independent review of the material",
|
|
343
|
+
"time_limit_minutes": 30,
|
|
344
|
+
"review_criteria": ["accuracy", "completeness", "clarity", "quality"],
|
|
345
|
+
"parallel_reviews": True
|
|
346
|
+
})
|
|
347
|
+
|
|
348
|
+
# Phase 3: Review Collection
|
|
349
|
+
await self._execute_phase(session, "review_collection", {
|
|
350
|
+
"instructions": "Collect and synthesize all review feedback",
|
|
351
|
+
"time_limit_minutes": 15,
|
|
352
|
+
"identify_conflicts": True,
|
|
353
|
+
"aggregate_scores": True
|
|
354
|
+
})
|
|
355
|
+
|
|
356
|
+
# Phase 4: Feedback Integration
|
|
357
|
+
await self._execute_phase(session, "feedback_integration", {
|
|
358
|
+
"instructions": "Integrate reviewer feedback into the material",
|
|
359
|
+
"time_limit_minutes": 20,
|
|
360
|
+
"collaborative_editing": True,
|
|
361
|
+
"track_changes": True
|
|
362
|
+
})
|
|
363
|
+
|
|
364
|
+
# Phase 5: Final Approval
|
|
365
|
+
await self._execute_phase(session, "final_approval", {
|
|
366
|
+
"instructions": "Reviewers provide final approval or request changes",
|
|
367
|
+
"time_limit_minutes": 10,
|
|
368
|
+
"require_consensus": True,
|
|
369
|
+
"approval_threshold": 0.8
|
|
370
|
+
})
|
|
325
371
|
|
|
326
372
|
async def _consensus_building_workflow(self, session: CollaborationSession) -> None:
|
|
327
|
-
"""
|
|
373
|
+
"""
|
|
374
|
+
Execute consensus building workflow.
|
|
375
|
+
|
|
376
|
+
Phases:
|
|
377
|
+
1. Issue presentation and clarification
|
|
378
|
+
2. Discussion round 1 - Position sharing
|
|
379
|
+
3. Common ground identification
|
|
380
|
+
4. Proposal refinement
|
|
381
|
+
5. Convergence check and agreement
|
|
382
|
+
"""
|
|
328
383
|
logger.info(f"Starting consensus building workflow for session {session.session_id}")
|
|
329
384
|
|
|
330
|
-
#
|
|
331
|
-
|
|
385
|
+
# Phase 1: Issue Presentation
|
|
386
|
+
await self._execute_phase(session, "issue_presentation", {
|
|
387
|
+
"instructions": "Present the issue clearly and allow clarification questions",
|
|
388
|
+
"time_limit_minutes": 15,
|
|
389
|
+
"clarification_enabled": True
|
|
390
|
+
})
|
|
391
|
+
|
|
392
|
+
# Phase 2: Position Sharing
|
|
393
|
+
await self._execute_phase(session, "position_sharing", {
|
|
394
|
+
"instructions": "Each member shares their position and rationale",
|
|
395
|
+
"time_limit_minutes": 20,
|
|
396
|
+
"equal_participation": True,
|
|
397
|
+
"capture_positions": True
|
|
398
|
+
})
|
|
399
|
+
|
|
400
|
+
# Phase 3: Common Ground Identification
|
|
401
|
+
await self._execute_phase(session, "common_ground_identification", {
|
|
402
|
+
"instructions": "Identify areas of agreement and shared values",
|
|
403
|
+
"time_limit_minutes": 15,
|
|
404
|
+
"find_overlaps": True,
|
|
405
|
+
"identify_blockers": True
|
|
406
|
+
})
|
|
407
|
+
|
|
408
|
+
# Phase 4: Proposal Refinement
|
|
409
|
+
await self._execute_phase(session, "proposal_refinement", {
|
|
410
|
+
"instructions": "Refine proposals to address concerns and maximize agreement",
|
|
411
|
+
"time_limit_minutes": 25,
|
|
412
|
+
"iterative_refinement": True,
|
|
413
|
+
"test_proposals": True
|
|
414
|
+
})
|
|
415
|
+
|
|
416
|
+
# Phase 5: Convergence Check
|
|
417
|
+
await self._execute_phase(session, "convergence_check", {
|
|
418
|
+
"instructions": "Check for consensus and finalize agreement",
|
|
419
|
+
"time_limit_minutes": 15,
|
|
420
|
+
"consensus_threshold": 0.9,
|
|
421
|
+
"allow_dissent": True,
|
|
422
|
+
"document_agreement": True
|
|
423
|
+
})
|
|
332
424
|
|
|
333
425
|
async def _execute_phase(
|
|
334
426
|
self,
|