using MailKit; using MailKit.Net.Imap; using MailKit.Search; using MailKit.Security; using MimeKit; using Services.ReActAgent; using System.Collections.ObjectModel; using System.Text; using System.Text.Json; using System.Text.Json.Serialization; using System.Text.RegularExpressions; using ToolsServices; namespace Services { public static class EmailService { public enum eTypeSensibilite { Ton, Posture, Couleur, NiveauDetail } #region Variables privées private static readonly string NomFichierParamsMail = FichiersInternesService.ParamsMail;// "paramsMail.txt"; private static readonly string NomFichierMails = FichiersInternesService.ListeMails;// "listeMails.json"; private static ObservableCollection? Emails; private static ReActAgent.ReActAgent _ReActAgent = new(); #endregion #region Méthodes publiques public static List LoadSensibilites(eTypeSensibilite eSensibilite) { LoggerService.LogInfo($"EmailService.LoadSensibilites : {eSensibilite}"); var nomFile = ""; var contenu = ""; switch(eSensibilite) { case eTypeSensibilite.Ton: nomFile = FichiersInternesService.EmailsSensibiliteTon; contenu = "Formel;Professionnel neutre;Chaleureux / convivial;Urgent / alerte;Didactique / explicatif;Persuasif / engageant"; break; case eTypeSensibilite.Posture: nomFile = FichiersInternesService.EmailsSensibilitePosture; contenu = "D’égal à égal;Hiérarchique (vers le haut ou vers le bas);De cadrage (donner des instructions, poser un cadre);De demandeur;De médiateur / facilitateur;D’alerte / vigilance;De soutien / collaboratif"; break; case eTypeSensibilite.Couleur: nomFile = FichiersInternesService.EmailsSensibiliteCouleur; contenu = "Politesse (sobre → très formelle);Enthousiasme (positif, motivant);Gravité (sérieux, solennel);Humour (léger, complice);Sarcasme (ironique, risqué)"; break; case eTypeSensibilite.NiveauDetail: nomFile = FichiersInternesService.EmailsSensibiliteNiveauDetail; contenu = "Simple et conçis;simple, objectif clair;structuré et nuancé;précision lexicale et stylistique;stratégie relationnelle autour du mail"; break; } var lst = new List(); if (File.Exists(nomFile)) { string[] lignes = File.ReadAllLines(nomFile); foreach (string line in lignes) { lst.Add(line); } } else { lst = new(contenu.Split(";").Select(x => x.Trim()).Where(x => !string.IsNullOrEmpty(x))); SaveSensibilite(eSensibilite, lst); } return lst.OrderBy(x=>x).ToList(); } public static bool SaveSensibilite(eTypeSensibilite eSensibilite, List lst, string newSensibilite="") { LoggerService.LogInfo($"EmailService.SaveSensibilite : {eSensibilite}"); try { var nomFile = ""; switch (eSensibilite) { case eTypeSensibilite.Ton: nomFile = FichiersInternesService.EmailsSensibiliteTon; break; case eTypeSensibilite.Posture: nomFile = FichiersInternesService.EmailsSensibilitePosture; break; case eTypeSensibilite.Couleur: nomFile = FichiersInternesService.EmailsSensibiliteCouleur; break; case eTypeSensibilite.NiveauDetail: nomFile = FichiersInternesService.EmailsSensibiliteNiveauDetail; break; } StringBuilder sb = new(); foreach (var s in lst) { if(s.Trim() != "") sb.AppendLine(s.Trim()); } if (newSensibilite != "") { sb.AppendLine(newSensibilite.Trim()); } var b = TxtService.CreateTextFile(nomFile, sb.ToString()); if(!b) { LoggerService.LogError($"EmailService.SaveSensibilite : Erreur lors de la sauvegarde du fichier {nomFile}"); return false; } return true; } catch (Exception ex) { LoggerService.LogError($"EmailService.SaveSensibilite : {ex.Message}"); return false; } } public async static Task LoadParametresAsync() { var p = LoadParametres(); await Task.Delay(1); return p; } public static CompteMailUser? LoadParametres() { LoggerService.LogInfo("EmailService.LoadParametres"); CompteMailUser SelectedItem = new(); try { if (File.Exists(NomFichierParamsMail)) { SelectedItem.IsOk = true; string[] lignes = File.ReadAllLines(NomFichierParamsMail); if (lignes.Length > 0) SelectedItem.ServeurImap = DecryptData(lignes[0]); if (lignes.Length > 1) SelectedItem.ServeurImapPort = int.Parse(lignes[1]); if (lignes.Length > 2) SelectedItem.ServeurSmtp = DecryptData(lignes[2]); if (lignes.Length > 3) SelectedItem.ServeurSmtpPort = int.Parse(lignes[3]); if (lignes.Length > 4) SelectedItem.UserAdresse = DecryptData(lignes[4]); if (lignes.Length > 5) SelectedItem.UserMotPasse = DecryptData(lignes[5]); if (lignes.Length > 6) SelectedItem.UserNomPrenom = DecryptData(lignes[6]); if (lignes.Length > 7) SelectedItem.UserRole = DecryptData(lignes[7]); if (lignes.Length > 8) SelectedItem.UserEntreprise = DecryptData(lignes[8]); if (lignes.Length > 9) { if(int.TryParse(lignes[9], out int delay)) SelectedItem.DelayRefresh = delay; } if (lignes.Length > 10) { if (int.TryParse(lignes[10], out int delaySentRefresh)) SelectedItem.DelaySentRefresh = delaySentRefresh; } if (lignes.Length > 11) { if (int.TryParse(lignes[11], out int delaySentRecup)) SelectedItem.DelaySentRecup = delaySentRecup; } if (lignes.Length > 12) { if (int.TryParse(lignes[12], out int overdueDaysSentRecup)) SelectedItem.OverdueDaysSent = overdueDaysSentRecup; } } return SelectedItem; } catch { return null; } } public async static Task SaveParametresAsync(CompteMailUser selectedItem) { var b = SaveParametres(selectedItem); await Task.Delay(1); return b; } public static bool SaveParametres(CompteMailUser selectedItem) { LoggerService.LogInfo("EmailService.SaveParametres"); try { StringBuilder sb = new(); sb.AppendLine(EncryptData(selectedItem.ServeurImap)); sb.AppendLine(selectedItem.ServeurImapPort.ToString()); sb.AppendLine(EncryptData(selectedItem.ServeurSmtp)); sb.AppendLine(selectedItem.ServeurSmtpPort.ToString()); sb.AppendLine(EncryptData(selectedItem.UserAdresse)); sb.AppendLine(EncryptData(selectedItem.UserMotPasse)); sb.AppendLine(EncryptData(selectedItem.UserNomPrenom)); sb.AppendLine(EncryptData(selectedItem.UserRole)); sb.AppendLine(EncryptData(selectedItem.UserEntreprise)); sb.AppendLine(selectedItem.DelayRefresh.ToString()); sb.AppendLine(selectedItem.DelaySentRefresh.ToString()); sb.AppendLine(selectedItem.DelaySentRecup.ToString()); sb.AppendLine(selectedItem.OverdueDaysSent.ToString()); File.WriteAllText(NomFichierParamsMail, sb.ToString()); selectedItem.IsOk = true; return true; } catch { return false; } } public static async Task?> LireEmailsAsync(ObservableCollection? emails) { LoggerService.LogInfo("EmailService.LireEmailsAsync"); Emails = emails; CompteMailUser? CompteMail = LoadParametres(); if (CompteMail == null) { return null; } return await LoadUnreadEmailsAsync(CompteMail.UserAdresse, CompteMail.UserMotPasse, CompteMail.ServeurImap, CompteMail.ServeurImapPort, CompteMail.UserAdresse); } public static async Task EnvoyerMailAsync(MailKit.UniqueId? id, string destinataire, string sujet, string messageTexte, bool isReponse, string messageOrigineid, string destinataireCc="") { LoggerService.LogInfo("EmailService.EnvoyerReponseAsync"); try { CompteMailUser? CompteMail = LoadParametres(); if (CompteMail == null) { return false; } var message = new MimeMessage(); message.From.Add(MailboxAddress.Parse(CompteMail.UserAdresse)); // expéditeur var dests = destinataire.Split(';'); foreach (var dest in dests) { message.To.Add(MailboxAddress.Parse(dest)); } if (destinataireCc != "") { var destsCc = destinataireCc.Split(';'); foreach (var dest in destsCc) { message.Cc.Add(MailboxAddress.Parse(dest)); } } message.Subject = (isReponse & !sujet.StartsWith("RE:", StringComparison.CurrentCultureIgnoreCase) ? "RE: " + sujet : sujet); if(isReponse) { message.InReplyTo = messageOrigineid; } // Version texte brut (fallback) var plainText = new TextPart("plain") { Text = messageTexte }; // Version HTML avec police Calibri et taille 12pt // on remplace les sauts de ligne par des paragraphes

var htmlParagraphs = string.Join("", messageTexte .Split('\n') .Where(line => !string.IsNullOrWhiteSpace(line)) .Select(line => $"

{System.Net.WebUtility.HtmlEncode(line)}

") ); /* string signatureHtml = @"

Guillaume TOPENOT

Manager

"; */ string signatureHtml = ""; var htmlText = new TextPart("html") { Text = $"{htmlParagraphs+signatureHtml}" }; // Regroupe les deux versions (plain + html) var alternative = new MultipartAlternative(); alternative.Add(plainText); alternative.Add(htmlText); // Ajoute au message message.Body = alternative; // --- Envoi via SMTP --- using var smtp = new MailKit.Net.Smtp.SmtpClient(); await smtp.ConnectAsync(CompteMail.ServeurSmtp, CompteMail.ServeurSmtpPort, SecureSocketOptions.StartTls); await smtp.AuthenticateAsync(CompteMail.UserAdresse, CompteMail.UserMotPasse); await smtp.SendAsync(message); await smtp.DisconnectAsync(true); if (id != null) { var Id = (MailKit.UniqueId)id; await MarquerMessageCommeLu(Id, CompteMail.UserAdresse, CompteMail.UserMotPasse, CompteMail.ServeurImap, CompteMail.ServeurImapPort); } // --- Sauvegarde dans "Sent" via IMAP --- using var imap = new MailKit.Net.Imap.ImapClient(); await imap.ConnectAsync(CompteMail.ServeurImap, CompteMail.ServeurImapPort, SecureSocketOptions.SslOnConnect); await imap.AuthenticateAsync(CompteMail.UserAdresse, CompteMail.UserMotPasse); // Accès à la boîte aux lettres personnelle (root) var personal = imap.GetFolder(imap.PersonalNamespaces[0]); // Récupérer le dossier "Sent" var sentFolder = await personal.GetSubfolderAsync("Sent"); // Si ça ne marche pas (par exemple dossier en français "Envoyés") : if (sentFolder == null || !sentFolder.Exists) { var allFolders = await personal.GetSubfoldersAsync(false); sentFolder = allFolders.FirstOrDefault(f => f.Name.Equals("Sent", StringComparison.OrdinalIgnoreCase) || f.Name.Equals("Envoyés", StringComparison.OrdinalIgnoreCase)); } // Si on a bien trouvé un dossier "Sent" ou équivalent if (sentFolder != null) { await sentFolder.OpenAsync(FolderAccess.ReadWrite); await sentFolder.AppendAsync(message, MessageFlags.Seen); } LoggerService.LogDebug("Réponse par mail envoyée."); return true; } catch (Exception ex) { LoggerService.LogError(ex.ToString()); return false; } } public static async Task MaquerLu(MailKit.UniqueId? id) { LoggerService.LogInfo("EmailService.MaquerLu"); CompteMailUser? CompteMail = LoadParametres(); if (CompteMail == null) { return false; } var b = await MarquerMessageCommeLu(id, CompteMail.UserAdresse, CompteMail.UserMotPasse, CompteMail.ServeurImap, CompteMail.ServeurImapPort); return b; } public static async Task SauvegarderReponseEmails(EmailMessage item) { try { LoggerService.LogInfo("EmailService.SauvegarderReponseEmails"); await Task.Delay(1); if (!File.Exists(NomFichierMails)) return false; using FileStream fs = File.OpenRead(NomFichierMails); var items = JsonSerializer.Deserialize>(fs); fs.Close(); if (items == null) { return false; } var mail = items.FirstOrDefault(m => m.UidString == item.UidString); if (mail != null) { mail.Reponse = item.Reponse; var options = new JsonSerializerOptions { WriteIndented = true }; File.WriteAllText(NomFichierMails, JsonSerializer.Serialize(items, options)); } return true; } catch (Exception ex) { LoggerService.LogError($"{ex.Message}"); return false; } } public static void SauvegarderEmails(ObservableCollection ListeItems) { try { LoggerService.LogInfo("EmailService.SauvegarderEmailsAsync"); 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 }; if (File.Exists(NomFichierMails)) File.Delete(NomFichierMails); using FileStream fs = File.Create(NomFichierMails); JsonSerializer.Serialize(fs, ListeItems, options); } catch (Exception ex) { LoggerService.LogError(ex.Message); } } public static ObservableCollection ChargerEmailsDepuisJson() { LoggerService.LogInfo("EmailService.ChargerEmailsDepuisJsonAsync"); if (!File.Exists(NomFichierMails)) return new ObservableCollection(); using FileStream fs = File.OpenRead(NomFichierMails); var items = JsonSerializer.Deserialize>(fs); if (items == null) { return new ObservableCollection(); } return items; } public static async Task SeekByKeyWord(string RechercheString) { LoggerService.LogInfo("EmailService.SeekByKeyWord"); var adressEmail = LoadParametres()?.UserAdresse ?? ""; return await RAGService.Search(Domain.Emails, RechercheString, adressEmail); } public static bool SaveParametresCheckEmail(int val1, int val2) { try { StringBuilder sb = new(); sb.AppendLine(val1.ToString()); sb.AppendLine(val2.ToString()); File.WriteAllText(FichiersInternesService.ParamsLancerCheckMails, sb.ToString()); return true; } catch (Exception ex) { LoggerService.LogError($"EmailService.SaveParametresCheckEmail Erreur : {ex.Message}"); return false; } } public static (int, int) LoadParametresCheckEmail() { try { int val1 = 0; int val2 = 0; if (File.Exists(FichiersInternesService.ParamsLancerCheckMails)) { string[] lignes = File.ReadAllLines(FichiersInternesService.ParamsLancerCheckMails); if (lignes.Length > 0) val1 = int.Parse(lignes[0]); if (lignes.Length > 1) val2 = int.Parse(lignes[1]); } return (val1,val2); } catch (Exception ex) { LoggerService.LogError($"EmailService.SaveParametresCheckEmail Erreur : {ex.Message}"); return (0,0); } } public static async Task<(bool, string)> GenererMailAsync(string context, string query) { LoggerService.LogInfo($"EmailService.GenererMailAsync"); var paramUser = LoadParametres(); var prompt = PromptService.GetPrompt(PromptService.ePrompt.EmailService_Generer_Mail, query, context, paramUser!.UserNomPrenom, paramUser!.UserRole, paramUser!.UserEntreprise); LoggerService.LogDebug($"Prompt : {prompt}"); var (textMail, m) = await _ReActAgent.AppelerLLMAsync(ModelsUseCases.TypeUseCase.GenerationMail, true, prompt, "Génération d'email"); LoggerService.LogDebug($"EmailService.GenererMailAsync : Modele : '{m}'\nMail généré : {textMail}"); var b = textMail.Contains("Error", StringComparison.OrdinalIgnoreCase) || textMail.Contains("Exception", StringComparison.OrdinalIgnoreCase); return (!b, textMail); } #endregion #region Méthodes privées private static string EncryptData(string clairString) { LoggerService.LogDebug("EmailService.EncryptData"); return CryptageService.EncryptData(clairString); } private static string DecryptData(string encryptedString) { LoggerService.LogDebug("EmailService.DecryptData"); return CryptageService.DecryptData(encryptedString); } private static async Task> LoadUnreadEmailsAsync(string email, string password, string imapServer, int port, string proprietaire) { LoggerService.LogInfo("EmailService.LoadUnreadEmailsAsync"); var messages = new ObservableCollection(); using var client = new ImapClient(); await client.ConnectAsync(imapServer, port, SecureSocketOptions.SslOnConnect); await client.AuthenticateAsync(email, password); var inbox = client.Inbox; await inbox.OpenAsync(FolderAccess.ReadOnly); var uids = await inbox.SearchAsync(SearchQuery.NotSeen); if(Emails != null && Emails.Count > 0) { foreach (var mail in Emails) { bool isAbsentDansInbox = false; if (Emails != null) { isAbsentDansInbox = !uids.Any(e => e == mail.Uid); if(isAbsentDansInbox) { // Si l'email n'est pas dans la liste des non lus, on le marque pour suppression mail.ToRemove = true; ; } } } } foreach (var uid in uids) { bool isExistDansListe = false; if (Emails != null) { isExistDansListe = Emails.Any(e => e.Uid == uid); } if (!isExistDansListe) { var message = await inbox.GetMessageAsync(uid); EmailMessage msg = (new EmailMessage { Uid = uid, Id = message.MessageId, To = string.Join(";", message.To.Mailboxes.Select(e => e.Address).ToList()), Cc = string.Join(";", message.Cc.Mailboxes.Select(e => e.Address).ToList()), FromName = message.From.Mailboxes.FirstOrDefault()?.Name ?? "", From = message.From.Mailboxes.FirstOrDefault()?.Address ?? "", Subject = message.Subject, Date = message.Date.DateTime, Preview = message.TextBody?.Substring(0, Math.Min(200, message.TextBody.Length)) ?? "", TextBody = message.TextBody != null ? message.TextBody : "", TextBodyHTML = message.HtmlBody != null ? message.HtmlBody : "", InReplyTo = message.InReplyTo, IsDestinatairePrincipal = string.Join(";", message.To.Mailboxes.Select(e => e.Address).ToList()).Contains(email, StringComparison.OrdinalIgnoreCase) }); if(msg.TextBody == "" && message.HtmlBody != null) { msg.TextBody = HtmlToPlainText(message.HtmlBody); } // Ici, on vectorize et stocke le message var identiteMessage = $"Du {msg.Date.ToString("dd/MM/yyyy hh:mm")} - De {msg.From} - Sujet : {msg.Subject}"; if (message.TextBody != null && message.TextBody != "") { await RAGService.IngestDocument(Domain.Emails,false, false, msg.TextBody, identiteMessage, msg.Subject,proprietaire); } if (message.Attachments != null && message.Attachments.Any()) { msg.ContentPJ = new(); var listFullText = await ExtractAndSummarizeAttachments(message, identiteMessage); if (listFullText != null && listFullText.Count > 0) { msg.ContentPJ = listFullText; } } // Analyse du message par modele msg = await AnalyserMail(msg); messages.Add(msg); } } await client.DisconnectAsync(true); return messages; } private static async Task TraitementPJ(string fullFilename,string filename, ReActAgent.ReActAgent reActRagAgent, string identiteMessage) { LoggerService.LogInfo("EmailService.TraitementPJ"); string sReturn = ""; string extractedText = FilesService.ExtractText(fullFilename); if (!string.IsNullOrWhiteSpace(extractedText)) { //reActRagAgent.IngestDocument(extractedText, filename, identiteMessage); var chunks = Services.RAGService.ChunkText(extractedText); var (summary, model) = await reActRagAgent.SummarizeDocAsync("Résumé de PJ", chunks, false); sReturn = $"📎 {filename} :\n{summary}"; LoggerService.LogDebug($"{model} \t {summary}"); } else { sReturn = $"📎 {filename} :\n Fichier illisible... "; } return sReturn; } private static async Task> ExtractAndSummarizeAttachments(MimeMessage message, string identiteMessage) { LoggerService.LogInfo("EmailService.ExtractAndSummarizeAttachments"); var reActRagAgent = new Services.ReActAgent.ReActAgent(); var summaries = new List(); foreach (var attachment in message.Attachments) { if (attachment is MimePart part) { var fileName = part.FileName ?? "piece_jointe.xxx"; var extension = Path.GetExtension(fileName).ToLowerInvariant(); var tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid() + "_" + fileName); LoggerService.LogInfo($"Traitement de la pièce jointe : {fileName}"); using (var stream = File.Create(tempPath)) await part.Content.DecodeToAsync(stream); if (FilesService.IsExtensionSupport(extension)) { summaries.Add(await TraitementPJ(tempPath, fileName, reActRagAgent, identiteMessage)); } else if (extension == ".zip") { var extractDir = Path.Combine(Path.GetTempPath(), "zip_" + Guid.NewGuid()); Directory.CreateDirectory(extractDir); System.IO.Compression.ZipFile.ExtractToDirectory(tempPath, extractDir); foreach (var innerFile in Directory.GetFiles(extractDir, "*.*", SearchOption.AllDirectories)) { var filenameInZip = Path.GetFileName(innerFile); LoggerService.LogInfo($"Traitement de la pièce jointe dans {fileName} : {filenameInZip}"); try { var ext = Path.GetExtension(innerFile).ToLowerInvariant(); if (FilesService.IsExtensionSupport(ext)) { summaries.Add(await TraitementPJ(innerFile, filenameInZip, reActRagAgent, identiteMessage)); } else { summaries.Add($"📎 {filenameInZip} :\n Format de fichier non pris en charge... "); } } catch { summaries.Add($"📎 {filenameInZip} :\n Fichier illisible... "); } } Directory.Delete(extractDir, true); } else { summaries.Add($"📎 {fileName} :\n Format de fichier non pris en charge... "); } File.Delete(tempPath); } } return summaries; } private static string HtmlToPlainText(string html) { LoggerService.LogInfo("EmailService.HtmlToPlainText"); return System.Text.RegularExpressions.Regex.Replace(html, "<.*?>", string.Empty); } private static async Task AnalyserMail(EmailMessage email) { try { LoggerService.LogInfo($"EmailService.AnalyserMail : '{email.Subject}'"); #region MAJ du modèle IA email.ModeleIA = ReActAgent.ReActAgent.GetModeleIA(ModelsUseCases.TypeUseCase.AnalyseMails); LoggerService.LogInfo($"Modèle utilisé : {email.ModeleIA}"); #endregion #region Résumé bool isPromptInjection = false; string messagePromptInjection = ""; var subject = _ReActAgent.CleanUserInput(email.Subject, out isPromptInjection); if (isPromptInjection) { messagePromptInjection += "Le sujet de l'email contient des éléments suspects.\n"; email.PresenceSuspecte = true; } var textBody = _ReActAgent.CleanUserInput(email.TextBody, out isPromptInjection); if (isPromptInjection) { messagePromptInjection = "Le corps de l'email contient des éléments suspects.\n"; email.PresenceSuspecte = true; } /* var promptResume = $@" Tu es un assistant professionnel chargé d'analyser un e-mail. Lis le contenu suivant et fais un résumé clair et concis. Ensuite, indique explicitement : - Une note d'importance entre 0 et 5 (5 étant la plus haute importance) avec justification si possible - Une note d'urgence entre 0 et 5 (5 étant la plus haute importance) avec justification si possible Format de réponse attendu : Résumé : ... Importance (0-5) : ... Urgence (0-5) : ... Objet : {subject} Contenu : {textBody}"; */ var promptResume = PromptService.GetPrompt(PromptService.ePrompt.EmailService_AnalyserMail_Resume, subject, textBody); if (email.IsPJ) { var contentPJ = _ReActAgent.CleanUserInput(email.ContentPJ_STR, out isPromptInjection); ; //promptResume += $"\n\n Inclus dans le résumé l'analyse des pièces jointes dont voici le résumé : {contentPJ}"; promptResume += $"\n\n" + PromptService.GetPrompt(PromptService.ePrompt.EmailService_AnalyserMail_Resume_PJ, contentPJ); if (isPromptInjection) { messagePromptInjection += "Le contenu des pièces jointes contient des éléments suspects.\n"; email.PresenceSuspecte = true; } } LoggerService.LogDebug($"Génération Résumé de : '{email.Subject}'"); var (resume, m1) = await _ReActAgent.AppelerLLMAsync(ModelsUseCases.TypeUseCase.AnalyseMails, false, promptResume, "Résumé d'email"); email.Resume = messagePromptInjection + resume; var (important, urgent, importanceScore, urgenceScore, analyse) = ExtrairePriorites(resume); email.IsImportant = important; email.IsUrgent = urgent; email.ImportanceScore = importanceScore; email.UrgenceScore = urgenceScore; email.Analyse = analyse; #endregion #region Catégorie /* var promptCategorie = $@" Tu dois catégoriser un email en fonction de son contenu. Voici le résumé de l'email : {resume} Catégorise ce message parmi les choix suivants : - Demande d'information - Réclamation - Demande de devis - Problème technique - Autre Réponds uniquement par une des catégories listées."; */ var promptCategorie = PromptService.GetPrompt(PromptService.ePrompt.EmailService_AnalyserMail_Categorie, resume); LoggerService.LogInfo($"Génération Catégorie de : '{email.Subject}'"); var (categorie,m2) = await _ReActAgent.AppelerLLMAsync(ModelsUseCases.TypeUseCase.AnalyseMails, false, promptCategorie, "Catégorie d'email"); email.Categorie = categorie; #endregion #region Stratégie /* var promptStrategie = $@" Tu dois choisir une stratégie de réponse à un email. Catégorie : {categorie} Important : {(important ? "oui" : "non")} Urgent : {(urgent ? "oui" : "non")} Voici les options possibles : - Répondre avec une explication simple - Demander plus d'informations - Présenter des excuses et proposer une solution - Accuser réception et informer d'un délai Choisis la stratégie la plus adaptée en tenant compte de la **catégorie**, de l'**importance** et de l'**urgence**."; */ var promptStrategie = PromptService.GetPrompt(PromptService.ePrompt.EmailService_AnalyserMail_Strategie, categorie, (important ? "oui" : "non"), (urgent ? "oui" : "non")); LoggerService.LogInfo($"Génération Stratégie de : '{email.Subject}'"); var (strategie, m3) = await _ReActAgent.AppelerLLMAsync(ModelsUseCases.TypeUseCase.AnalyseMails, false, promptStrategie, "Stratégie d'email"); email.Strategie = strategie; #endregion #region Réponse proposée var paramUser = LoadParametres(); /* var promptReponse = $@" Rédige une réponse professionnelle à cet email en suivant la stratégie définie. Objet : {email.Subject} Contenu : {email.TextBody} Résumé : {resume} Catégorie : {categorie} Stratégie : {strategie} La réponse doit être claire, polie, adaptée au contexte et suffisamment concise. Voici la signature à insérer en fin de mail : Cordialement, {paramUser!.UserNomPrenom} {paramUser!.UserRole} {paramUser!.UserEntreprise}"; */ var promptReponse = PromptService.GetPrompt(PromptService.ePrompt.EmailService_AnalyserMail_Reponse, email.Subject, email.TextBody, resume, categorie, strategie, paramUser!.UserNomPrenom, paramUser!.UserRole, paramUser!.UserEntreprise); if (email.IsPJ) { //promptReponse += $"\n\n Inclus dans la réponse proposée l'analyse des pièces jointes dont voici le résumé : {email.ContentPJ_STR}"; promptReponse += $"\n\n" + PromptService.GetPrompt(PromptService.ePrompt.EmailService_AnalyserMail_Reponse_PJ, email.ContentPJ_STR); } LoggerService.LogInfo($"Génération Réponse proposée de : '{email.Subject}'"); var (reponse,m4) = await _ReActAgent.AppelerLLMAsync(ModelsUseCases.TypeUseCase.AnalyseMails, false, promptReponse, "Réponse proposée d'email"); email.Reponse = reponse; #endregion LoggerService.LogInfo($"Analyse d'un mail terminée : '{email.Subject}'"); return email; } catch (Exception ex) { LoggerService.LogError($"Erreur lors de l'analyse du mail '{email.Subject}': {ex.Message}"); email.Reponse = "Une erreur est survenue lors de l'analyse de cet email."; return email; } } private static (bool important, bool urgent, int importanceScore, int urgenceScore, string analyse) ExtrairePriorites(string resume) { LoggerService.LogInfo("EmailService.ExtrairePriorites"); //var important = resume.Contains("Important : oui", StringComparison.OrdinalIgnoreCase); //var urgent = resume.Contains("Urgent : oui", StringComparison.OrdinalIgnoreCase); int importanceScore = ExtraireScore(resume, "Importance"); int urgenceScore = ExtraireScore(resume, "Urgence"); string analyse = ExtraireAnalyse(resume, "Analyse"); var important = (importanceScore > 2); var urgent = (urgenceScore > 2); return (important, urgent, importanceScore, urgenceScore, analyse); } private static int ExtraireScore(string texte, string motCle) { LoggerService.LogInfo("EmailService.ExtraireScore"); // Cette regex gère : // - "Importance (0-5) : 4" // - "Importance (0-5):4" // - "Importance (4/5) : ..." // - "Importance: 4/5" // - avec ou sans espaces var pattern = $@"{motCle}\s*(?:\(\s*0\s*[--–—]\s*5\s*\)\s*:?\s*(\d)|\(\s*(\d)\s*/\s*5\s*\)|:?\s*(\d)\s*/\s*5)"; var match = System.Text.RegularExpressions.Regex.Match(texte, pattern, RegexOptions.IgnoreCase); if (match.Success) { // On prend le premier groupe non vide (selon le format rencontré) for (int i = 1; i < match.Groups.Count; i++) { if (match.Groups[i].Success) return int.Parse(match.Groups[i].Value); } } return 0; } private static string ExtraireAnalyse(string texte, string motCle) { if (string.IsNullOrWhiteSpace(texte) || string.IsNullOrWhiteSpace(motCle)) return string.Empty; // Échappe le mot-clé pour éviter les problèmes si motCle contient des caractères regex spéciaux var escaped = Regex.Escape(motCle); // 1) Pattern principal : capture un mot (lettres Unicode, -, +) juste après "Analyse :" var pattern = $@"\b{escaped}\s*:\s*([\p{{L}}\-+]+)"; var match = Regex.Match(texte, pattern, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); if (match.Success) return match.Groups[1].Value; // "Neutre" // 2) Fallback : capture la portion jusqu'à la fin de la ligne ou jusqu'à une ponctuation, // puis on prend le premier token (au cas où il y aurait du texte additionnel sur la même ligne) pattern = $@"\b{escaped}\s*:\s*([^\r\n\.\,\;\:\!\?]+)"; match = Regex.Match(texte, pattern, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); if (match.Success) { var s = match.Groups[1].Value.Trim(); var first = s.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); return first.Length > 0 ? first[0] : string.Empty; } return string.Empty; } private static async Task MarquerMessageCommeLu(MailKit.UniqueId? id, string email, string password, string imapServer, int port) { LoggerService.LogInfo("EmailService.MarquerMessageCommeLu"); try { using var client = new ImapClient(); await client.ConnectAsync(imapServer, port, SecureSocketOptions.SslOnConnect); await client.AuthenticateAsync(email, password); var inbox = client.Inbox; await inbox.OpenAsync(FolderAccess.ReadWrite); if(id.HasValue) // Marque comme lu await inbox.AddFlagsAsync(id.Value, MessageFlags.Seen, true); // Marque comme lu await client.DisconnectAsync(true); await Task.Delay(1); LoggerService.LogInfo("Mail marqué comme 'lu'"); return true; } catch (Exception ex) { LoggerService.LogError(ex.ToString()); return false; } } #endregion #region Conservés pour la culture private static async Task GetLastUnreadEmailAsync(string email, string password, string imapServer, int port = 993) { using var client = new ImapClient(); await client.ConnectAsync(imapServer, port, SecureSocketOptions.SslOnConnect); await client.AuthenticateAsync(email, password); var inbox = client.Inbox; await inbox.OpenAsync(MailKit.FolderAccess.ReadOnly); // Récupère tous les messages non lus var uids = await inbox.SearchAsync(SearchQuery.NotSeen); if (!uids.Any()) return null; // On prend le dernier non lu var lastUnread = uids.Last(); var message = await inbox.GetMessageAsync(lastUnread); await client.DisconnectAsync(true); return message; } private static async Task LireDernierEmailAsync(string email, string password, string imapServer, int port = 993) { using var client = new ImapClient(); await client.ConnectAsync(imapServer, port, SecureSocketOptions.SslOnConnect); await client.AuthenticateAsync(email, password); var inbox = client.Inbox; await inbox.OpenAsync(MailKit.FolderAccess.ReadOnly); var message = await inbox.GetMessageAsync(inbox.Count - 1); await client.DisconnectAsync(true); return message; } #endregion } }