–– coding: utf-8 ––
"""
MIRA — Noyau Phase 2
Fichier : noyau_phase2.py
Phase : 2 — Persistance SQLite branchée sur le noyau
Date : 18/10/2026
Nouveautés par rapport à noyau_minimal.py :
- Initialisation des deux bases SQLite au démarrage
- _enregistrer_historique() écrit dans historique.db
- M2_historique rechargé depuis historique.db au démarrage
- Identité MIRA-0001 définie dans utilisateur.db
- tour_num lu depuis MAX(tour) dans historique.db
(les numéros de tour ne repartent pas de 1 à chaque session)
Corrections v2 :
- import json retiré (inutile)
- tour_num calculé depuis la base et non depuis M2_historique
- ERREUR_GESTIONNAIRES initialisée à "" pour éviter NameError
"""
import os
import sqlite3
import sys
from datetime import datetime, timezone
CHEMIN_NOYAU = os.path.dirname(os.path.abspath(file))
CHEMIN_DATA = "/mnt/sda1/home/MIRA_Project/data"
if CHEMIN_DATA not in sys.path:
sys.path.insert(0, CHEMIN_DATA)
ERREUR_GESTIONNAIRES = ""
try:
import gestionnaire_historique as gh
import gestionnaire_utilisateur as gu
GESTIONNAIRES_OK = True
except Exception as e:
GESTIONNAIRES_OK = False
ERREUR_GESTIONNAIRES = str(e)
def _lire_prochain_tour():
if not GESTIONNAIRES_OK:
return 1
try:
import sqlite3
connexion = sqlite3.connect(gh.CHEMIN_BASE)
curseur = connexion.cursor()
curseur.execute("SELECT MAX(tour) FROM echanges")
resultat = curseur.fetchone()
connexion.close()
if resultat and resultat[0] is not None:
return resultat[0] + 1
return 1
except Exception:
return 1
def initialiser_bases():
if not GESTIONNAIRES_OK:
print("ATTENTION : gestionnaires indisponibles — "
-
ERREUR_GESTIONNAIRES)
return Falsegh.initialiser()
gu.initialiser()identite = gu.lire_identite()
if identite is None:
gu.definir_identite("MIRA-0001", "createur")
print("Identité MIRA-0001 définie.")ok_h, err_h = gh.verifier_integrite()
ok_u, err_u = gu.verifier_integrite()if not ok_h:
print("ERREUR historique.db : " + str(err_h))
return False
if not ok_u:
print("ERREUR utilisateur.db : " + str(err_u))
return Falsereturn True
def charger_historique_depuis_base(limite=20):
if not GESTIONNAIRES_OK:
return []
echanges = gh.lire_historique_recent(limite)
historique = []
for e in echanges:
historique.append({
"tour" : e["tour"],
"horodatage" : e["horodatage"],
"question" : e["question"],
"reponse" : e["reponse"],
"source" : e["source"]
})
return historique
def _nouveau_contexte(question, historique=None):
return {
"M1_question" : question,
"M2_historique" : historique if historique else [],
"M3_intention" : None,
"M4_specialiste": None,
"M5_reponse" : None,
"M6_meta" : {
"source_reponse" : None,
"erreurs" : [],
"mode" : "normal"
}
}
def _detecter_intention(contexte):
q = contexte["M1_question"].lower()
if any(m in q for m in ["date", "jour", "heure", "aujourd"]):
contexte["M3_intention"] = "question_date"
elif any(m in q for m in ["qui t'a", "cree", "createur", "auteur"]):
contexte["M3_intention"] = "identite"
elif any(m in q for m in ["maintenance", "analyser", "rapport"]):
contexte["M3_intention"] = "maintenance"
else:
contexte["M3_intention"] = "inconnue"
return contexte
def _reponse_degradee(contexte):
intention = contexte["M3_intention"]
if intention == "question_date":
maintenant = datetime.now(timezone.utc)
contexte["M5_reponse"] = (
"Nous sommes le {}."
.format(maintenant.strftime("%d/%m/%Y à %Hh%M UTC"))
)
contexte["M6_meta"]["source_reponse"] = "degradee"
elif intention == "identite":
contexte["M5_reponse"] = (
"Je suis MIRA, conçue et façonnée "
"par Da Conceição Mario."
)
contexte["M6_meta"]["source_reponse"] = "degradee"
return contexte
def _reponse_factice(contexte):
if contexte["M5_reponse"] is None:
contexte["M5_reponse"] = (
"Je suppose mais je ne garantis pas cette réponse, "
"je n’ai pas accès au réseau."
)
contexte["M6_meta"]["source_reponse"] = "factice"
return contexte
def _enregistrer_historique(contexte):
tour_num = _lire_prochain_tour()
entree = {
"tour" : tour_num,
"horodatage" : datetime.now(timezone.utc).isoformat(),
"question" : contexte["M1_question"],
"reponse" : contexte["M5_reponse"],
"source" : contexte["M6_meta"]["source_reponse"]
}
contexte["M2_historique"].append(entree)
if GESTIONNAIRES_OK:
try:
gh.ajouter_echange(
tour_num,
contexte["M1_question"],
contexte["M5_reponse"],
contexte["M6_meta"]["source_reponse"]
)
except Exception as e:
contexte["M6_meta"]["erreurs"].append(
"historique.db : " + str(e)
)
return contexte
def executer(contexte):
try:
contexte = _detecter_intention(contexte)
contexte = _reponse_degradee(contexte)
contexte = _reponse_factice(contexte)
contexte = _enregistrer_historique(contexte)
except Exception as e:
contexte["M6_meta"]["erreurs"].append(str(e))
if contexte["M5_reponse"] is None:
contexte["M5_reponse"] = "Erreur interne dans le noyau."
contexte["M6_meta"]["source_reponse"] = "erreur"
return contexte
if name == "main":
print("=== MIRA — Noyau Phase 2 ===\n")
print("Initialisation des bases...")
ok = initialiser_bases()
if not ok:
print("Arrêt : bases inaccessibles.")
sys.exit(1)
print("Bases OK.\n")
historique = charger_historique_depuis_base(20)
print("Historique chargé : {} échange(s).\n".format(len(historique)))
questions = [
"quel jour sommes-nous ?",
"qui t'a créé ?",
"comment fonctionne Python ?"
]
for q in questions:
print("--- Question : " + q)
ctx = _nouveau_contexte(q, historique)
ctx = executer(ctx)
print("Réponse : " + str(ctx["M5_reponse"]))
print("Source : " + str(ctx["M6_meta"]["source_reponse"]))
print("Erreurs : " + str(ctx["M6_meta"]["erreurs"]))
historique = ctx["M2_historique"]
print()
print("--- Historique final ---")
for e in historique[-3:]:
print("{} — {} → {}".format(
e["tour"], e["question"][:30], e["source"]))
print("\nTest terminé.")