–– coding: utf-8 ––
"""
MIRA — Outils déterministes
Fichier : outils.py
Phase : 3 — Outils déterministes branchés sur le noyau
Date : 18/10/2026
Rôle :
Fournir des réponses directes et fiables pour les intentions
qui ne nécessitent pas Phi-4 Mini (date, calcul, état système).
Appelé par noyau_phase3.py via executer_outil(intention, question).
Retourne :
- Une chaîne de caractères si l’outil couvre l’intention
- None si l’intention n’est pas couverte (le noyau continue)
"""
import os
import re
import shutil
from datetime import datetime, timezone
———————————————————-
JOURS ET MOIS EN FRANÇAIS
———————————————————-
JOURS_FR = {
0: "lundi", 1: "mardi", 2: "mercredi", 3: "jeudi",
4: "vendredi", 5: "samedi", 6: "dimanche"
}
MOIS_FR = {
1: "janvier", 2: "février", 3: "mars", 4: "avril",
5: "mai", 6: "juin", 7: "juillet", 8: "août",
9: "septembre", 10: "octobre", 11: "novembre", 12: "décembre"
}
==========================================================
OUTIL : DATE ET HEURE
==========================================================
def outil_date_heure(question):
"""
Répond aux questions sur la date et/ou l’heure.
Utilise l’horloge locale de la VM.
"""
maintenant = datetime.now()
q = question.lower()
jour_nom = JOURS_FR[maintenant.weekday()]
jour_num = maintenant.day
mois_nom = MOIS_FR[maintenant.month]
annee = maintenant.year
heure_str = maintenant.strftime("%H h %M")
if any(m in q for m in ["heure", "temps", "maintenant"]):
if any(m in q for m in ["date", "jour", "aujourd"]):
return (
"Nous sommes le {} {} {} {}, il est {}.".format(
jour_nom, jour_num, mois_nom, annee, heure_str
)
)
return "Il est {}.".format(heure_str)
return (
"Nous sommes le {} {} {} {}.".format(
jour_nom, jour_num, mois_nom, annee
)
)
==========================================================
OUTIL : CALCUL
==========================================================
def outil_calcul(question):
"""
Évalue une expression mathématique simple extraite de la question.
Opérations supportées : + – * / * ( )
Refuse toute expression non numérique (sécurité).
"""
expression = re.sub(r"[^0-9+-/().,%\s]", "", question)
expression = expression.replace(",", ".").strip()
if not expression:
return "Je n'ai pas trouvé d'expression à calculer dans ta question."
if re.search(r"[a-zA-Z_]", expression):
return "Je ne peux calculer que des expressions numériques simples."
try:
resultat = eval(expression, {"__builtins__": {}})
if isinstance(resultat, float):
if resultat == int(resultat):
resultat = int(resultat)
else:
resultat = round(resultat, 6)
return "{} = {}".format(expression, resultat)
except ZeroDivisionError:
return "Division par zéro impossible."
except Exception:
return "Je n'ai pas pu calculer cette expression."
==========================================================
OUTIL : ÉTAT SYSTÈME
==========================================================
def outil_etat_systeme(question):
"""
Retourne des informations basiques sur l’état du système :
espace disque, mémoire disponible (via /proc/meminfo).
"""
lignes = []
try:
total, utilise, libre = shutil.disk_usage("/")
lignes.append("Disque / : {:.1f} Go total, {:.1f} Go libres.".format(
total / 1_073_741_824,
libre / 1_073_741_824
))
except Exception as e:
lignes.append("Disque : information indisponible ({}).".format(e))
try:
meminfo = {}
with open("/proc/meminfo", "r") as f:
for ligne in f:
cles = ligne.split()
if len(cles) >= 2:
meminfo[cles[0].rstrip(":")] = int(cles[1])
total_ram = meminfo.get("MemTotal", 0) // 1024
libre_ram = meminfo.get("MemAvailable", 0) // 1024
lignes.append("RAM : {} Mo total, {} Mo disponibles.".format(
total_ram, libre_ram
))
except Exception as e:
lignes.append("RAM : information indisponible ({}).".format(e))
try:
with open("/proc/loadavg", "r") as f:
load = f.read().split()
lignes.append("Charge CPU (1 min) : {}.".format(load[0]))
except Exception as e:
lignes.append("CPU : information indisponible ({}).".format(e))
if lignes:
return "État du système :\n" + "\n".join(" - " + l for l in lignes)
return "Impossible de lire l'état du système."
==========================================================
POINT D’ENTRÉE PRINCIPAL
==========================================================
def executer_outil(intention, question):
"""
Appelée par noyau_phase3.py.
Retourne une réponse (str) si l’intention est couverte,
None sinon (le noyau passe à l’étape suivante).
"""
if intention == "question_date":
return outil_date_heure(question)
if intention == "calcul":
return outil_calcul(question)
if intention == "etat_systeme":
return outil_etat_systeme(question)
return None
==========================================================
TEST AUTONOME
==========================================================
if name == "main":
print("=== TEST outils.py ===\n")
tests = [
("question_date", "quel jour sommes-nous ?"),
("question_date", "quelle heure est-il ?"),
("calcul", "combien font 15 * 6 ?"),
("calcul", "calcule 100 / 4 + 3"),
("calcul", "combien font 2 ** 10 ?"),
("etat_systeme", "quel est l'état du système ?"),
("inconnue", "comment fonctionne Python ?"),
]
for intention, question in tests:
reponse = executer_outil(intention, question)
print("Intention : {}".format(intention))
print("Question : {}".format(question))
print("Réponse : {}".format(reponse))
print()
print("=== TEST TERMINÉ ===")