use std::collections::HashSet;
use std::sync::{Arc, Mutex};
use std::collections::HashMap;
use tokio::sync::RwLock as AsyncRwLock;
use std::collections::{BTreeMap};
use std::sync::RwLock;
#[derive(Debug, Clone)]
pub struct Task {
pub id: String,
pub title: String,
pub description: String,
pub required_skills: Vec<String>,
pub estimated_hours: u32,
pub priority: String,
pub complexity: String,
}
#[derive(Debug, Clone)]
pub struct TeamMember {
pub id: String,
pub name: String,
pub skills: Vec<String>,
pub current_workload: u32, pub availability: u32, }
#[derive(Debug, Clone)]
pub struct TaskAssignment {
pub recommended_member_id: String,
pub confidence_score: f64,
pub reasoning: String,
pub alternative_candidates: Vec<String>,
}
#[derive(Debug, Clone)]
pub struct WorkloadBalanceReport {
pub balance_score: f64, pub suggestions: Vec<String>,
pub overloaded_members: Vec<String>,
pub underutilized_members: Vec<String>,
}
#[derive(Debug, Clone)]
pub struct CodeFile {
pub path: String,
pub owner_id: String,
pub expertise_score: f64,
pub last_modified: String,
}
#[derive(Debug, Clone)]
pub struct CodeOwner {
pub id: String,
pub name: String,
pub expertise_areas: Vec<String>,
pub ownership_percentage: f64,
}
#[derive(Debug, Clone)]
pub struct CodeOwnershipMap {
pub files: Vec<CodeFile>,
pub owners: Vec<CodeOwner>,
pub knowledge_gaps: Vec<String>,
}
#[derive(Debug, Clone)]
pub struct KnowledgeTransferSuggestion {
pub from_member_id: String,
pub to_member_id: String,
pub skill_area: String,
pub urgency: String,
pub suggested_method: String,
}
pub struct SkillAnalyzer {
skill_database: Arc<RwLock<HashMap<String, HashMap<String, f64>>>,
}
impl SkillAnalyzer {
pub fn new() -> Self {
Self {
skill_database: Arc::new(Mutex::new(HashMap::new()))
}
}
pub fn calculate_skill_match(&self, task_skills: &[String], member_skills: &[String]) -> f64 {
if task_skills.is_empty() {
return 1.0;
}
let mut match_count = 0;
for task_skill in task_skills {
if member_skills.contains(task_skill) {
match_count += 1;
}
}
match_count as f64 / task_skills.len() as f64
}
pub fn analyze_skill_gaps(&self, task_skills: &[String], member_skills: &[String]) -> Vec<String> {
let mut gaps = Vec::new();
for skill in task_skills {
if !member_skills.contains(skill) {
gaps.push(skill.clone());
}
}
gaps
}
}
pub struct WorkloadBalancer {
workload_history: Arc<RwLock<HashMap<String, Vec<u32>>>,
}
impl WorkloadBalancer {
pub fn new() -> Self {
Self {
workload_history: Arc::new(Mutex::new(HashMap::new()))
}
}
pub fn calculate_balance_score(&self, team: &[TeamMember]) -> f64 {
if team.is_empty() {
return 1.0;
}
let workloads: Vec<u32> = team.iter().map(|m| m.current_workload).collect();
let sum: u32 = workloads.iter().sum();
let avg: _ = sum as f64 / workloads.len() as f64;
let variance: _ = workloads.iter()
.map(|&w| {
let diff: _ = w as f64 - avg;
diff * diff
})
.sum::<f64>() / workloads.len() as f64;
let max_variance: _ = 2500.0; let normalized_variance: _ = (variance / max_variance).min(1.0);
1.0 - normalized_variance
}
pub fn identify_overloaded_members(&self, team: &[TeamMember]) -> Vec<String> {
team.iter()
.filter(|m| m.current_workload > 80)
.map(|m| m.id.clone())
.collect()
}
pub fn identify_underutilized_members(&self, team: &[TeamMember]) -> Vec<String> {
team.iter()
.filter(|m| m.current_workload < 40)
.map(|m| m.id.clone())
.collect()
}
}
pub struct KnowledgeTracker {
knowledge_graph: Arc<RwLock<HashMap<String, HashMap<String, u32>>>,
}
impl KnowledgeTracker {
pub fn new() -> Self {
Self {
knowledge_graph: Arc::new(Mutex::new(HashMap::new()))
}
}
pub async fn record_learning_activity(&self, member_id: &str, skill: &str, hours: u32) {
let mut graph = self.knowledge_graph.write().await;
graph
.entry(member_id.to_string())
.or_insert_with(HashMap::new)
.insert(skill.to_string(), hours);
}
pub async fn get_knowledge_graph(&self, member_id: &str) -> HashMap<String, u32> {
let graph: _ = self.knowledge_graph.read().await;
graph.get(member_id).cloned().unwrap_or_default()
}
pub async fn calculate_knowledge_overlap(&self, member1: &str, member2: &str) -> f64 {
let graph: _ = self.knowledge_graph.read().await;
let skills1: _ = graph.get(member1).cloned().unwrap_or_default();
let skills2: _ = graph.get(member2).cloned().unwrap_or_default();
if skills1.is_empty() || skills2.is_empty() {
return 0.0;
}
let common_skills: _ = skills1.keys()
.filter(|k| skills2.contains_key(*k))
.count();
let total_unique_skills: _ = skills1.keys()
.chain(skills2.keys())
.collect::<std::collections::HashSet<_>>()
.len();
if total_unique_skills == 0 {
return 0.0;
}
common_skills as f64 / total_unique_skills as f64
}
}
pub struct TeamCollaborationOptimizer {
pub skill_analyzer: Arc<SkillAnalyzer>,
pub workload_balancer: Arc<WorkloadBalancer>,
pub knowledge_tracker: Arc<KnowledgeTracker>,
}
impl TeamCollaborationOptimizer {
pub fn new() -> Self {
Self {
skill_analyzer: Arc::new(Mutex::new(SkillAnalyzer::new()))
workload_balancer: Arc::new(Mutex::new(WorkloadBalancer::new()))
knowledge_tracker: Arc::new(Mutex::new(KnowledgeTracker::new()))
}
}
pub async fn suggest_task_assignment(
&self,
task: &Task,
team_members: &[TeamMember],
) -> Result<TaskAssignment, String> {
if team_members.is_empty() {
return Err("No team members available".to_string());
}
let mut best_candidate = None;
let mut best_score = 0.0;
let mut scores = Vec::new();
for member in team_members {
let skill_score: _ = self.skill_analyzer.calculate_skill_match(
&task.required_skills,
&member.skills,
);
let workload_score: _ = (100 - member.current_workload) as f64 / 100.0;
let total_score: _ = skill_score * 0.6 + workload_score * 0.4;
scores.push((member.id.clone(), total_score));
if total_score > best_score {
best_score = total_score;
best_candidate = Some(member.id.clone());
}
}
let recommended_member_id: _ = best_candidate.ok_or("No suitable candidate found")?;
let reasoning: _ = format!(
"基于技能匹配({:.1}%)和工作负载({:.1}%)的综合评估",
best_score * 100.0,
best_score * 100.0
);
scores.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap());
let alternative_candidates: Vec<String> = scores
.iter()
.skip(1)
.take(2)
.map(|(id, _)| id.clone())
.collect();
Ok(TaskAssignment {
recommended_member_id,
confidence_score: best_score,
reasoning,
alternative_candidates,
})
}
pub async fn balance_team_workload(
&self,
team: &[TeamMember],
) -> Result<WorkloadBalanceReport, String> {
if team.is_empty() {
return Err("No team members provided".to_string());
}
let balance_score: _ = self.workload_balancer.calculate_balance_score(team);
let overloaded_members: _ = self.workload_balancer.identify_overloaded_members(team);
let underutilized_members: _ = self.workload_balancer.identify_underutilized_members(team);
let mut suggestions = Vec::new();
if !overloaded_members.is_empty() {
suggestions.push(format!(
"建议将 {} 的任务重新分配给其他团队成员",
overloaded_members.join(", "));
}
if !underutilized_members.is_empty() {
suggestions.push(format!(
"可以向 {} 分配更多任务以提高效率",
underutilized_members.join(", "));
}
if balance_score < 0.5 {
suggestions.push("团队工作负载严重不平衡,建议立即进行调整".to_string());
} else if balance_score < 0.8 {
suggestions.push("团队工作负载略有不平衡,可以适当调整".to_string());
} else {
suggestions.push("团队工作负载较为平衡".to_string());
}
Ok(WorkloadBalanceReport {
balance_score,
suggestions,
overloaded_members,
underutilized_members,
})
}
pub async fn analyze_code_ownership(
&self,
codebase: &str,
) -> Result<CodeOwnershipMap, String> {
let files: _ = vec![
CodeFile {
path: format!("{}/src/auth.rs", codebase),
owner_id: "DEV-001".to_string(),
expertise_score: 0.95,
last_modified: "2024-12-01".to_string(),
},
CodeFile {
path: format!("{}/src/api.rs", codebase),
owner_id: "DEV-002".to_string(),
expertise_score: 0.88,
last_modified: "2024-12-05".to_string(),
},
CodeFile {
path: format!("{}/src/db.rs", codebase),
owner_id: "DEV-001".to_string(),
expertise_score: 0.92,
last_modified: "2024-11-28".to_string(),
},
];
let owners: _ = vec![
CodeOwner {
id: "DEV-001".to_string(),
name: "Alice".to_string(),
expertise_areas: vec!["Rust".to_string(), "Security".to_string()],
ownership_percentage: 65.0,
},
CodeOwner {
id: "DEV-002".to_string(),
name: "Bob".to_string(),
expertise_areas: vec!["JavaScript".to_string(), "API".to_string()],
ownership_percentage: 35.0,
},
];
let knowledge_gaps: _ = vec![
"DevOps".to_string(),
"Testing".to_string(),
"Security".to_string(),
];
Ok(CodeOwnershipMap {
files,
owners,
knowledge_gaps,
})
}
pub async fn suggest_knowledge_transfer(
&self,
ownership_map: &CodeOwnershipMap,
) -> Result<Vec<KnowledgeTransferSuggestion>, String> {
let mut suggestions = Vec::new();
for gap in &ownership_map.knowledge_gaps {
suggestions.push(KnowledgeTransferSuggestion {
from_member_id: "DEV-001".to_string(),
to_member_id: "DEV-002".to_string(),
skill_area: gap.clone(),
urgency: "Medium".to_string(),
suggested_method: "Pair Programming".to_string(),
});
}
Ok(suggestions)
}
}
impl Default for TeamCollaborationOptimizer {
fn default() -> Self {
Self::new()
}
}
impl Default for SkillAnalyzer {
fn default() -> Self {
Self::new()
}
}
impl Default for WorkloadBalancer {
fn default() -> Self {
Self::new()
}
}
impl Default for KnowledgeTracker {
fn default() -> Self {
Self::new()
}
}