–– coding: utf-8 ––
"""
MIRA — Gestionnaire de la connaissance utilisateur
Fichier : gestionnaire_utilisateur.py
Base : /mnt/sda1/MIRA_Project/data/utilisateur.db
Phase : 1 — Persistance
Décisions retenues :
- Base séparée de historique.db (B1)
- MIRA observe et retient automatiquement (Q4)
- L’utilisateur peut corriger/oublier à tout moment (Q4)
- Deux niveaux : autonome (Niveau 2) et validation créateur (Niveau 1)
- Protection des données : jamais partagées sans accord (D12)
- Référence unique par instance MIRA (D4)
"""
import sqlite3
import os
from datetime import datetime, timezone
CHEMIN_BASE = "/mnt/sda1/MIRA_Project/data/utilisateur.db"
def initialiser():
dossier = os.path.dirname(CHEMIN_BASE)
if dossier and not os.path.exists(dossier):
os.makedirs(dossier)
connexion = sqlite3.connect(CHEMIN_BASE)
curseur = connexion.cursor()
curseur.execute("""
CREATE TABLE IF NOT EXISTS preferences (
id INTEGER PRIMARY KEY AUTOINCREMENT,
cle TEXT NOT NULL UNIQUE,
valeur TEXT NOT NULL,
source TEXT NOT NULL DEFAULT 'observe',
horodatage TEXT NOT NULL,
actif INTEGER NOT NULL DEFAULT 1
)
""")
curseur.execute("""
CREATE TABLE IF NOT EXISTS sujets (
id INTEGER PRIMARY KEY AUTOINCREMENT,
sujet TEXT NOT NULL UNIQUE,
nombre_mentions INTEGER NOT NULL DEFAULT 1,
premier_mention TEXT NOT NULL,
dernier_mention TEXT NOT NULL
)
""")
curseur.execute("""
CREATE TABLE IF NOT EXISTS corrections (
id INTEGER PRIMARY KEY AUTOINCREMENT,
horodatage TEXT NOT NULL,
contexte TEXT NOT NULL,
erreur TEXT NOT NULL,
correction TEXT NOT NULL
)
""")
curseur.execute("""
CREATE TABLE IF NOT EXISTS surveillances (
id INTEGER PRIMARY KEY AUTOINCREMENT,
horodatage TEXT NOT NULL,
sujet TEXT NOT NULL,
parametres TEXT,
statut TEXT NOT NULL DEFAULT 'actif',
dernier_rap TEXT
)
""")
curseur.execute("""
CREATE TABLE IF NOT EXISTS identite (
id INTEGER PRIMARY KEY CHECK (id = 1),
reference TEXT NOT NULL,
type_mira TEXT NOT NULL DEFAULT 'createur',
nom_client TEXT,
horodatage TEXT NOT NULL
)
""")
connexion.commit()
connexion.close()
def definir_identite(reference, type_mira="createur", nom_client=None):
horodatage = datetime.now(timezone.utc).isoformat()
connexion = sqlite3.connect(CHEMIN_BASE)
curseur = connexion.cursor()
curseur.execute("""
INSERT INTO identite (id, reference, type_mira, nom_client, horodatage)
VALUES (1, ?, ?, ?, ?)
ON CONFLICT(id) DO UPDATE SET
reference = excluded.reference,
type_mira = excluded.type_mira,
nom_client = excluded.nom_client,
horodatage = excluded.horodatage
""", (reference, type_mira, nom_client, horodatage))
connexion.commit()
connexion.close()
def lire_identite():
connexion = sqlite3.connect(CHEMIN_BASE)
curseur = connexion.cursor()
curseur.execute("""
SELECT reference, type_mira, nom_client, horodatage
FROM identite WHERE id = 1
""")
ligne = curseur.fetchone()
connexion.close()
if ligne:
return {
"reference" : ligne[0],
"type_mira" : ligne[1],
"nom_client" : ligne[2],
"horodatage" : ligne[3]
}
return None
def enregistrer_preference(cle, valeur, source="observe"):
horodatage = datetime.now(timezone.utc).isoformat()
connexion = sqlite3.connect(CHEMIN_BASE)
curseur = connexion.cursor()
curseur.execute("""
INSERT INTO preferences (cle, valeur, source, horodatage, actif)
VALUES (?, ?, ?, ?, 1)
ON CONFLICT(cle) DO UPDATE SET
valeur = excluded.valeur,
source = excluded.source,
horodatage = excluded.horodatage,
actif = 1
""", (cle, valeur, source, horodatage))
connexion.commit()
connexion.close()
def lire_preference(cle):
connexion = sqlite3.connect(CHEMIN_BASE)
curseur = connexion.cursor()
curseur.execute("""
SELECT valeur, source FROM preferences
WHERE cle = ? AND actif = 1
""", (cle,))
ligne = curseur.fetchone()
connexion.close()
if ligne:
return {"valeur": ligne[0], "source": ligne[1]}
return None
def lire_toutes_preferences():
connexion = sqlite3.connect(CHEMIN_BASE)
curseur = connexion.cursor()
curseur.execute("""
SELECT cle, valeur, source, horodatage
FROM preferences WHERE actif = 1
ORDER BY cle ASC
""")
lignes = curseur.fetchall()
connexion.close()
return [
{
"cle" : ligne[0],
"valeur" : ligne[1],
"source" : ligne[2],
"horodatage" : ligne[3]
}
for ligne in lignes
]
def oublier_preference(cle):
connexion = sqlite3.connect(CHEMIN_BASE)
curseur = connexion.cursor()
curseur.execute("""
UPDATE preferences SET actif = 0 WHERE cle = ?
""", (cle,))
connexion.commit()
connexion.close()
def mentionner_sujet(sujet):
maintenant = datetime.now(timezone.utc).isoformat()
connexion = sqlite3.connect(CHEMIN_BASE)
curseur = connexion.cursor()
curseur.execute("""
INSERT INTO sujets (sujet, nombre_mentions, premier_mention, dernier_mention)
VALUES (?, 1, ?, ?)
ON CONFLICT(sujet) DO UPDATE SET
nombre_mentions = nombre_mentions + 1,
dernier_mention = excluded.dernier_mention
""", (sujet, maintenant, maintenant))
connexion.commit()
connexion.close()
def lire_sujets_frequents(limite=10):
connexion = sqlite3.connect(CHEMIN_BASE)
curseur = connexion.cursor()
curseur.execute("""
SELECT sujet, nombre_mentions, premier_mention, dernier_mention
FROM sujets
ORDER BY nombre_mentions DESC
LIMIT ?
""", (limite,))
lignes = curseur.fetchall()
connexion.close()
return [
{
"sujet" : ligne[0],
"nombre_mentions" : ligne[1],
"premier_mention" : ligne[2],
"dernier_mention" : ligne[3]
}
for ligne in lignes
]
def enregistrer_correction(contexte, erreur, correction):
horodatage = datetime.now(timezone.utc).isoformat()
connexion = sqlite3.connect(CHEMIN_BASE)
curseur = connexion.cursor()
curseur.execute("""
INSERT INTO corrections (horodatage, contexte, erreur, correction)
VALUES (?, ?, ?, ?)
""", (horodatage, contexte, erreur, correction))
connexion.commit()
connexion.close()
def lire_corrections_recentes(limite=10):
connexion = sqlite3.connect(CHEMIN_BASE)
curseur = connexion.cursor()
curseur.execute("""
SELECT horodatage, contexte, erreur, correction
FROM corrections
ORDER BY id DESC
LIMIT ?
""", (limite,))
lignes = curseur.fetchall()
connexion.close()
return [
{
"horodatage" : ligne[0],
"contexte" : ligne[1],
"erreur" : ligne[2],
"correction" : ligne[3]
}
for ligne in lignes
]
def ajouter_surveillance(sujet, parametres=None):
horodatage = datetime.now(timezone.utc).isoformat()
connexion = sqlite3.connect(CHEMIN_BASE)
curseur = connexion.cursor()
curseur.execute("""
INSERT INTO surveillances (horodatage, sujet, parametres, statut)
VALUES (?, ?, ?, 'actif')
""", (horodatage, sujet, parametres))
connexion.commit()
connexion.close()
def lire_surveillances_actives():
connexion = sqlite3.connect(CHEMIN_BASE)
curseur = connexion.cursor()
curseur.execute("""
SELECT id, horodatage, sujet, parametres, dernier_rap
FROM surveillances
WHERE statut = 'actif'
ORDER BY id ASC
""")
lignes = curseur.fetchall()
connexion.close()
return [
{
"id" : ligne[0],
"horodatage" : ligne[1],
"sujet" : ligne[2],
"parametres" : ligne[3],
"dernier_rap" : ligne[4]
}
for ligne in lignes
]
def mettre_a_jour_rapport_surveillance(id_surveillance):
maintenant = datetime.now(timezone.utc).isoformat()
connexion = sqlite3.connect(CHEMIN_BASE)
curseur = connexion.cursor()
curseur.execute("""
UPDATE surveillances SET dernier_rap = ?
WHERE id = ?
""", (maintenant, id_surveillance))
connexion.commit()
connexion.close()
def arreter_surveillance(id_surveillance):
connexion = sqlite3.connect(CHEMIN_BASE)
curseur = connexion.cursor()
curseur.execute("""
UPDATE surveillances SET statut = 'termine'
WHERE id = ?
""", (id_surveillance,))
connexion.commit()
connexion.close()
def verifier_integrite():
try:
if not os.path.exists(CHEMIN_BASE):
return True, None
connexion = sqlite3.connect(CHEMIN_BASE)
curseur = connexion.cursor()
curseur.execute("PRAGMA integrity_check")
resultat = curseur.fetchone()
connexion.close()
if resultat and resultat[0] == "ok":
return True, None
else:
return False, "Résultat integrity_check : {}".format(resultat)
except Exception as e:
return False, str(e)
if name == "main":
print("Initialisation de utilisateur.db…")
initialiser()
ok, erreur = verifier_integrite()
if ok:
print("Base utilisateur : OK")
else:
print("ERREUR base utilisateur : {}".format(erreur))
definir_identite("MIRA-0001", "createur")
identite = lire_identite()
print("Identité : {} ({})".format(identite["reference"], identite["type_mira"]))
enregistrer_preference("langue", "français", "observe")
enregistrer_preference("longueur_reponse", "courte", "declare")
prefs = lire_toutes_preferences()
print("Préférences ({}) :".format(len(prefs)))
for p in prefs:
print(" {} = {} [{}]".format(p["cle"], p["valeur"], p["source"]))
mentionner_sujet("MIRA")
mentionner_sujet("Tiny Core")
mentionner_sujet("MIRA")
sujets = lire_sujets_frequents(5)
print("Sujets fréquents ({}) :".format(len(sujets)))
for s in sujets:
print(" {} — {} mention(s)".format(s["sujet"], s["nombre_mentions"]))
print("Test terminé.")