diff --git a/app.py b/app.py index a35abe0..30333e2 100644 --- a/app.py +++ b/app.py @@ -71,6 +71,7 @@ Si une phrase contient plusieurs choses a enregistrer, utilise : {"actions": [{...}, {...}]} Quand l'utilisateur demande ce que tu sais d'un client, d'un projet, d'une tache ou d'un depot, utilise chercher_memoire. +Si l'utilisateur dit "pour CLIENT" en ajoutant une tache, renseigne toujours le champ client avec CLIENT. Pour tout le reste, reponds en francais naturel, avec des phrases courtes. N'utilise pas d'anglais sauf si l'utilisateur le demande explicitement. @@ -186,13 +187,21 @@ def detecter_action_directe(texte): { "action": "ajouter_client", "nom": nom, - "notes": "Ajoute depuis une liste dictee par Laurent.", + "notes": "Ajoute depuis une liste fournie par Laurent.", "statut": "actif", } for nom in clients_a_ajouter ] } + tache_client = detecter_tache_client(texte_nettoye) + if tache_client: + return tache_client + + recherche_taches = detecter_recherche_taches(texte_nettoye) + if recherche_taches: + return recherche_taches + recherche_match = re.search( r"(?:qu(?:'| )?est[- ]?ce que tu sais sur|que sais[- ]?tu sur|cherche dans la memoire|memoire sur)\s+(.+)", texte_nettoye, @@ -261,6 +270,45 @@ def detecter_action_directe(texte): return {"actions": actions} +def detecter_tache_client(texte): + if not re.search(r"\b(note|notes|noter|tache|doit|dois|a faire|à faire)\b", texte, flags=re.IGNORECASE): + return None + + match = re.search( + r"\bpour\s+(?:mon\s+client\s+|le\s+client\s+)?([A-Z0-9][A-Z0-9&.\- ]{1,40}?)[,\s]+(?:on\s+)?(?:doit|dois|devra|faut)\s+(.+?)(?:\s+tu\s+peux\s+noter.*|\s+note.*|\s+notes.*|\s*$)", + texte, + flags=re.IGNORECASE, + ) + if not match: + return None + + client_nom = nettoyer_nom_client(match.group(1)) + titre = nettoyer_titre_tache(match.group(2)) + if not client_nom or not titre: + return None + + return { + "action": "ajouter_tache", + "titre": titre, + "client": client_nom, + "details": texte, + } + + +def detecter_recherche_taches(texte): + match = re.search( + r"\b(?:que\s+dois[- ]?je\s+faire|quoi\s+faire|taches?|a faire|à faire)\b.*\b(?:pour|sur)\s+(?:mon\s+client\s+|le\s+client\s+)?([A-Z0-9][A-Z0-9&.\- ]{1,40})", + texte, + flags=re.IGNORECASE, + ) + if not match: + return None + client_nom = nettoyer_nom_client(match.group(1)) + if not client_nom: + return None + return {"action": "chercher_memoire", "requete": client_nom} + + def extraire_liste_clients(texte): if not re.search(r"\bclients?\b", texte, flags=re.IGNORECASE): return [] @@ -316,6 +364,13 @@ def nettoyer_nom_client(nom): return nom +def nettoyer_titre_tache(titre): + titre = titre.strip(" -\t\r.,;:?") + titre = re.sub(r"^de\s+", "", titre, flags=re.IGNORECASE) + titre = re.sub(r"\s+", " ", titre) + return titre[:1].upper() + titre[1:] if titre else "" + + def transcrire_audio(fichier): suffix = Path(fichier.filename or "voice.webm").suffix or ".webm" with tempfile.NamedTemporaryFile(delete=False, suffix=suffix) as tmp: diff --git a/memory.py b/memory.py index 3d284eb..d33e998 100644 --- a/memory.py +++ b/memory.py @@ -245,21 +245,34 @@ def add_memory(content, kind="note", subject="", client_name="", project_name="" def search_memory(query="", limit=12): query = clean_text(query) like = f"%{query}%" + search_long_text = int(len(query) > 4) with connect() as db: if query: clients = db.execute( - "SELECT * FROM clients WHERE name LIKE ? OR notes LIKE ? ORDER BY updated_at DESC LIMIT ?", - (like, like, limit), + """ + SELECT * FROM clients + WHERE name LIKE ? OR (? = 1 AND notes LIKE ?) + ORDER BY + CASE WHEN name = ? COLLATE NOCASE THEN 0 ELSE 1 END, + updated_at DESC + LIMIT ? + """, + (like, search_long_text, like, query, limit), ).fetchall() projects = db.execute( """ SELECT p.*, c.name AS client_name FROM projects p LEFT JOIN clients c ON c.id = p.client_id - WHERE p.name LIKE ? OR p.summary LIKE ? OR p.next_action LIKE ? OR c.name LIKE ? - ORDER BY p.updated_at DESC LIMIT ? + WHERE p.name LIKE ? + OR c.name LIKE ? + OR (? = 1 AND (p.summary LIKE ? OR p.next_action LIKE ?)) + ORDER BY + CASE WHEN p.name = ? COLLATE NOCASE OR c.name = ? COLLATE NOCASE THEN 0 ELSE 1 END, + p.updated_at DESC + LIMIT ? """, - (like, like, like, like, limit), + (like, like, search_long_text, like, like, query, query, limit), ).fetchall() tasks = db.execute( """ @@ -268,9 +281,12 @@ def search_memory(query="", limit=12): LEFT JOIN clients c ON c.id = t.client_id LEFT JOIN projects p ON p.id = t.project_id WHERE t.done = 0 AND (t.title LIKE ? OR t.details LIKE ? OR c.name LIKE ? OR p.name LIKE ?) - ORDER BY t.created_at DESC LIMIT ? + ORDER BY + CASE WHEN c.name = ? COLLATE NOCASE OR p.name = ? COLLATE NOCASE THEN 0 ELSE 1 END, + t.created_at DESC + LIMIT ? """, - (like, like, like, like, limit), + (like, like, like, like, query, query, limit), ).fetchall() repos = db.execute( """ @@ -278,9 +294,12 @@ def search_memory(query="", limit=12): FROM repositories r LEFT JOIN projects p ON p.id = r.project_id WHERE r.name LIKE ? OR r.local_path LIKE ? OR r.remote_url LIKE ? OR p.name LIKE ? - ORDER BY r.updated_at DESC LIMIT ? + ORDER BY + CASE WHEN r.name = ? COLLATE NOCASE OR p.name = ? COLLATE NOCASE THEN 0 ELSE 1 END, + r.updated_at DESC + LIMIT ? """, - (like, like, like, like, limit), + (like, like, like, like, query, query, limit), ).fetchall() notes = db.execute( """ @@ -288,10 +307,12 @@ def search_memory(query="", limit=12): FROM memories m LEFT JOIN clients c ON c.id = m.client_id LEFT JOIN projects p ON p.id = m.project_id - WHERE m.subject LIKE ? OR m.content LIKE ? OR c.name LIKE ? OR p.name LIKE ? + WHERE c.name LIKE ? + OR p.name LIKE ? + OR (? = 1 AND (m.subject LIKE ? OR m.content LIKE ?)) ORDER BY m.created_at DESC LIMIT ? """, - (like, like, like, like, limit), + (like, like, search_long_text, like, like, limit), ).fetchall() else: clients = db.execute("SELECT * FROM clients ORDER BY updated_at DESC LIMIT ?", (limit,)).fetchall()