|
- using ToolsServices;
- using Services.ReActAgent;
- using System.Collections.ObjectModel;
- using System.Text;
- using System.Text.Json;
- using System.Text.Json.Serialization;
-
- namespace Services
- {
- public static class RechercheCVService
- {
- #region Variables
- private static readonly string NomFichierRechercheCV = FichiersInternesService.ListeRechercheCV;// "listeRechercheCV.json";
- private static readonly string NomFichierParametres = FichiersInternesService.ParamsRechercheCV;
-
- #endregion
-
- #region Méthodes publiques
- public static (string, string) LoadParametres()
- {
- LoggerService.LogInfo("RechercheCVService.LoadParametres");
- //ParametresOllamaService SelectedItem = new();
-
- try
- {
- string FicheMission="";
- string PathCV="";
- if (File.Exists(NomFichierParametres))
- {
-
- string[] lignes = File.ReadAllLines(NomFichierParametres);
-
- if (lignes.Length > 0)
- FicheMission = lignes[0];
-
- if (lignes.Length > 1)
- PathCV = lignes[1];
-
- }
- return (FicheMission, PathCV);
-
- }
- catch
- {
- LoggerService.LogError($"Erreur lors du chargement des paramètres depuis {NomFichierParametres}");
- return ("","");
- }
- }
-
- public static bool SaveParametres(string FicheMission, string PathCV)
- {
- LoggerService.LogInfo("RechercheCVService.SaveParametres");
- try
- {
- StringBuilder sb = new();
- sb.AppendLine(FicheMission);
- sb.AppendLine(PathCV);
-
- File.WriteAllText(NomFichierParametres, sb.ToString());
-
- return true;
- }
- catch
- {
- LoggerService.LogError($"Erreur lors de la sauvegarde des paramètres dans {NomFichierParametres}");
- return false;
- }
-
- }
-
- public static async Task<List<ReponseRechercheCV>?> RechercherCV(string ficheMission, string dossierCV, bool isGenererXML)
- {
- LoggerService.LogInfo("RechercheCVService.RechercheCV");
-
- var reActRagAgent = new ReActAgent.ReActAgent();
- var modeleIA = ReActAgent.ReActAgent.GetModeleIA(ModelsUseCases.TypeUseCase.AnalyseCVMission);
-
- LoggerService.LogInfo($"Analyse des CV");
- LoggerService.LogInfo($"Fiche mission : {ficheMission}");
- LoggerService.LogInfo($"Dossier CV : {dossierCV}");
- LoggerService.LogInfo($"Extraire les CV en XML : {isGenererXML}");
- LoggerService.LogInfo($"Modèle utilisé : {modeleIA}");
-
- if (!Directory.Exists(dossierCV))
- {
- LoggerService.LogWarning($"Le dossier {dossierCV} n'existe pas.");
- return null;
- }
-
- if (!File.Exists(ficheMission))
- {
- LoggerService.LogWarning($"Le fichier {ficheMission} n'existe pas.");
- return null;
- }
-
- var fichiers = Directory
- .EnumerateFiles(dossierCV, "*.*", SearchOption.AllDirectories)
- .Where(f => f.EndsWith(".pdf", StringComparison.OrdinalIgnoreCase)
- || f.EndsWith(".docx", StringComparison.OrdinalIgnoreCase)
- || f.EndsWith(".xlsx", StringComparison.OrdinalIgnoreCase))
- .ToArray();
-
- if (fichiers.Length == 0)
- {
- LoggerService.LogWarning($"Aucun fichier trouvé dans le dossier spécifié : {dossierCV}");
- return null;
- }
- string messagePromptInjection1 = "";
- bool isPromptInjection = false;
-
- var ficheMissionText = reActRagAgent.CleanUserInput(FilesService.ExtractText(ficheMission), out isPromptInjection);
- if(isPromptInjection)
- {
- var msg = "Attention, le texte de la fiche de mission contient des éléments suspects";
- messagePromptInjection1 = $"{msg}.\n";
- LoggerService.LogWarning(msg);
- }
- List<ReponseRechercheCV> retours = new();
- foreach (var fichier in fichiers)
- {
- var bIngest = await RAGService.IngestDocument(Domain.CV, true, false, FilesService.ExtractText(fichier), fichier);
-
-
- }
-
- foreach (var fichier in fichiers)
- {
-
- try
- {
- #region Analyse du CV
- ReponseRechercheCV retour = new();
- string messagePromptInjection2 = "";
- var texteCV = reActRagAgent.CleanUserInput(FilesService.ExtractText(fichier), out isPromptInjection);
-
- if(isPromptInjection)
- {
- var msg = "Attention, le texte de la fiche de mission contient des éléments suspects";
- messagePromptInjection2 = $"{msg}.\n";
- retour.PresenceSuspecte = true;
- LoggerService.LogWarning($"{msg}: {fichier}");
- }
- /*
- var prompt = $@"
- Tu es un expert en recrutement. Ton rôle est d'évaluer la compatibilité entre une offre d'emploi et un CV.
-
- Analyse comparative :
-
- 1. **Points forts** : liste les éléments du CV qui correspondent bien aux exigences de l'offre (compétences, expériences, formations, etc.).
-
- 2. **Points manquants ou faibles** : identifie les éléments de l'offre qui sont absents ou peu développés dans le CV.
-
- 3. **Note de compatibilité** : donne une note globale de correspondance entre le CV et l'offre, sur 10, avec une explication.
-
- Voici les documents à comparer :
-
- ---
- **Offre d’emploi** :
- {ficheMissionText}
-
- ---
- **CV du candidat** :
- {texteCV}
-
- ---
- Réponds en suivant la structure suivante :
-
- **Points forts :**
- - …
-
- **Points manquants ou faibles :**
- - …
-
- **Note de compatibilité (sur 10) :**
- X/10 – Explication : …
-
- ";
- */
- var prompt = PromptService.GetPrompt(PromptService.ePrompt.RechercheCVService_RechercheCV_Analyse, ficheMissionText, texteCV);
-
- LoggerService.LogInfo($"Analyse du CV : {fichier}");
- var (reponse,m1) = await reActRagAgent.AppelerLLMAsync(ModelsUseCases.TypeUseCase.AnalyseCVMission, true, prompt,"Analyse de CV");
- var reponseComplete = $"Pour le CV {fichier} :\n{reponse}\n";
- //var reponseClean = reponse.Replace("\\n", "\n").Replace("\\r", "\r");
- var reponseCompleteClean = reponseComplete.Replace("\\n", "\n").Replace("\\r", "\r");
-
- retour.FichierCV = fichier;
- retour.Avis = messagePromptInjection1 + messagePromptInjection2 + reponseCompleteClean;
-
- // Note : On peut ajouter une logique pour extraire la note de la réponse si nécessaire
- if (reponse.Contains("Note de compatibilité"))
- {
- var noteMatch = System.Text.RegularExpressions.Regex.Match(reponse, @"(\d+)/10");
- if (noteMatch.Success && int.TryParse(noteMatch.Groups[1].Value, out int note))
- {
- retour.Note = note;
- }
- }
- #endregion
-
- #region Renseigner le modèle IA
- retour.ModeleIA = modeleIA;
- #endregion
-
- #region Génération XML
- if (isGenererXML)
- {
- /*
- var promptXML = $@"
- Tu es un assistant spécialisé dans l'extraction d'informations depuis des CV.
- Je vais te fournir le contenu brut d’un CV (texte brut sans mise en forme).
- À partir de ce contenu, génère un document structuré au format XML en respectant la structure suivante :
-
- <CV>
- <Identite>
- <Nom></Nom>
- <Prenom></Prenom>
- <Email></Email>
- <Telephone></Telephone>
- <Adresse></Adresse>
- <DateDeNaissance></DateDeNaissance>
- <Nationalite></Nationalite>
- </Identite>
- <Profil></Profil>
- <Competences>
- <Competence nom=""..."" niveau=""..."" />
- ...
- </Competences>
- <Langues>
- <Langue nom=""..."" niveau=""..."" />
- ...
- </Langues>
- <Experiences>
- <Experience>
- <Poste></Poste>
- <Entreprise></Entreprise>
- <Lieu></Lieu>
- <DateDebut></DateDebut>
- <DateFin></DateFin>
- <Description></Description>
- </Experience>
- ...
- </Experiences>
- <Formations>
- <Formation>
- <Diplome></Diplome>
- <Etablissement></Etablissement>
- <DateDebut></DateDebut>
- <DateFin></DateFin>
- </Formation>
- ...
- </Formations>
- <Certifications>
- <Certification>
- <Nom></Nom>
- <Organisme></Organisme>
- <Date></Date>
- </Certification>
- ...
- </Certifications>
- </CV>
-
- Si une information est absente, laisse le champ vide. Ne fais aucun commentaire, retourne uniquement le XML.
- N'oublie aucune expérience, aucune formation, aucune langue, ni aucune certification.
- Formate le tout proprement au format XML. N'ajoute pas de texte explicatif. Commence directement par <document>.
-
- Voici un contenu PDF extrait :
-
- {texteCV}
-
- ";
- */
- var promptXML = PromptService.GetPrompt(PromptService.ePrompt.RechercheCVService_RechercheCV_Generate, texteCV);
- var (reponseXML,m2) = await reActRagAgent.AppelerLLMAsync(ModelsUseCases.TypeUseCase.AnalyseCVMission, true, promptXML,"CV en XML");
- var reponseCompleteCleanXML = reponseXML.Replace("\\n", "\n").Replace("\\r", "\r");
-
- retour.VersionXML = reponseCompleteCleanXML;
-
- }
- #endregion
-
- #region Vectorisation du CV
- await RAGService.IngestDocument(Domain.CV,true, false, texteCV, fichier);
- //reActRagAgent.IngestDocument(texteCV, fichier);
- #endregion
-
- retours.Add(retour);
- }
-
- catch (Exception ex)
- {
- LoggerService.LogError($"Erreur lors de l'extraction du texte de {fichier} : {ex.Message}");
- }
- }
-
- LoggerService.LogInfo($"Analyse des CV terminée");
- return retours;
- }
-
- public static async Task SauvegarderRechercheAsync(ObservableCollection<ReponseRechercheCV> ListeItems)
- {
- LoggerService.LogInfo("RechercheCVService.SauvegarderRechercheAsync");
-
- if (ListeItems == null)
- return;
-
- var options = new JsonSerializerOptions
- {
- WriteIndented = true,
- // Ignore les propriétés non sérialisables comme UniqueId si nécessaire
- IgnoreReadOnlyProperties = false,
- DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
- };
-
- using FileStream fs = File.Create(NomFichierRechercheCV);
- await JsonSerializer.SerializeAsync(fs, ListeItems, options);
- }
-
- public static async Task<ObservableCollection<ReponseRechercheCV>> ChargerCVDepuisJsonAsync(ObservableCollection<ReponseRechercheCV> ListeItems)
- {
- LoggerService.LogInfo("RechercheCVService.ChargerCVDepuisJsonAsync");
-
- if (!File.Exists(NomFichierRechercheCV))
- return new ObservableCollection<ReponseRechercheCV>();
-
- using FileStream fs = File.OpenRead(NomFichierRechercheCV);
- var items = await JsonSerializer.DeserializeAsync<ObservableCollection<ReponseRechercheCV>>(fs);
-
- if (items != null)
- {
- ListeItems = items;
- }
- return ListeItems;
- }
-
- public static async Task<string> SeekByKeyWord(string RechercheString)
- {
- LoggerService.LogInfo("RechercheCVService.SeekByKeyWord");
- return await RAGService.Search(Domain.CV, RechercheString);
- }
- #endregion
-
- #region Méthodes privées
- #endregion
- }
- }
|