interface_demarrage.py — v2 (Linux, bug corrigé)

Bienvenue sur CFTPfr.fr Forums core interface_demarrage.py — v2 (Linux, bug corrigé)

  • Ce sujet est vide.
Affichage de 1 message (sur 1 au total)
  • Auteur
    Messages
  • #224
    Mario Da Conceicao
    Maître des clés

    Version corrigée du 25/07/2026 — étape 3 du portage Linux. Trois changements :

    1. Chemins calculés automatiquement (plus de "D:…" en dur)
    2. Remplacement des mécanismes Windows-only (STARTUPINFO, CREATE_NO_WINDOW) par un lancement de processus simple, qui fonctionne pareil sous Windows et Linux
    3. Utilise directement l’interpréteur Python en cours d’exécution (sys.executable) au lieu d’un chemin figé vers pythonw.exe — logique une fois qu’on n’aura plus WinPython embarqué

    ⚠️ Point non résolu, à valider avec toi : le bouton "Lancer l’IA" pointait par erreur vers mira_os.py. Or mira_ia.py (le vrai module IA) n’a pas d’écran à lui — c’est une brique utilisée en coulisse par mira_os.py et par ce fichier. En attendant qu’on décide ensemble s’il faut lui construire un écran propre, j’ai fait pointer ce bouton vers le chat (chat_ia.py), qui est la chose la plus proche d’"interagir avec l’IA" qui ait un vrai écran aujourd’hui. Dis-moi si tu préfères autre chose.

    import tkinter as tk
    from tkinter import messagebox, simpledialog
    from pathlib import Path
    import subprocess
    import sys
    import os
    import json
    import hashlib
    import secrets
    import importlib.util
    
    # --- CORRECTION 1 : chemins calculés automatiquement, plus de "D:\..." en dur ---
    BASE_DIR = Path(__file__).resolve().parent
    # CORRECTION 3 : on utilise l'interpréteur Python en cours d'exécution, plus de pythonw.exe figé
    PYTHON_EXE = Path(sys.executable)
    MIRA_OS_FILE = (BASE_DIR / "mira_os" / "mira_os.py").resolve()
    CHAT_FILE = (BASE_DIR / "mira_ai" / "chat_ia.py").resolve()
    USERS_FILE = (BASE_DIR / "mira_ai" / "utilisateurs.json").resolve()
    PLUGINS_DIR = (BASE_DIR / "mira_ai" / "plugins").resolve()
    CONFIG_FILE = (BASE_DIR / "mira_ai" / "config.json").resolve()
    MIRA_LANG_FILE = (BASE_DIR / "mira_lang" / "main.py").resolve()
    
    # --- Fonctions de hachage des mots de passe (inchangées, déjà correctes) ---
    def hacher_mot_de_passe(mot_de_passe: str) -> str:
        salt = secrets.token_hex(16)
        hash_mdp = hashlib.sha256((mot_de_passe + salt).encode("utf-8")).hexdigest()
        return f"{salt}:{hash_mdp}"
    
    def verifier_mot_de_passe(mot_de_passe: str, stocke: str) -> bool:
        try:
            salt, hash_stocke = stocke.split(":")
            return hashlib.sha256((mot_de_passe + salt).encode("utf-8")).hexdigest() == hash_stocke
        except Exception:
            return False
    
    class PluginManager:
        def __init__(self, plugins_dir=PLUGINS_DIR):
            self.plugins_dir = Path(plugins_dir)
            self.plugins = {}
            self.charger_plugins()
    
        def charger_plugins(self):
            self.plugins = {}
            if not self.plugins_dir.exists():
                self.plugins_dir.mkdir(parents=True, exist_ok=True)
                return
            for file in self.plugins_dir.glob("*.py"):
                if file.name.startswith("_"):
                    continue
                try:
                    spec = importlib.util.spec_from_file_location(file.stem, file)
                    module = importlib.util.module_from_spec(spec)
                    spec.loader.exec_module(module)
                    if hasattr(module, "INTENTION") and hasattr(module, "executer"):
                        self.plugins[module.INTENTION] = module
                except Exception as e:
                    print(f"Erreur chargement plugin {file.name}: {e}")
    
        def executer(self, intention, message, app):
            module = self.plugins.get(intention)
            if module:
                try:
                    return module.executer(message, app)
                except Exception as e:
                    return f"Erreur dans le plugin '{intention}': {e}"
            return None
    
    class InterfaceDemarrage:
        def __init__(self):
            self.fenetre = tk.Tk()
            self.fenetre.title("MIRA_OS - Centre de contrôle")
            self.fenetre.geometry("600x550")
    
            (BASE_DIR / "mira_ai").mkdir(parents=True, exist_ok=True)
            PLUGINS_DIR.mkdir(parents=True, exist_ok=True)
    
            self.verifier_utilisateurs_par_defaut()
            self.plugin_manager = PluginManager()
            self.creer_interface()
    
        def verifier_utilisateurs_par_defaut(self):
            if not USERS_FILE.exists():
                try:
                    with open(USERS_FILE, "w", encoding="utf-8") as f:
                        json.dump({
                            "utilisateurs": [
                                {"nom": "admin", "mot_de_passe": hacher_mot_de_passe("admin123"), "role": "administrateur"}
                            ]
                        }, f, indent=4, ensure_ascii=False)
                except Exception as e:
                    messagebox.showerror("Erreur", f"Impossible de créer le fichier: {e}")
    
        def creer_interface(self):
            tk.Label(self.fenetre, text="Bienvenue dans MIRA_OS", font=("Arial", 16, "bold")).pack(pady=10)
    
            frame_boutons = tk.Frame(self.fenetre)
            frame_boutons.pack(pady=20)
    
            boutons = [
                ("🖥️ Lancer MIRA_OS", self.lancer_mira_os, "#4CAF50", 0, 0),
                ("🤖 Lancer l'IA", self.lancer_ia, "#2196F3", 0, 1),
                ("💬 Chat avec l'IA", self.lancer_chat, "#FF9800", 0, 2),
                ("📘 Lancer MIRA_LANG", self.lancer_lang, "#3F51B5", 1, 0),
                ("🔄 Mise à jour", self.mise_a_jour_ia, "#17A2B8", 1, 1),
                ("👤 Gérer les utilisateurs", self.gerer_utilisateurs, "#9C27B0", 1, 2),
                ("🔌 Recharger plugins", self.recharger_plugins, "#607D8B", 2, 0)
            ]
    
            for texte, commande, couleur, row, col in boutons:
                tk.Button(
                    frame_boutons,
                    text=texte,
                    command=commande,
                    width=15,
                    height=3,
                    font=("Arial", 10, "bold"),
                    bg=couleur,
                    fg="white"
                ).grid(row=row, column=col, padx=10, pady=10)
    
            tk.Button(
                self.fenetre,
                text="❌ Quitter",
                command=self.quitter,
                width=10,
                height=2,
                font=("Arial", 10, "bold"),
                bg="#F44336",
                fg="white"
            ).pack(pady=20)
    
        def lancer_processus(self, fichier_py):
            """
            CORRECTION 2 : lancement de processus simplifié, sans STARTUPINFO ni
            CREATE_NO_WINDOW (mécanismes Windows-only). Fonctionne pareil sous
            Windows et Linux. Sur un système sans bureau, il n'y a de toute façon
            pas de fenêtre à cacher.
            """
            if not PYTHON_EXE.exists():
                messagebox.showerror("Erreur critique", f"Interpréteur Python introuvable :\n{PYTHON_EXE}")
                return
    
            if not fichier_py.exists():
                messagebox.showerror(
                    "Erreur critique",
                    f"Fichier introuvable.\n\nChemin attendu :\n{fichier_py}"
                )
                return
    
            try:
                process = subprocess.Popen(
                    [str(PYTHON_EXE), str(fichier_py)],
                    cwd=str(fichier_py.parent),
                    stdout=subprocess.PIPE,
                    stderr=subprocess.PIPE,
                    text=True
                )
    
                try:
                    stdout, stderr = process.communicate(timeout=1)
                    if process.returncode != 0:
                        messagebox.showerror(
                            "Erreur d'exécution",
                            f"Le script a échoué avec le code {process.returncode}.\n\n"
                            f"Erreur :\n{stderr}\n\nSortie :\n{stdout}\n\n"
                            f"Fichier : {fichier_py}"
                        )
                except subprocess.TimeoutExpired:
                    # Normal pour une interface graphique qui continue de tourner
                    pass
    
            except FileNotFoundError as e:
                messagebox.showerror("Erreur système", f"Fichier ou programme introuvable :\n{e}")
            except PermissionError as e:
                messagebox.showerror("Erreur de permissions", f"Permission refusée :\n{e}")
            except Exception as e:
                messagebox.showerror("Erreur inattendue", f"Impossible de lancer le processus :\n{e}")
    
        def lancer_mira_os(self):
            self.lancer_processus(MIRA_OS_FILE)
    
        def lancer_ia(self):
            # CORRECTION BUG : pointait par erreur vers MIRA_OS_FILE.
            # mira_ia.py n'a pas d'écran propre (voir note en tête de sujet) ;
            # on pointe vers le chat en attendant une décision sur ce point.
            self.lancer_processus(CHAT_FILE)
    
        def lancer_chat(self):
            self.lancer_processus(CHAT_FILE)
    
        def lancer_lang(self):
            self.lancer_processus(MIRA_LANG_FILE)
    
        def mise_a_jour_ia(self):
            nouveaux_plugins = self.plugin_manager.charger_plugins()
            if nouveaux_plugins:
                messagebox.showinfo("Mise à jour", f"Nouveaux plugins détectés :\n- " + "\n- ".join(nouveaux_plugins))
            else:
                messagebox.showinfo("Mise à jour", "Aucun nouveau plugin détecté.")
    
        def gerer_utilisateurs(self):
            nom = simpledialog.askstring("Connexion", "Nom d'utilisateur :")
            if not nom:
                return
            mot_de_passe = simpledialog.askstring("Connexion", "Mot de passe :", show="*")
            if not mot_de_passe:
                return
            if self.verifier_utilisateur(nom, mot_de_passe):
                self.fenetre_utilisateurs()
            else:
                messagebox.showerror("Erreur", "Nom d'utilisateur ou mot de passe incorrect.")
    
        def verifier_utilisateur(self, nom, mot_de_passe):
            if not USERS_FILE.exists():
                return False
            try:
                with open(USERS_FILE, "r", encoding="utf-8") as f:
                    data = json.load(f)
                for utilisateur in data.get("utilisateurs", []):
                    if utilisateur["nom"] == nom and verifier_mot_de_passe(mot_de_passe, utilisateur["mot_de_passe"]):
                        return True
                return False
            except Exception:
                return False
    
        def fenetre_utilisateurs(self):
            fenetre_users = tk.Toplevel(self.fenetre)
            fenetre_users.title("Gestion des utilisateurs")
            fenetre_users.geometry("400x300")
    
            tk.Button(
                fenetre_users, text="➕ Ajouter un utilisateur", command=self.ajouter_utilisateur,
                width=30, height=2, font=("Arial", 10, "bold"), bg="#4CAF50", fg="white"
            ).pack(pady=10)
    
            tk.Button(
                fenetre_users, text="➖ Supprimer un utilisateur", command=self.supprimer_utilisateur,
                width=30, height=2, font=("Arial", 10, "bold"), bg="#F44336", fg="white"
            ).pack(pady=10)
    
        def ajouter_utilisateur(self):
            nom = simpledialog.askstring("Nouvel utilisateur", "Nom :")
            if not nom:
                return
            mot_de_passe = simpledialog.askstring("Nouvel utilisateur", "Mot de passe :", show="*")
            if not mot_de_passe:
                return
            role = simpledialog.askstring("Nouvel utilisateur", "Rôle :", initialvalue="utilisateur") or "utilisateur"
    
            try:
                if USERS_FILE.exists():
                    with open(USERS_FILE, "r", encoding="utf-8") as f:
                        data = json.load(f)
                else:
                    data = {"utilisateurs": []}
    
                for u in data["utilisateurs"]:
                    if u["nom"] == nom:
                        messagebox.showerror("Erreur", f"L'utilisateur {nom} existe déjà !")
                        return
    
                data["utilisateurs"].append({
                    "nom": nom,
                    "mot_de_passe": hacher_mot_de_passe(mot_de_passe),
                    "role": role
                })
    
                with open(USERS_FILE, "w", encoding="utf-8") as f:
                    json.dump(data, f, indent=4, ensure_ascii=False)
    
                messagebox.showinfo("Succès", f"Utilisateur {nom} ajouté !")
            except Exception as e:
                messagebox.showerror("Erreur", f"Erreur: {e}")
    
        def supprimer_utilisateur(self):
            nom = simpledialog.askstring("Supprimer un utilisateur", "Nom :")
            if not nom:
                return
            if not USERS_FILE.exists():
                messagebox.showerror("Erreur", "Aucun utilisateur.")
                return
            try:
                with open(USERS_FILE, "r", encoding="utf-8") as f:
                    data = json.load(f)
    
                utilisateurs = [u for u in data["utilisateurs"] if u["nom"] != nom]
                if len(utilisateurs) == len(data["utilisateurs"]):
                    messagebox.showerror("Erreur", f"Utilisateur {nom} introuvable.")
                    return
    
                data["utilisateurs"] = utilisateurs
                with open(USERS_FILE, "w", encoding="utf-8") as f:
                    json.dump(data, f, indent=4, ensure_ascii=False)
    
                messagebox.showinfo("Succès", f"Utilisateur {nom} supprimé !")
            except Exception as e:
                messagebox.showerror("Erreur", f"Erreur: {e}")
    
        def recharger_plugins(self):
            nouveaux = self.plugin_manager.charger_plugins()
            if nouveaux:
                messagebox.showinfo("Plugins", f"Nouveaux plugins chargés:\n- " + "\n- ".join(nouveaux))
            else:
                messagebox.showinfo("Plugins", "Aucun nouveau plugin détecté.")
    
        def quitter(self):
            self.fenetre.destroy()
    
        def run(self):
            self.fenetre.mainloop()
    
    if __name__ == "__main__":
        app = InterfaceDemarrage()
        app.run()
Affichage de 1 message (sur 1 au total)
  • Vous devez être connecté pour répondre à ce sujet.
Retour en haut