Inject context
This commit is contained in:
97
app.py
97
app.py
@@ -16,7 +16,9 @@ from memory import (
|
|||||||
add_repository,
|
add_repository,
|
||||||
add_task,
|
add_task,
|
||||||
close_task,
|
close_task,
|
||||||
|
get_memory_snapshot,
|
||||||
init_db,
|
init_db,
|
||||||
|
list_clients,
|
||||||
search_memory,
|
search_memory,
|
||||||
upsert_client,
|
upsert_client,
|
||||||
upsert_project,
|
upsert_project,
|
||||||
@@ -69,6 +71,7 @@ Actions disponibles :
|
|||||||
{"action": "ajouter_repo", "nom": "...", "projet": "...", "chemin": "...", "url": "...", "branche": "..."}
|
{"action": "ajouter_repo", "nom": "...", "projet": "...", "chemin": "...", "url": "...", "branche": "..."}
|
||||||
{"action": "ajouter_note", "contenu": "...", "sujet": "...", "client": "...", "projet": "...", "type": "note"}
|
{"action": "ajouter_note", "contenu": "...", "sujet": "...", "client": "...", "projet": "...", "type": "note"}
|
||||||
{"action": "chercher_memoire", "requete": "..."}
|
{"action": "chercher_memoire", "requete": "..."}
|
||||||
|
{"action": "lister_clients"}
|
||||||
|
|
||||||
Si une phrase contient plusieurs choses a enregistrer, utilise :
|
Si une phrase contient plusieurs choses a enregistrer, utilise :
|
||||||
{"actions": [{...}, {...}]}
|
{"actions": [{...}, {...}]}
|
||||||
@@ -96,10 +99,66 @@ def sauvegarder_contacts(contacts):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def construire_system_prompt():
|
def construire_system_prompt(session_id=None):
|
||||||
contacts = charger_contacts()
|
contacts = charger_contacts()
|
||||||
lignes = [f"- {nom.title()} : {email}" for nom, email in contacts.items()]
|
lignes = [f"- {nom.title()} : {email}" for nom, email in contacts.items()]
|
||||||
return SYSTEM_PROMPT + "\n\nContacts connus :\n" + "\n".join(lignes)
|
return (
|
||||||
|
SYSTEM_PROMPT
|
||||||
|
+ "\n\nContacts connus :\n"
|
||||||
|
+ "\n".join(lignes)
|
||||||
|
+ "\n\nMemoire professionnelle actuelle :\n"
|
||||||
|
+ construire_contexte_memoire(session_id)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def construire_contexte_memoire(session_id=None):
|
||||||
|
snapshot = get_memory_snapshot()
|
||||||
|
contexte = session_contexts.get(session_id or "", {})
|
||||||
|
lignes = []
|
||||||
|
|
||||||
|
clients_mem = snapshot["clients"]
|
||||||
|
if clients_mem:
|
||||||
|
lignes.append("Clients connus et taches ouvertes :")
|
||||||
|
for client_mem in clients_mem:
|
||||||
|
lignes.append(f"- {client_mem['name']} : {client_mem['open_task_count']} tache(s) ouverte(s)")
|
||||||
|
else:
|
||||||
|
lignes.append("Aucun client connu.")
|
||||||
|
|
||||||
|
if snapshot["tasks"]:
|
||||||
|
lignes.append("Taches ouvertes recentes :")
|
||||||
|
for tache in snapshot["tasks"][:15]:
|
||||||
|
sujet = tache.get("client_name") or tache.get("project_name") or "general"
|
||||||
|
lignes.append(f"- #{tache['id']} {sujet} : {tache['title']}")
|
||||||
|
|
||||||
|
if snapshot["projects"]:
|
||||||
|
lignes.append("Projets recents :")
|
||||||
|
for projet in snapshot["projects"][:10]:
|
||||||
|
client_nom = projet.get("client_name") or "sans client"
|
||||||
|
statut = projet.get("status") or "actif"
|
||||||
|
lignes.append(f"- {projet['name']} ({client_nom}) : {statut}")
|
||||||
|
|
||||||
|
if snapshot["repositories"]:
|
||||||
|
lignes.append("Depots Git associes :")
|
||||||
|
for repo in snapshot["repositories"][:10]:
|
||||||
|
cible = repo.get("project_name") or "sans projet"
|
||||||
|
chemin = repo.get("local_path") or repo.get("remote_url") or "chemin non renseigne"
|
||||||
|
lignes.append(f"- {repo['name']} -> {cible} : {chemin}")
|
||||||
|
|
||||||
|
if contexte:
|
||||||
|
lignes.append("Contexte de la conversation en cours :")
|
||||||
|
if contexte.get("last_client"):
|
||||||
|
lignes.append(f"- dernier client mentionne : {contexte['last_client']}")
|
||||||
|
if contexte.get("last_project"):
|
||||||
|
lignes.append(f"- dernier projet mentionne : {contexte['last_project']}")
|
||||||
|
if contexte.get("tasks"):
|
||||||
|
ids = ", ".join(f"#{tache['id']} {tache['title']}" for tache in contexte["tasks"][:5])
|
||||||
|
lignes.append(f"- dernieres taches affichees : {ids}")
|
||||||
|
|
||||||
|
lignes.append(
|
||||||
|
"Utilise ce contexte pour repondre aux questions globales. "
|
||||||
|
"Pour modifier la memoire, reponds avec une action JSON."
|
||||||
|
)
|
||||||
|
return "\n".join(lignes)
|
||||||
|
|
||||||
|
|
||||||
def resoudre_contact(destinataire):
|
def resoudre_contact(destinataire):
|
||||||
@@ -132,6 +191,7 @@ ACTIONS = {
|
|||||||
"ajouter_repo",
|
"ajouter_repo",
|
||||||
"ajouter_note",
|
"ajouter_note",
|
||||||
"chercher_memoire",
|
"chercher_memoire",
|
||||||
|
"lister_clients",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -171,7 +231,7 @@ def demander_au_llm(session_id, texte):
|
|||||||
|
|
||||||
reponse = client.chat.completions.create(
|
reponse = client.chat.completions.create(
|
||||||
model=CHAT_MODEL,
|
model=CHAT_MODEL,
|
||||||
messages=[{"role": "system", "content": construire_system_prompt()}] + historique,
|
messages=[{"role": "system", "content": construire_system_prompt(session_id)}] + historique,
|
||||||
temperature=0.45,
|
temperature=0.45,
|
||||||
max_tokens=900,
|
max_tokens=900,
|
||||||
)
|
)
|
||||||
@@ -221,8 +281,8 @@ def detecter_action_directe(texte, session_id=None):
|
|||||||
"requete": recherche_match.group(1).strip(" ?.,;:"),
|
"requete": recherche_match.group(1).strip(" ?.,;:"),
|
||||||
}
|
}
|
||||||
|
|
||||||
if re.search(r"\b(liste|affiche|montre)\b.*\bclients?\b", texte_min):
|
if detecter_liste_clients_demandee(texte_min):
|
||||||
return {"action": "chercher_memoire", "requete": ""}
|
return {"action": "lister_clients"}
|
||||||
|
|
||||||
if re.search(r"\b(liste|affiche|montre)\b.*\b(projets?|taches?|repos?|depots?)\b", texte_min):
|
if re.search(r"\b(liste|affiche|montre)\b.*\b(projets?|taches?|repos?|depots?)\b", texte_min):
|
||||||
return {"action": "chercher_memoire", "requete": ""}
|
return {"action": "chercher_memoire", "requete": ""}
|
||||||
@@ -351,6 +411,18 @@ def detecter_suppression_tache(texte, session_id):
|
|||||||
return {"action": "terminer_tache", "id": task_id}
|
return {"action": "terminer_tache", "id": task_id}
|
||||||
|
|
||||||
|
|
||||||
|
def detecter_liste_clients_demandee(texte_min):
|
||||||
|
if not re.search(r"\bclients?\b", texte_min):
|
||||||
|
return False
|
||||||
|
return bool(
|
||||||
|
re.search(r"\b(liste|affiche|montre|donne)\b.*\bclients?\b", texte_min)
|
||||||
|
or re.search(r"\bclients?\b.*\b(liste|affiche|montre|donne)\b", texte_min)
|
||||||
|
or re.search(r"\b(quels?|qui)\s+sont\b.*\bclients?\b", texte_min)
|
||||||
|
or re.search(r"\btous\s+mes\s+clients?\b", texte_min)
|
||||||
|
or re.search(r"\bmes\s+clients?\b", texte_min)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def extraire_liste_clients(texte):
|
def extraire_liste_clients(texte):
|
||||||
if not re.search(r"\bclients?\b", texte, flags=re.IGNORECASE):
|
if not re.search(r"\bclients?\b", texte, flags=re.IGNORECASE):
|
||||||
return []
|
return []
|
||||||
@@ -533,6 +605,14 @@ def executer_action(action):
|
|||||||
resultat = search_memory(action.get("requete", ""))
|
resultat = search_memory(action.get("requete", ""))
|
||||||
return formater_memoire(resultat), {"memoryRead": True, "memoryResult": resultat, "memoryQuery": action.get("requete", "")}
|
return formater_memoire(resultat), {"memoryRead": True, "memoryResult": resultat, "memoryQuery": action.get("requete", "")}
|
||||||
|
|
||||||
|
if nom_action == "lister_clients":
|
||||||
|
clients_mem = list_clients()
|
||||||
|
return formater_liste_clients(clients_mem), {
|
||||||
|
"memoryRead": True,
|
||||||
|
"memoryResult": {"clients": clients_mem, "projects": [], "tasks": [], "repositories": [], "memories": []},
|
||||||
|
"memoryQuery": "",
|
||||||
|
}
|
||||||
|
|
||||||
return "", {}
|
return "", {}
|
||||||
|
|
||||||
|
|
||||||
@@ -630,6 +710,13 @@ def formater_memoire(resultat):
|
|||||||
return "Voici ce que j'ai trouve :\n" + "\n".join(f"- {ligne}" for ligne in lignes[:10])
|
return "Voici ce que j'ai trouve :\n" + "\n".join(f"- {ligne}" for ligne in lignes[:10])
|
||||||
|
|
||||||
|
|
||||||
|
def formater_liste_clients(clients_mem):
|
||||||
|
if not clients_mem:
|
||||||
|
return "Je n'ai encore aucun client dans la memoire professionnelle."
|
||||||
|
noms = [client_mem["name"] for client_mem in clients_mem]
|
||||||
|
return "Voici tes clients :\n" + "\n".join(f"- {nom}" for nom in noms)
|
||||||
|
|
||||||
|
|
||||||
def traiter_message(session_id, texte, avec_audio=False):
|
def traiter_message(session_id, texte, avec_audio=False):
|
||||||
action_directe = detecter_action_directe(texte, session_id)
|
action_directe = detecter_action_directe(texte, session_id)
|
||||||
reponse = json.dumps(action_directe, ensure_ascii=False) if action_directe else demander_au_llm(session_id, texte)
|
reponse = json.dumps(action_directe, ensure_ascii=False) if action_directe else demander_au_llm(session_id, texte)
|
||||||
|
|||||||
63
memory.py
63
memory.py
@@ -195,6 +195,69 @@ def add_task(title, client_name="", project_name="", details="", due_at=""):
|
|||||||
return row_to_dict(db.execute("SELECT * FROM tasks WHERE id = ?", (cursor.lastrowid,)).fetchone())
|
return row_to_dict(db.execute("SELECT * FROM tasks WHERE id = ?", (cursor.lastrowid,)).fetchone())
|
||||||
|
|
||||||
|
|
||||||
|
def list_clients(limit=100):
|
||||||
|
with connect() as db:
|
||||||
|
rows = db.execute(
|
||||||
|
"SELECT * FROM clients ORDER BY name COLLATE NOCASE LIMIT ?",
|
||||||
|
(limit,),
|
||||||
|
).fetchall()
|
||||||
|
return [row_to_dict(row) for row in rows]
|
||||||
|
|
||||||
|
|
||||||
|
def get_memory_snapshot(limit=25):
|
||||||
|
with connect() as db:
|
||||||
|
clients = db.execute(
|
||||||
|
"""
|
||||||
|
SELECT c.*,
|
||||||
|
COUNT(t.id) AS open_task_count
|
||||||
|
FROM clients c
|
||||||
|
LEFT JOIN tasks t ON t.client_id = c.id AND t.done = 0
|
||||||
|
GROUP BY c.id
|
||||||
|
ORDER BY c.name COLLATE NOCASE
|
||||||
|
LIMIT ?
|
||||||
|
""",
|
||||||
|
(limit,),
|
||||||
|
).fetchall()
|
||||||
|
tasks = db.execute(
|
||||||
|
"""
|
||||||
|
SELECT t.*, c.name AS client_name, p.name AS project_name
|
||||||
|
FROM tasks t
|
||||||
|
LEFT JOIN clients c ON c.id = t.client_id
|
||||||
|
LEFT JOIN projects p ON p.id = t.project_id
|
||||||
|
WHERE t.done = 0
|
||||||
|
ORDER BY t.created_at DESC
|
||||||
|
LIMIT ?
|
||||||
|
""",
|
||||||
|
(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
|
||||||
|
ORDER BY p.updated_at DESC
|
||||||
|
LIMIT ?
|
||||||
|
""",
|
||||||
|
(limit,),
|
||||||
|
).fetchall()
|
||||||
|
repos = db.execute(
|
||||||
|
"""
|
||||||
|
SELECT r.*, p.name AS project_name
|
||||||
|
FROM repositories r
|
||||||
|
LEFT JOIN projects p ON p.id = r.project_id
|
||||||
|
ORDER BY r.updated_at DESC
|
||||||
|
LIMIT ?
|
||||||
|
""",
|
||||||
|
(limit,),
|
||||||
|
).fetchall()
|
||||||
|
return {
|
||||||
|
"clients": [row_to_dict(row) for row in clients],
|
||||||
|
"tasks": [row_to_dict(row) for row in tasks],
|
||||||
|
"projects": [row_to_dict(row) for row in projects],
|
||||||
|
"repositories": [row_to_dict(row) for row in repos],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def close_task(task_id):
|
def close_task(task_id):
|
||||||
with connect() as db:
|
with connect() as db:
|
||||||
row = db.execute(
|
row = db.execute(
|
||||||
|
|||||||
Reference in New Issue
Block a user