export interface PredefinedCategory { name: string; color: string; keywords: string[]; icon: string; } export const PREDEFINED_CATEGORIES: PredefinedCategory[] = [ { name: 'Dev', color: '#3b82f6', // Blue icon: '💻', keywords: [ 'code', 'coding', 'development', 'develop', 'dev', 'programming', 'program', 'bug', 'fix', 'debug', 'feature', 'implement', 'refactor', 'review', 'api', 'database', 'db', 'frontend', 'backend', 'ui', 'ux', 'component', 'service', 'function', 'method', 'class', 'git', 'commit', 'merge', 'pull request', 'pr', 'deploy', 'deployment', 'test', 'testing', 'unit test', 'integration' ] }, { name: 'Meeting', color: '#8b5cf6', // Purple icon: '🤝', keywords: [ 'meeting', 'réunion', 'call', 'standup', 'daily', 'retrospective', 'retro', 'planning', 'demo', 'presentation', 'sync', 'catch up', 'catchup', 'interview', 'discussion', 'brainstorm', 'workshop', 'session', 'one on one', '1on1', 'review meeting', 'sprint planning' ] }, { name: 'Admin', color: '#6b7280', // Gray icon: '📋', keywords: [ 'admin', 'administration', 'paperwork', 'documentation', 'doc', 'docs', 'report', 'reporting', 'timesheet', 'expense', 'invoice', 'email', 'mail', 'communication', 'update', 'status', 'config', 'configuration', 'setup', 'installation', 'maintenance', 'backup', 'security', 'permission', 'user management' ] }, { name: 'Learning', color: '#10b981', // Green icon: '📚', keywords: [ 'learning', 'learn', 'study', 'training', 'course', 'tutorial', 'research', 'reading', 'documentation', 'knowledge', 'skill', 'certification', 'workshop', 'seminar', 'conference', 'practice', 'exercise', 'experiment', 'exploration', 'investigate' ] } ]; export class TaskCategorizationService { /** * Suggère une catégorie basée sur le titre et la description d'une tâche */ static suggestCategory(title: string, description?: string): PredefinedCategory | null { const text = `${title} ${description || ''}`.toLowerCase(); // Compte les matches pour chaque catégorie const categoryScores = PREDEFINED_CATEGORIES.map(category => { const matches = category.keywords.filter(keyword => text.includes(keyword.toLowerCase()) ).length; return { category, score: matches }; }); // Trouve la meilleure catégorie const bestMatch = categoryScores.reduce((best, current) => current.score > best.score ? current : best ); // Retourne la catégorie seulement s'il y a au moins un match return bestMatch.score > 0 ? bestMatch.category : null; } /** * Suggère plusieurs catégories avec leur score de confiance */ static suggestCategoriesWithScore(title: string, description?: string): Array<{ category: PredefinedCategory; score: number; confidence: number; }> { const text = `${title} ${description || ''}`.toLowerCase(); const categoryScores = PREDEFINED_CATEGORIES.map(category => { const matches = category.keywords.filter(keyword => text.includes(keyword.toLowerCase()) ); const score = matches.length; const confidence = Math.min((score / 3) * 100, 100); // Max 100% de confiance avec 3+ mots-clés return { category, score, confidence }; }); return categoryScores .filter(item => item.score > 0) .sort((a, b) => b.score - a.score); } /** * Analyse les activités et retourne la répartition par catégorie */ static analyzeActivitiesByCategory(activities: Array<{ title: string; description?: string }>): { [categoryName: string]: { count: number; percentage: number; color: string; icon: string; } } { const categoryCounts: { [key: string]: number } = {}; const uncategorized = { count: 0 }; // Initialiser les compteurs PREDEFINED_CATEGORIES.forEach(cat => { categoryCounts[cat.name] = 0; }); // Analyser chaque activité activities.forEach(activity => { const suggestedCategory = this.suggestCategory(activity.title, activity.description); if (suggestedCategory) { categoryCounts[suggestedCategory.name]++; } else { uncategorized.count++; } }); const total = activities.length; const result: { [categoryName: string]: { count: number; percentage: number; color: string; icon: string } } = {}; // Ajouter les catégories prédéfinies PREDEFINED_CATEGORIES.forEach(category => { const count = categoryCounts[category.name]; result[category.name] = { count, percentage: total > 0 ? (count / total) * 100 : 0, color: category.color, icon: category.icon }; }); // Ajouter "Autre" si nécessaire if (uncategorized.count > 0) { result['Autre'] = { count: uncategorized.count, percentage: total > 0 ? (uncategorized.count / total) * 100 : 0, color: '#d1d5db', icon: '❓' }; } return result; } /** * Retourne les tags suggérés pour une tâche */ static getSuggestedTags(title: string, description?: string): string[] { const suggestions = this.suggestCategoriesWithScore(title, description); return suggestions .filter(s => s.confidence >= 30) // Seulement les suggestions avec 30%+ de confiance .slice(0, 2) // Maximum 2 suggestions .map(s => s.category.name); } }