gestionnaire_utilisateur.py — connaissance utilisateur SQLite Phase 1 (18/10/2026)

–– 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é.")

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Défiler vers le haut