package skills import ( "sort" "strings" ) // Match retorna las skills mas relevantes para una query dada. // Implementacion inicial: keyword matching simple contra name + description. // La query y las skills son procesadas en lowercase para matching case-insensitive. // // El scoring es basico: // - Match exacto en name: 1.0 // - Match parcial en name: 0.8 // - Match en description: 0.6 * (palabras coincidentes / palabras totales) // - Sin match: 0.0 // // Retorna las skills ordenadas por confidence descendente. func Match(query string, skills []SkillMeta) []SkillMatch { query = strings.ToLower(strings.TrimSpace(query)) if query == "" { return nil } queryWords := strings.Fields(query) var matches []SkillMatch for _, skill := range skills { confidence := scoreSkill(queryWords, skill) if confidence > 0 { matches = append(matches, SkillMatch{ Skill: skill, Confidence: confidence, }) } } sort.Sort(ByConfidence(matches)) return matches } // scoreSkill calcula el score de relevancia de una skill para las palabras de query. func scoreSkill(queryWords []string, skill SkillMeta) float64 { nameLower := strings.ToLower(skill.Name) descLower := strings.ToLower(skill.Description) // Match exacto en name queryStr := strings.Join(queryWords, " ") if nameLower == queryStr { return 1.0 } // Match parcial en name (todas las palabras de query aparecen en name) nameMatches := 0 for _, word := range queryWords { if strings.Contains(nameLower, word) { nameMatches++ } } if nameMatches == len(queryWords) { return 0.8 } // Match en description (contar palabras coincidentes) descWords := strings.Fields(descLower) descMatches := 0 for _, qword := range queryWords { for _, dword := range descWords { if strings.Contains(dword, qword) || strings.Contains(qword, dword) { descMatches++ break } } } if descMatches > 0 { ratio := float64(descMatches) / float64(len(queryWords)) return 0.6 * ratio } return 0.0 } // FilterByCategory retorna solo las skills que pertenecen a las categorias especificadas. // Si categories esta vacio, retorna todas las skills sin filtrar. func FilterByCategory(skills []SkillMeta, categories []string) []SkillMeta { if len(categories) == 0 { return skills } catSet := make(map[string]bool) for _, cat := range categories { catSet[strings.ToLower(cat)] = true } var filtered []SkillMeta for _, skill := range skills { if catSet[strings.ToLower(skill.Category)] { filtered = append(filtered, skill) } } return filtered }