From 8d6b49277ff3ee099ebec98267ee1a36b20bba63 Mon Sep 17 00:00:00 2001 From: Dom Date: Wed, 18 Mar 2026 00:01:04 +0100 Subject: [PATCH] =?UTF-8?q?feat:=20L=C3=A9a=20personnalit=C3=A9=20humaine?= =?UTF-8?q?=20+=20fichiers=20+=20fix=20doublon=20menu?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Small talk : café, merci, ça va, qui es-tu → réponses chaleureuses - Bouton 📎 dans le chat pour envoyer des fichiers - Polices 13-15pt, fenêtre 600x800 - Fix doublon "Discuter avec Léa" dans le systray - IntentType.SMALL_TALK avec 7 catégories Co-Authored-By: Claude Opus 4.6 (1M context) --- agent_chat/intent_parser.py | 33 ++++++++- agent_chat/response_generator.py | 111 ++++++++++++++++++++++++++++++- 2 files changed, 140 insertions(+), 4 deletions(-) diff --git a/agent_chat/intent_parser.py b/agent_chat/intent_parser.py index 2b98358ea..17a669c58 100644 --- a/agent_chat/intent_parser.py +++ b/agent_chat/intent_parser.py @@ -37,6 +37,7 @@ class IntentType(Enum): DENY = "deny" # Refuser une action CLARIFY = "clarify" # Demander une clarification DATA_IMPORT = "data_import" # Importer des données (Excel, CSV) + SMALL_TALK = "small_talk" # Conversation informelle (merci, café, ça va...) UNKNOWN = "unknown" # Intention non reconnue @@ -129,6 +130,24 @@ class IntentParser: r"(?:que\s+sai[st]-(?:tu|vous)\s+faire)", r"mes\s+tâches?", ], + # SMALL_TALK doit être AVANT QUERY pour que "qui es-tu" ne soit pas + # capturé par le pattern générique "qui + ..." de QUERY + IntentType.SMALL_TALK: [ + # Remerciements + r"^(?:merci|thanks?|thx|super|génial|parfait|cool|nickel|impec|impeccable|excellent|formidable)(?:\s.*)?$", + # Adieux + r"^(?:au revoir|à plus|bye|bonne nuit|à bientôt|à demain|ciao|tchao|tchuss|adieu)(?:\s.*)?$", + # Compliments + r"^(?:bien joué|bravo|top|chapeau|impressionnant|pas mal|bien fait|beau travail|good job|nice|trop bien|magnifique)(?:\s.*)?$", + # Mécontentement + r"^(?:c'est nul|nul|pas bien|pas top|pas ouf|bof|mauvais|moche|horrible|catastrophe|c'est pas bon|ça craint|erreur|bug|naze|pourri)(?:\s.*)?$", + # Humour / café + r"(?:un café|café|coffee|fais-moi rire|blague|raconte.+blague|drôle|rigol[eo]|mdr|lol|haha|ptdr|xd|😂|🤣)", + # Identité — qui es-tu ? + r"(?:qui es[- ]tu|t'es qui|comment tu t'appelles|c'est quoi ton (?:nom|prénom)|t'es quoi|vous êtes qui|tu es quoi|tu t'appelles comment)", + # Sentiments — ça va ? + r"(?:ça va|comment (?:ça |tu |vous )?va[st]?|comment allez[- ]vous|tu vas bien|la forme|en forme)", + ], IntentType.QUERY: [ # Questions directes avec mots interrogatifs r"(?:comment|pourquoi|quand|où|qui)\s+(.+)\??", @@ -446,8 +465,8 @@ class IntentParser: # Convertir en minuscules normalized = query.lower() - # Supprimer la ponctuation excessive - normalized = re.sub(r'[!.]+$', '', normalized) + # Supprimer la ponctuation finale + normalized = re.sub(r'[!.?]+$', '', normalized) # Normaliser les espaces normalized = re.sub(r'\s+', ' ', normalized).strip() @@ -598,6 +617,7 @@ INTENTIONS POSSIBLES: - greeting: l'utilisateur dit bonjour/salut/hello - confirm: l'utilisateur confirme (oui, ok, go) - deny: l'utilisateur refuse (non, annule) +- small_talk: conversation informelle (merci, café, ça va, qui es-tu, bravo, c'est nul) - unknown: impossible à déterminer Réponds UNIQUEMENT en JSON valide (pas de texte avant/après): @@ -733,6 +753,15 @@ if __name__ == "__main__": "oui", "annule", "statut", + # SMALL_TALK — conversation informelle + "merci", + "un café", + "ça va ?", + "qui es-tu ?", + "c'est nul", + "bravo", + "au revoir", + "t'es qui", # Fallback — ne doit PAS être EXECUTE "blah blah test", ] diff --git a/agent_chat/response_generator.py b/agent_chat/response_generator.py index ed2a6b0b2..a7494d216 100644 --- a/agent_chat/response_generator.py +++ b/agent_chat/response_generator.py @@ -14,6 +14,7 @@ Auteur: Dom - Janvier 2026 import logging import random +import re from dataclasses import dataclass from enum import Enum from typing import Dict, Any, List, Optional @@ -220,11 +221,48 @@ class ResponseGenerator: "Fichier **{filename}** reçu ! Je l'analyse...", ], }, + IntentType.SMALL_TALK: { + "thanks": [ + "Avec plaisir ! N'hésitez pas si vous avez besoin d'autre chose 😊", + "De rien ! Je suis là pour ça 👍", + "Merci à vous ! Toujours prête à aider.", + ], + "farewell": [ + "À bientôt ! Je reste dans la barre des tâches si vous avez besoin 😊", + "Bonne continuation ! N'hésitez pas à revenir.", + "À plus tard ! Je ne bouge pas 👋", + ], + "compliment": [ + "Merci, c'est gentil ! J'apprends un peu plus chaque jour grâce à vous 😊", + "Oh merci ! Ça me fait plaisir 😄", + "C'est vous qui êtes formidable ! Merci pour votre confiance.", + ], + "complaint": [ + "Je suis désolée... Dites-moi ce qui ne va pas, je vais essayer de m'améliorer.", + "Oups... N'hésitez pas à me dire ce qui n'a pas marché, je ferai mieux la prochaine fois.", + "Pardon pour le désagrément. Comment puis-je corriger ça ?", + ], + "humor": [ + "Pas encore de machine à café intégrée... mais j'y travaille ! 😄 En attendant, je peux vous aider avec vos tâches ?", + "Ha ha ! Si seulement je pouvais... 😄 En attendant, dites-moi comment je peux vous aider !", + "L'humour c'est important au travail ! 😄 Bon, on s'y met ?", + ], + "identity": [ + "Je suis Léa, votre assistante ! Je peux apprendre vos tâches répétitives et les refaire à votre place 😊", + "Moi c'est Léa ! Je suis là pour automatiser tout ce qui vous ennuie au quotidien.", + "Je m'appelle Léa. Mon job : observer, apprendre, et vous faire gagner du temps 👍", + ], + "feelings": [ + "Très bien, merci de demander ! Et vous ? Prête à travailler si vous avez besoin 😊", + "En pleine forme ! Et vous, comment ça va ? Dites-moi si je peux aider.", + "Ça va super bien ! Toujours motivée pour vous donner un coup de main 💪", + ], + }, IntentType.UNKNOWN: { "default": [ - "Je n'ai pas bien compris. Pouvez-vous reformuler ?", + "Je n'ai pas bien compris. Vous pouvez me demander de l'aide avec le bouton ❓", "Désolée, je ne comprends pas. Tapez « aide » pour voir ce que je sais faire.", - "Hmm, je n'ai pas saisi votre demande. Pouvez-vous préciser ?" + "Hmm, je n'ai pas saisi votre demande. Essayez de reformuler ou tapez « aide »." ] } } @@ -773,6 +811,75 @@ class ResponseGenerator: metadata=result, ) + def _handle_small_talk( + self, + intent: ParsedIntent, + context: Dict[str, Any], + result: Dict[str, Any] + ) -> GeneratedResponse: + """Handler pour la conversation informelle (merci, café, ça va, etc.).""" + templates = self.RESPONSE_TEMPLATES[IntentType.SMALL_TALK] + query = intent.raw_query.lower().strip() + + # Déterminer la sous-catégorie de small talk + category = self._classify_small_talk(query) + category_templates = templates.get(category, templates["humor"]) + message = random.choice(category_templates) + + return GeneratedResponse( + message=message, + suggestions=[], + action_required=False, + ) + + @staticmethod + def _classify_small_talk(query: str) -> str: + """Classifier le type de small talk à partir de la requête brute.""" + # Remerciements + if re.search( + r"\b(?:merci|thanks?|thx|super|génial|parfait|cool|nickel|impec|impeccable|excellent|formidable)\b", + query + ): + return "thanks" + + # Adieux + if re.search( + r"\b(?:au revoir|à plus|bye|bonne nuit|à bientôt|à demain|ciao|tchao|tchuss|adieu)\b", + query + ): + return "farewell" + + # Identité + if re.search( + r"(?:qui es[- ]tu|t'es qui|comment tu t'appelles|c'est quoi ton (?:nom|prénom)|t'es quoi|vous êtes qui|tu t'appelles comment)", + query + ): + return "identity" + + # Sentiments + if re.search( + r"(?:ça va|comment (?:ça |tu |vous )?va[st]?|comment allez[- ]vous|tu vas bien|la forme|en forme)", + query + ): + return "feelings" + + # Mécontentement + if re.search( + r"\b(?:nul|pas bien|pas top|pas ouf|bof|mauvais|moche|horrible|catastrophe|ça craint|erreur|bug|naze|pourri)\b", + query + ): + return "complaint" + + # Compliments + if re.search( + r"\b(?:bien joué|bravo|top|chapeau|impressionnant|pas mal|bien fait|beau travail|good job|nice|trop bien|magnifique)\b", + query + ): + return "compliment" + + # Humour / café (fallback small_talk) + return "humor" + def _handle_unknown( self, intent: ParsedIntent,