Skip to content

Commit 8ac722e

Browse files
Phase 8 Batch 5: Team Collaboration AI (450 lines, 12 endpoints, Feature #16)
1 parent 5701e44 commit 8ac722e

3 files changed

Lines changed: 536 additions & 0 deletions

File tree

app/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ def _register_blueprints(app):
228228
from app.routes.face_recognition_routes import face_bp
229229
from app.routes.compliance_routes import compliance_bp
230230
from app.routes.knowledge_base_routes import kb_bp
231+
from app.routes.team_collaboration_routes import team_bp
231232
from app.admin_secure.routes import create_secure_admin_blueprint
232233
import secrets
233234

@@ -246,6 +247,7 @@ def _register_blueprints(app):
246247
app.register_blueprint(face_bp)
247248
app.register_blueprint(compliance_bp)
248249
app.register_blueprint(kb_bp)
250+
app.register_blueprint(team_bp)
249251
app.register_blueprint(phase6_bp)
250252
app.register_blueprint(projects_bp, url_prefix='/project')
251253

app/ml/team_collaboration.py

Lines changed: 315 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,315 @@
1+
# app/ml/team_collaboration.py
2+
"""
3+
Team Collaboration AI System
4+
Real-time collaboration, smart suggestions, activity tracking, and team insights.
5+
"""
6+
7+
from dataclasses import dataclass, field
8+
from datetime import datetime, timedelta
9+
from typing import Dict, List, Optional, Set
10+
from enum import Enum
11+
import uuid
12+
13+
14+
class CollaborationActivityType(Enum):
15+
"""Types of collaboration activities."""
16+
MESSAGE = "message"
17+
MENTION = "mention"
18+
EDIT = "edit"
19+
COMMENT = "comment"
20+
APPROVAL = "approval"
21+
ASSIGNMENT = "assignment"
22+
COMPLETION = "completion"
23+
24+
25+
class SuggestionType(Enum):
26+
"""Smart suggestion types."""
27+
ASSIGNMENT = "assignment" # Suggest who should do task
28+
TIMING = "timing" # Suggest best time for meeting
29+
EXPERTISE = "expertise" # Suggest expert for question
30+
COLLABORATION = "collaboration" # Suggest who should collaborate
31+
AUTOMATION = "automation" # Suggest task automation
32+
33+
34+
@dataclass
35+
class TeamMember:
36+
"""Team member profile."""
37+
member_id: str = field(default_factory=lambda: str(uuid.uuid4()))
38+
name: str = ""
39+
email: str = ""
40+
role: str = ""
41+
skills: List[str] = field(default_factory=list)
42+
availability: Dict = field(default_factory=dict) # day -> hours
43+
activity_level: float = 0.0 # 0-1 scale
44+
last_active: datetime = field(default_factory=datetime.utcnow)
45+
46+
def to_dict(self) -> Dict:
47+
return {
48+
'member_id': self.member_id,
49+
'name': self.name,
50+
'role': self.role,
51+
'skills': self.skills,
52+
'activity_level': self.activity_level,
53+
'last_active': self.last_active.isoformat()
54+
}
55+
56+
57+
@dataclass
58+
class CollaborationActivity:
59+
"""Collaboration activity record."""
60+
activity_id: str = field(default_factory=lambda: str(uuid.uuid4()))
61+
member_id: str = ""
62+
activity_type: CollaborationActivityType = CollaborationActivityType.MESSAGE
63+
resource_id: str = ""
64+
resource_type: str = "" # task, document, project
65+
timestamp: datetime = field(default_factory=datetime.utcnow)
66+
details: Dict = field(default_factory=dict)
67+
68+
def to_dict(self) -> Dict:
69+
return {
70+
'activity_id': self.activity_id,
71+
'member_id': self.member_id,
72+
'activity_type': self.activity_type.value,
73+
'resource_type': self.resource_type,
74+
'timestamp': self.timestamp.isoformat()
75+
}
76+
77+
78+
@dataclass
79+
class SmartSuggestion:
80+
"""AI-generated smart suggestion."""
81+
suggestion_id: str = field(default_factory=lambda: str(uuid.uuid4()))
82+
suggestion_type: SuggestionType = SuggestionType.ASSIGNMENT
83+
context: str = ""
84+
suggested_members: List[str] = field(default_factory=list)
85+
confidence: float = 0.0
86+
rationale: str = ""
87+
created_at: datetime = field(default_factory=datetime.utcnow)
88+
accepted: bool = False
89+
90+
def to_dict(self) -> Dict:
91+
return {
92+
'suggestion_id': self.suggestion_id,
93+
'type': self.suggestion_type.value,
94+
'suggested_members': self.suggested_members,
95+
'confidence': round(self.confidence, 2),
96+
'rationale': self.rationale,
97+
'accepted': self.accepted
98+
}
99+
100+
101+
class TeamCollaborationAI:
102+
"""
103+
AI-powered team collaboration system with real-time insights.
104+
"""
105+
106+
def __init__(self):
107+
"""Initialize team collaboration system."""
108+
self.team_members: Dict[str, TeamMember] = {}
109+
self.activities: List[CollaborationActivity] = []
110+
self.suggestions: Dict[str, SmartSuggestion] = {}
111+
self.team_metrics = {
112+
'total_activities': 0,
113+
'collaboration_score': 0.0,
114+
'response_time_avg': 0,
115+
'productivity_index': 0.0
116+
}
117+
118+
def add_team_member(self, name: str, email: str, role: str,
119+
skills: List[str] = None) -> TeamMember:
120+
"""Add team member."""
121+
member = TeamMember(
122+
name=name,
123+
email=email,
124+
role=role,
125+
skills=skills or []
126+
)
127+
128+
self.team_members[member.member_id] = member
129+
return member
130+
131+
def log_activity(self, member_id: str, activity_type: CollaborationActivityType,
132+
resource_id: str, resource_type: str,
133+
details: Dict = None) -> CollaborationActivity:
134+
"""Log collaboration activity."""
135+
activity = CollaborationActivity(
136+
member_id=member_id,
137+
activity_type=activity_type,
138+
resource_id=resource_id,
139+
resource_type=resource_type,
140+
details=details or {}
141+
)
142+
143+
self.activities.append(activity)
144+
self.team_metrics['total_activities'] += 1
145+
146+
# Update member's activity level
147+
if member_id in self.team_members:
148+
member = self.team_members[member_id]
149+
member.last_active = datetime.utcnow()
150+
member.activity_level = min(1.0, member.activity_level + 0.05)
151+
152+
return activity
153+
154+
def suggest_team_member_for_task(self, task_description: str,
155+
required_skills: List[str]) -> SmartSuggestion:
156+
"""AI suggestion for who should be assigned to task."""
157+
# Find members with matching skills
158+
candidates = []
159+
for member in self.team_members.values():
160+
skill_match = sum(1 for skill in required_skills if skill in member.skills)
161+
if skill_match > 0:
162+
candidates.append((member, skill_match))
163+
164+
# Sort by skill match and activity level
165+
candidates.sort(key=lambda x: (x[1], x[0].activity_level), reverse=True)
166+
167+
suggested_members = [c[0].member_id for c in candidates[:3]]
168+
confidence = min(1.0, len(candidates) / max(len(required_skills), 1))
169+
170+
suggestion = SmartSuggestion(
171+
suggestion_type=SuggestionType.ASSIGNMENT,
172+
context=task_description,
173+
suggested_members=suggested_members,
174+
confidence=confidence,
175+
rationale=f"Based on skill match and current activity level"
176+
)
177+
178+
self.suggestions[suggestion.suggestion_id] = suggestion
179+
return suggestion
180+
181+
def suggest_meeting_time(self, member_ids: List[str],
182+
duration_minutes: int = 60) -> SmartSuggestion:
183+
"""AI suggestion for best meeting time."""
184+
# Find common available slots
185+
available_slots = {}
186+
187+
for hour in range(9, 18): # 9am to 6pm
188+
day_key = 'all_days'
189+
availability = sum(
190+
1 for mid in member_ids
191+
if mid in self.team_members and hour in self.team_members[mid].availability.get(day_key, [])
192+
)
193+
194+
if availability == len(member_ids):
195+
available_slots[hour] = availability
196+
197+
best_slot = max(available_slots.items(), key=lambda x: x[1])[0] if available_slots else 10
198+
199+
suggestion = SmartSuggestion(
200+
suggestion_type=SuggestionType.TIMING,
201+
context=f"Meeting for {len(member_ids)} members ({duration_minutes} min)",
202+
suggested_members=member_ids,
203+
confidence=0.85,
204+
rationale=f"Suggested time: {best_slot}:00 - all participants available"
205+
)
206+
207+
self.suggestions[suggestion.suggestion_id] = suggestion
208+
return suggestion
209+
210+
def suggest_expert(self, topic: str, member_ids: List[str] = None) -> SmartSuggestion:
211+
"""AI suggestion for expert on topic."""
212+
if not member_ids:
213+
member_ids = list(self.team_members.keys())
214+
215+
topic_keywords = topic.lower().split()
216+
217+
# Find expert by skill match
218+
candidates = []
219+
for mid in member_ids:
220+
if mid not in self.team_members:
221+
continue
222+
223+
member = self.team_members[mid]
224+
skill_match = sum(1 for keyword in topic_keywords if keyword in member.skills)
225+
226+
if skill_match > 0:
227+
candidates.append((mid, skill_match))
228+
229+
candidates.sort(key=lambda x: x[1], reverse=True)
230+
suggested_members = [c[0] for c in candidates[:2]]
231+
confidence = min(1.0, (candidates[0][1] / len(topic_keywords)) if candidates else 0)
232+
233+
suggestion = SmartSuggestion(
234+
suggestion_type=SuggestionType.EXPERTISE,
235+
context=f"Expert needed for: {topic}",
236+
suggested_members=suggested_members,
237+
confidence=confidence,
238+
rationale=f"Member(s) with relevant skills in {topic}"
239+
)
240+
241+
self.suggestions[suggestion.suggestion_id] = suggestion
242+
return suggestion
243+
244+
def get_collaboration_insights(self, member_id: str = None) -> Dict:
245+
"""Get collaboration insights."""
246+
if member_id and member_id in self.team_members:
247+
# Individual insights
248+
member = self.team_members[member_id]
249+
member_activities = [a for a in self.activities if a.member_id == member_id]
250+
251+
activity_by_type = {}
252+
for activity in member_activities:
253+
atype = activity.activity_type.value
254+
activity_by_type[atype] = activity_by_type.get(atype, 0) + 1
255+
256+
return {
257+
'member_id': member_id,
258+
'name': member.name,
259+
'activity_count': len(member_activities),
260+
'activity_by_type': activity_by_type,
261+
'activity_level': member.activity_level,
262+
'last_active': member.last_active.isoformat()
263+
}
264+
else:
265+
# Team insights
266+
activities_by_type = {}
267+
for activity in self.activities:
268+
atype = activity.activity_type.value
269+
activities_by_type[atype] = activities_by_type.get(atype, 0) + 1
270+
271+
# Calculate collaboration score
272+
team_members_active = sum(1 for m in self.team_members.values() if m.activity_level > 0.3)
273+
collaboration_score = (team_members_active / max(len(self.team_members), 1)) * 100
274+
275+
return {
276+
'total_members': len(self.team_members),
277+
'total_activities': self.team_metrics['total_activities'],
278+
'activities_by_type': activities_by_type,
279+
'active_members': team_members_active,
280+
'collaboration_score': round(collaboration_score, 1),
281+
'recent_activities': [a.to_dict() for a in self.activities[-10:]]
282+
}
283+
284+
def get_team_stats(self) -> Dict:
285+
"""Get team statistics."""
286+
return {
287+
'total_members': len(self.team_members),
288+
'total_activities': self.team_metrics['total_activities'],
289+
'total_suggestions': len(self.suggestions),
290+
'accepted_suggestions': sum(1 for s in self.suggestions.values() if s.accepted),
291+
'team_roles': list(set(m.role for m in self.team_members.values())),
292+
'average_activity_level': round(
293+
sum(m.activity_level for m in self.team_members.values()) / max(len(self.team_members), 1), 2
294+
)
295+
}
296+
297+
def accept_suggestion(self, suggestion_id: str) -> bool:
298+
"""Mark suggestion as accepted."""
299+
if suggestion_id in self.suggestions:
300+
self.suggestions[suggestion_id].accepted = True
301+
return True
302+
return False
303+
304+
def get_member_activity_timeline(self, member_id: str,
305+
days: int = 7) -> List[Dict]:
306+
"""Get member activity timeline."""
307+
cutoff_date = datetime.utcnow() - timedelta(days=days)
308+
activities = [a for a in self.activities
309+
if a.member_id == member_id and a.timestamp > cutoff_date]
310+
311+
return [a.to_dict() for a in activities]
312+
313+
314+
# Global team collaboration AI instance
315+
team_collab = TeamCollaborationAI()

0 commit comments

Comments
 (0)