Bienvenue sur CFTPfr.fr › Forums › scripts › chat_ia.py — v2 (chemins corrigés pour Linux)
- Ce sujet est vide.
Affichage de 1 message (sur 1 au total)
-
AuteurMessages
-
26.07.2026 à 21h27 #222
Mario Da Conceicao
Maître des clésVersion corrigée du 25/07/2026 — étape 1 du portage Linux. Seul changement : le chemin de base n’est plus écrit en dur (
D:\MIRA_Project\mira_ai), il se calcule automatiquement à partir de l’emplacement du fichier lui-même. Ça fonctionne pareil sous Windows et sous Linux, peu importe où le dossier est installé. Le reste du comportement est identique à la version d’origine (voir le sujet "chat_ia.py" précédent pour comparer).import tkinter as tk from tkinter import scrolledtext, simpledialog, messagebox from pathlib import Path import json import os import re import webbrowser import subprocess import ast import operator as op import importlib.util import sqlite3 import hashlib import secrets import random from datetime import datetime from difflib import get_close_matches # --- CORRECTION : chemin calculé automatiquement, plus de "D:\..." écrit en dur --- # Fonctionne sous Windows ET sous Linux, peu importe où le dossier est installé. BASE_DIR = Path(__file__).resolve().parent PROJECT_ROOT = BASE_DIR.parent PLUGINS_DIR = BASE_DIR / "plugins" CONFIG_FILE = BASE_DIR / "config.json" KNOWLEDGE_FILE = BASE_DIR / "connaissances.json" HISTORY_FILE = BASE_DIR / "history" / "questions_non_comprises.txt" DB_FILE = BASE_DIR / "memory.db" SAFE_OPERATORS = { ast.Add: op.add, ast.Sub: op.sub, ast.Mult: op.mul, ast.Div: op.truediv, ast.FloorDiv: op.floordiv, ast.Mod: op.mod, ast.Pow: op.pow, ast.UAdd: op.pos, ast.USub: op.neg, } def hacher_mot_de_passe(mot_de_passe: str) -> str: salt = secrets.token_hex(16) h = hashlib.sha256((mot_de_passe + salt).encode("utf-8")).hexdigest() return f"{salt}:{h}" def verifier_mot_de_passe(mot_de_passe: str, stocke: str) -> bool: try: salt, h = stocke.split(":") return hashlib.sha256((mot_de_passe + salt).encode("utf-8")).hexdigest() == h except Exception: return False class AutoImprover: def __init__(self, db_file=DB_FILE): self.db_file = Path(db_file) self.db_file.parent.mkdir(parents=True, exist_ok=True) self.conn = sqlite3.connect(self.db_file) self.conn.execute(""" CREATE TABLE IF NOT EXISTS messages( id INTEGER PRIMARY KEY AUTOINCREMENT, ts TEXT, sender TEXT, content TEXT ) """) self.conn.execute(""" CREATE TABLE IF NOT EXISTS needs( id INTEGER PRIMARY KEY AUTOINCREMENT, ts TEXT, message TEXT, domain TEXT, priority INTEGER, suggestion TEXT, done INTEGER DEFAULT 0 ) """) self.conn.execute(""" CREATE TABLE IF NOT EXISTS improvements( id INTEGER PRIMARY KEY AUTOINCREMENT, ts TEXT, title TEXT, description TEXT, score INTEGER DEFAULT 0, applied INTEGER DEFAULT 0 ) """) self.conn.commit() def log_message(self, sender, content): self.conn.execute( "INSERT INTO messages(ts, sender, content) VALUES(?,?,?)", (datetime.now().isoformat(timespec="seconds"), sender, content) ) self.conn.commit() def classify_message(self, message): msg = message.lower() if any(w in msg for w in ["code", "python", "script", "corrige"]): return "code", 4, "Ajouter une analyse de code plus poussée" if any(w in msg for w in ["fichier", "dossier", "ouvrir", "lire"]): return "fichiers", 3, "Améliorer l'ouverture et la prévisualisation des fichiers" if any(w in msg for w in ["recherche", "web", "internet", "trouve"]): return "recherche", 3, "Ajouter un moteur de recherche et de résumé" if any(w in msg for w in ["plugin", "module", "extension", "ajouter"]): return "extensions", 5, "Créer un système d'installation automatique de plugins" if any(w in msg for w in ["erreur", "bug", "panne", "crash", "ne marche pas"]): return "diagnostic", 4, "Créer un module de diagnostic plus précis" if any(w in msg for w in ["mémoire", "souviens", "historique"]): return "memoire", 4, "Ajouter une mémoire conversationnelle plus intelligente" return "general", 1, "Améliorer la compréhension générale" def analyze_and_learn(self, message): domain, priority, suggestion = self.classify_message(message) self.conn.execute( "INSERT INTO needs(ts, message, domain, priority, suggestion) VALUES(?,?,?,?,?)", (datetime.now().isoformat(timespec="seconds"), message, domain, priority, suggestion) ) self.conn.execute( "INSERT INTO improvements(ts, title, description, score, applied) VALUES(?,?,?,?,0)", (datetime.now().isoformat(timespec="seconds"), f"Besoin détecté: {domain}", message, 1) ) self.conn.commit() return domain def top_needs(self, limit=5): cur = self.conn.execute(""" SELECT domain, suggestion, COUNT(*) as cnt, MAX(priority) as maxp FROM needs WHERE done=0 GROUP BY domain, suggestion ORDER BY cnt DESC, maxp DESC LIMIT ? """, (limit,)) return cur.fetchall() def suggest_next_update(self): rows = self.top_needs() if not rows: return "Je n'ai pas encore assez de données pour proposer une amélioration." lines = ["Améliorations suggérées :"] for domain, suggestion, cnt, maxp in rows: lines.append(f"- {domain} ({cnt} demandes, priorité {maxp}) : {suggestion}") return "\n".join(lines) class PluginManager: def __init__(self): self.plugins = {} PLUGINS_DIR.mkdir(parents=True, exist_ok=True) def charger_plugins(self): self.plugins = {} for file in 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 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 plugin {intention}: {e}" return None class ChatIA: def __init__(self): self.fenetre = tk.Tk() self.fenetre.title("MIRA_IA - Assistant Intelligent") self.fenetre.geometry("900x700") self.auto = AutoImprover() self.plugin_manager = PluginManager() self.plugin_manager.charger_plugins() self.historique = [] self.contexte = {"derniere_intention": None, "derniere_question": None} self.connaissances = self.charger_connaissances() self.chat_area = scrolledtext.ScrolledText( self.fenetre, width=95, height=32, wrap=tk.WORD, font=("Segoe UI", 10), bg="#f8f9fa" ) self.chat_area.pack(padx=10, pady=10, fill=tk.BOTH, expand=True) self.append_system("Bonjour ! Je suis MIRA_IA. Je peux apprendre de vos demandes et proposer des améliorations.") panel = tk.Frame(self.fenetre) panel.pack(fill=tk.X, padx=10, pady=6) self.entry = tk.Entry(panel, font=("Segoe UI", 10)) self.entry.pack(side=tk.LEFT, fill=tk.X, expand=True) self.entry.bind("<Return>", self.send) tk.Button(panel, text="Envoyer", command=self.send, bg="#4CAF50", fg="white").pack(side=tk.LEFT, padx=5) tk.Button(panel, text="Suggestions", command=self.show_suggestions).pack(side=tk.LEFT, padx=5) tk.Button(panel, text="Plugins", command=self.reload_plugins).pack(side=tk.LEFT, padx=5) tk.Button(panel, text="Historique", command=self.export_history).pack(side=tk.LEFT, padx=5) def charger_connaissances(self): default = { "salutations": {"mots_cles": ["bonjour", "salut", "hello", "hey", "coucou"], "reponses": ["Bonjour !", "Salut !"]}, "presentation": {"mots_cles": ["qui es-tu", "ton nom", "présente toi"], "reponses": ["Je suis MIRA_IA, un assistant local modulaire."]}, "remerciements": {"mots_cles": ["merci", "super", "génial"], "reponses": ["Avec plaisir !", "Je vous en prie !"]}, "au_revoir": {"mots_cles": ["au revoir", "bye", "exit", "quit"], "reponses": ["Au revoir !"], "action": "quitter"}, "aide": {"mots_cles": ["aide", "commandes", "que peux-tu faire"], "reponses": ["Je peux calculer, rechercher, ouvrir des fichiers, diagnostiquer et charger des plugins."]}, "calcul": {"mots_cles": ["calcule", "calcul", "combien font", "+", "-", "*", "/"], "reponses": ["Donnez une opération."], "action": "calculer"}, "recherche": {"mots_cles": ["recherche", "cherche", "trouve", "web", "internet"], "reponses": ["Quel sujet ?"], "action": "recherche_web"}, "fichier": {"mots_cles": ["ouvre", "lire", "fichier", "dossier"], "reponses": ["Quel fichier ?"], "action": "ouvrir_fichier"}, "probleme": {"mots_cles": ["erreur", "bug", "problème", "ne marche pas"], "reponses": ["Décrivez le problème."], "action": "resoudre_probleme"}, } if KNOWLEDGE_FILE.exists(): try: with open(KNOWLEDGE_FILE, "r", encoding="utf-8") as f: return {**default, **json.load(f)} except Exception: pass KNOWLEDGE_FILE.parent.mkdir(parents=True, exist_ok=True) with open(KNOWLEDGE_FILE, "w", encoding="utf-8") as f: json.dump(default, f, indent=4, ensure_ascii=False) return default def append(self, sender, message): self.chat_area.config(state=tk.NORMAL) self.chat_area.insert(tk.END, f"{datetime.now().strftime('%H:%M')} | {sender}: {message}\n") self.chat_area.config(state=tk.DISABLED) self.chat_area.see(tk.END) def append_system(self, message): self.append("MIRA_IA", message) def normalize(self, text): return re.sub(r"\s+", " ", text.lower().strip()) def send(self, event=None): msg = self.entry.get().strip() if not msg: return self.entry.delete(0, tk.END) self.append("Toi", msg) self.historique.append((datetime.now().isoformat(timespec="seconds"), "Toi", msg)) self.auto.log_message("Toi", msg) self.auto.analyze_and_learn(msg) response = self.generate(msg) self.append_system(response) self.historique.append((datetime.now().isoformat(timespec="seconds"), "MIRA_IA", response)) self.auto.log_message("MIRA_IA", response) def generate(self, message): msg = self.normalize(message) if self.contexte["derniere_intention"] == "recherche" and msg not in ["oui", "non"]: return self.search_web(message) intent = self.detect_intent(message) if intent: info = self.connaissances[intent] self.contexte["derniere_intention"] = intent self.contexte["derniere_question"] = message action = info.get("action") if action == "quitter": self.fenetre.after(100, self.fenetre.destroy) return random.choice(info.get("reponses", ["Au revoir !"])) if action: return self.execute_action(action, message) return random.choice(info.get("reponses", ["Je ne sais pas répondre."])) plugin_intent = self.detect_plugin_intent(message) if plugin_intent: rep = self.plugin_manager.executer(plugin_intent, message, self) if rep: return rep self.save_unknown(message) return self.fallback_answer(message) def detect_intent(self, message): msg = self.normalize(message) best_intent = None best_score = 0 for intent, info in self.connaissances.items(): score = 0 for kw in info.get("mots_cles", []): if kw in msg: score += 2 if score > best_score: best_score = score best_intent = intent return best_intent def detect_plugin_intent(self, message): msg = self.normalize(message) for intent in self.plugin_manager.plugins: if intent in msg: return intent return None def execute_action(self, action, message): if action == "calculer": return self.calculate(message) if action == "recherche_web": return self.search_web(message) if action == "ouvrir_fichier": return self.open_file(message) if action == "resoudre_probleme": return self.solve_problem(message) return "Action non reconnue." def calculate(self, message): expr = self.extract_expression(message) if not expr: expr = simpledialog.askstring("Calcul", "Entrez une expression:") or "" if not expr: return "Aucune expression fournie." try: node = ast.parse(expr, mode="eval") return f"Résultat : {self.eval_node(node.body)}" except Exception: return "Calcul invalide." def extract_expression(self, message): msg = self.normalize(message) msg = re.sub(r"^(calcule|calcul|combien font|résous|resous)\s*", "", msg) return msg.strip() def eval_node(self, node): if isinstance(node, ast.Constant) and isinstance(node.value, (int, float)): return node.value if isinstance(node, ast.BinOp) and type(node.op) in SAFE_OPERATORS: return SAFE_OPERATORS[type(node.op)](self.eval_node(node.left), self.eval_node(node.right)) if isinstance(node, ast.UnaryOp) and type(node.op) in SAFE_OPERATORS: return SAFE_OPERATORS[type(node.op)](self.eval_node(node.operand)) raise ValueError("Expression interdite") def search_web(self, message): msg = self.normalize(message) for word in ["recherche", "cherche", "trouve", "web", "internet", "google"]: msg = msg.replace(word, "") subject = msg.strip() if not subject: subject = simpledialog.askstring("Recherche web", "Quel sujet ?") or "" if not subject: return "Recherche annulée." webbrowser.open("https://www.google.com/search?q=" + subject.replace(" ", "+")) self.contexte["derniere_intention"] = "recherche" return f"Recherche lancée pour : {subject}" def open_file(self, message): path_text = re.sub(r"\b(ouvre|lire|fichier|dossier)\b", "", message, flags=re.I).strip().strip('"').strip("'") if not path_text: path_text = simpledialog.askstring("Fichier", "Chemin complet du fichier:") or "" if not path_text: return "Aucun fichier indiqué." p = Path(path_text) if not p.is_absolute(): # CORRECTION : PROJECT_ROOT calculé automatiquement, plus de "D:\MIRA_Project" en dur p = PROJECT_ROOT / path_text if not p.exists(): return f"Le fichier n'existe pas : {p}" try: if p.suffix.lower() in [".txt", ".py", ".json", ".md", ".log", ".csv"]: return "Voici un aperçu:\n" + "\n".join(p.read_text(encoding="utf-8", errors="replace").splitlines()[:30]) if os.name == "nt": os.startfile(str(p)) else: subprocess.run(["xdg-open", str(p)]) return f"Fichier ouvert : {p}" except Exception as e: return f"Erreur fichier : {e}" def solve_problem(self, message): msg = self.normalize(message) if "python" in msg: return "Python : envoyez l'erreur exacte, le code et le résultat attendu." if "mira_os" in msg: return "MIRA_OS : vérifiez les chemins, les dépendances et les logs." return "Décrivez le contexte, le message d'erreur et ce que vous avez essayé." def fallback_answer(self, message): all_keys = list(self.connaissances.keys()) close = get_close_matches(self.normalize(message), all_keys, n=1, cutoff=0.4) if close: key = close[0] info = self.connaissances[key] return random.choice(info.get("reponses", ["Je ne sais pas."])) return f"Je n'ai pas compris : '{message}'. Essayez par exemple 'Calcule 5+3' ou 'Recherche Python'." def save_unknown(self, message): HISTORY_FILE.parent.mkdir(parents=True, exist_ok=True) with open(HISTORY_FILE, "a", encoding="utf-8") as f: f.write(f"{datetime.now().isoformat(timespec='seconds')} | {message}\n") def show_suggestions(self): msg = self.auto.suggest_next_update() messagebox.showinfo("Suggestions d'évolution", msg) def reload_plugins(self): self.plugin_manager.charger_plugins() messagebox.showinfo("Plugins", "Plugins rechargés.") def export_history(self): out = BASE_DIR / f"historique_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt" with open(out, "w", encoding="utf-8") as f: for ts, sender, msg in self.historique: f.write(f"{ts} | {sender}: {msg}\n") self.append_system(f"Historique exporté : {out.name}") def run(self): self.fenetre.mainloop() if __name__ == "__main__": ChatIA().run() -
AuteurMessages
Affichage de 1 message (sur 1 au total)
- Vous devez être connecté pour répondre à ce sujet.