Public Access
This commit is contained in:
1 parent
e3557873b9
commit
b88d693d69
2 files changed
+86
-33
No files matched your search
+23
-32
@@ -1,11 +1,15 @@
|
|||||||
import os
|
import os
|
||||||
|
import threading
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from modules.logger import log_event
|
from modules.logger import log_event
|
||||||
|
|
||||||
|
# IMPORT DE NOTRE MOTEUR FAISS (Le nouveau cerveau)
|
||||||
|
from modules.vector_rag import rechercher_contexte_global, indexer_dossier_thematique
|
||||||
|
|
||||||
# Définition du chemin racine sécurisé sur ton RAID
|
# Définition du chemin racine sécurisé sur ton RAID
|
||||||
RAG_BASE_DIR = "/DATA/AppData/MULTI-IA-AETHAS38/RAG"
|
RAG_BASE_DIR = "/DATA/AppData/MULTI-IA-AETHAS38/RAG"
|
||||||
|
|
||||||
# Les thématiques pour organiser l'apprentissage (Ajout de Général et Éducation)
|
# Les thématiques pour organiser l'apprentissage
|
||||||
THEMATIQUES_RAG = [
|
THEMATIQUES_RAG = [
|
||||||
"Minecraft_KubeJS",
|
"Minecraft_KubeJS",
|
||||||
"Juridique_Loi_Francaise",
|
"Juridique_Loi_Francaise",
|
||||||
@@ -31,44 +35,23 @@ def initialiser_arborescence_rag():
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
log_event("ERROR", "RAG", f"Erreur lors de l'initialisation de l'arborescence : {e}")
|
log_event("ERROR", "RAG", f"Erreur lors de l'initialisation de l'arborescence : {e}")
|
||||||
|
|
||||||
def extraire_contexte_rag(thematique):
|
|
||||||
"""
|
|
||||||
Lit tous les fichiers .txt ou .md d'une thématique donnée
|
|
||||||
et les concatène pour les injecter dans le prompt de l'IA.
|
|
||||||
"""
|
|
||||||
contexte_global = ""
|
|
||||||
chemin_theme = os.path.join(RAG_BASE_DIR, thematique)
|
|
||||||
|
|
||||||
# Si le thème est "aucun" ou introuvable, on tape dans les connaissances générales
|
|
||||||
if thematique == "aucun" or not os.path.exists(chemin_theme):
|
|
||||||
chemin_theme = os.path.join(RAG_BASE_DIR, "Connaissances_Generales")
|
|
||||||
|
|
||||||
try:
|
|
||||||
if os.path.exists(chemin_theme):
|
|
||||||
for fichier in os.listdir(chemin_theme):
|
|
||||||
if fichier.endswith(".txt") or fichier.endswith(".md"):
|
|
||||||
chemin_fichier = os.path.join(chemin_theme, fichier)
|
|
||||||
with open(chemin_fichier, 'r', encoding='utf-8') as f:
|
|
||||||
contexte_global += f"\n--- Extrait de {fichier} ---\n"
|
|
||||||
contexte_global += f.read() + "\n"
|
|
||||||
except Exception as e:
|
|
||||||
log_event("ERROR", "RAG", f"Erreur de lecture du contexte {thematique} : {e}")
|
|
||||||
|
|
||||||
return contexte_global
|
|
||||||
|
|
||||||
def rechercher_contexte_rag(prompt, categorie="general"):
|
def rechercher_contexte_rag(prompt, categorie="general"):
|
||||||
"""
|
"""
|
||||||
Récupère le contenu des fichiers de la thématique pour alimenter l'IA.
|
Récupère le contenu des fichiers via la recherche sémantique FAISS + Ollama.
|
||||||
|
(Remplace l'ancienne méthode d'extraction basique).
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
return extraire_contexte_rag(categorie)
|
# On fouille dans toute la base de connaissances et on récupère les 3 meilleurs blocs
|
||||||
|
contexte = rechercher_contexte_global(prompt, top_k=3)
|
||||||
|
return contexte
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log_event("ERROR", "RAG_MANAGER", f"Erreur lors de la recherche RAG : {e}")
|
log_event("ERROR", "RAG_MANAGER", f"Erreur lors de la recherche FAISS : {e}")
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
def auto_apprendre_rag(prompt, reponse, thematique_simplifiee):
|
def auto_apprendre_rag(prompt, reponse, thematique_simplifiee):
|
||||||
"""
|
"""
|
||||||
Sauvegarde systématiquement TOUTES les réponses pour enrichir la base de connaissances.
|
Sauvegarde systématiquement la réponse en Markdown,
|
||||||
|
puis déclenche l'indexation FAISS pour auto-incrémenter le RAG.
|
||||||
"""
|
"""
|
||||||
# Mapping élargi
|
# Mapping élargi
|
||||||
mapping = {
|
mapping = {
|
||||||
@@ -80,8 +63,6 @@ def auto_apprendre_rag(prompt, reponse, thematique_simplifiee):
|
|||||||
"education_nationale": "Education_Nationale"
|
"education_nationale": "Education_Nationale"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Si le thème n'est pas dans le mapping (ex: "aucun", "physique", "cuisine"),
|
|
||||||
# on le force dans le dossier "Connaissances_Generales" au lieu de l'ignorer.
|
|
||||||
theme_reel = mapping.get(thematique_simplifiee.lower(), "Connaissances_Generales")
|
theme_reel = mapping.get(thematique_simplifiee.lower(), "Connaissances_Generales")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -95,10 +76,20 @@ def auto_apprendre_rag(prompt, reponse, thematique_simplifiee):
|
|||||||
|
|
||||||
contenu = f"## Question utilisateur\n{prompt}\n\n## Réponse de l'IA (Contexte validé)\n{reponse}\n"
|
contenu = f"## Question utilisateur\n{prompt}\n\n## Réponse de l'IA (Contexte validé)\n{reponse}\n"
|
||||||
|
|
||||||
|
# 1. Sauvegarde physique du fichier
|
||||||
with open(chemin_fichier, 'w', encoding='utf-8') as f:
|
with open(chemin_fichier, 'w', encoding='utf-8') as f:
|
||||||
f.write(contenu)
|
f.write(contenu)
|
||||||
|
|
||||||
log_event("INFO", "RAG_MANAGER", f"Connaissance sauvegardée dans {theme_reel} ({nom_fichier}).")
|
log_event("INFO", "RAG_MANAGER", f"Connaissance sauvegardée dans {theme_reel} ({nom_fichier}).")
|
||||||
|
|
||||||
|
# 2. AUTO-INCRÉMENTATION : Lancement de l'indexation FAISS
|
||||||
|
# On utilise un Thread (processus en arrière-plan) pour que l'indexation via Ollama
|
||||||
|
# se fasse silencieusement sans bloquer l'interface web de l'utilisateur.
|
||||||
|
tache_indexation = threading.Thread(target=indexer_dossier_thematique, args=(theme_reel,))
|
||||||
|
tache_indexation.start()
|
||||||
|
|
||||||
|
log_event("INFO", "RAG_MANAGER", f"Indexation vectorielle lancée en tâche de fond pour {theme_reel}.")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log_event("ERROR", "RAG_MANAGER", f"Erreur lors de l'auto-apprentissage : {e}")
|
log_event("ERROR", "RAG_MANAGER", f"Erreur lors de l'auto-apprentissage : {e}")
|
||||||
|
|
||||||
|
|||||||
+63
-1
@@ -118,4 +118,66 @@ def rechercher_contexte_vectoriel(thematique: str, question: str, top_k: int = 3
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Erreur de recherche FAISS : {e}")
|
print(f"Erreur de recherche FAISS : {e}")
|
||||||
|
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
def indexer_tout_le_rag():
|
||||||
|
"""Parcourt tous les sous-dossiers de RAG_BASE_DIR et les indexe automatiquement."""
|
||||||
|
print("=== LANCEMENT DE L'INDEXATION GLOBALE ===")
|
||||||
|
if not os.path.exists(RAG_BASE_DIR):
|
||||||
|
print(f"Dossier introuvable : {RAG_BASE_DIR}")
|
||||||
|
return
|
||||||
|
|
||||||
|
for element in os.listdir(RAG_BASE_DIR):
|
||||||
|
chemin = os.path.join(RAG_BASE_DIR, element)
|
||||||
|
if os.path.isdir(chemin):
|
||||||
|
# Appelle la fonction existante pour chaque dossier trouvé
|
||||||
|
indexer_dossier_thematique(element)
|
||||||
|
print("=== INDEXATION GLOBALE TERMINÉE ===")
|
||||||
|
|
||||||
|
def rechercher_contexte_global(question: str, top_k: int = 3):
|
||||||
|
"""Cherche la réponse dans TOUTES les thématiques indexées et garde les meilleurs extraits."""
|
||||||
|
if not os.path.exists(VECTOR_DB_DIR):
|
||||||
|
return ""
|
||||||
|
|
||||||
|
vecteur_q = obtenir_embedding(question)
|
||||||
|
if not vecteur_q:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
vecteur_q_np = np.array([vecteur_q]).astype('float32')
|
||||||
|
tous_fragments = []
|
||||||
|
|
||||||
|
# On fouille dans chaque dossier de la base vectorielle
|
||||||
|
for thematique in os.listdir(VECTOR_DB_DIR):
|
||||||
|
dossier_db = os.path.join(VECTOR_DB_DIR, thematique)
|
||||||
|
fichier_index = os.path.join(dossier_db, "index.faiss")
|
||||||
|
fichier_chunks = os.path.join(dossier_db, "chunks.json")
|
||||||
|
|
||||||
|
if os.path.exists(fichier_index) and os.path.exists(fichier_chunks):
|
||||||
|
try:
|
||||||
|
index = faiss.read_index(fichier_index)
|
||||||
|
with open(fichier_chunks, 'r', encoding='utf-8') as f:
|
||||||
|
chunks = json.load(f)
|
||||||
|
|
||||||
|
# Recherche dans ce dossier spécifique
|
||||||
|
distances, indices = index.search(vecteur_q_np, top_k)
|
||||||
|
|
||||||
|
# On stocke les résultats avec leur score de pertinence (distance)
|
||||||
|
for dist, i in zip(distances[0], indices[0]):
|
||||||
|
if i < len(chunks) and i != -1:
|
||||||
|
tous_fragments.append((dist, chunks[i]["texte"], thematique))
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not tous_fragments:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
# On trie TOUS les fragments trouvés pour ne garder que les (top_k) les plus pertinents, tous dossiers confondus
|
||||||
|
# (FAISS utilise la distance L2 : plus le score est petit, plus le texte correspond à la question)
|
||||||
|
tous_fragments.sort(key=lambda x: x[0])
|
||||||
|
meilleurs = tous_fragments[:top_k]
|
||||||
|
|
||||||
|
contexte_final = []
|
||||||
|
for dist, texte, theme in meilleurs:
|
||||||
|
contexte_final.append(f"[Source : Dossier {theme}]\n{texte}")
|
||||||
|
|
||||||
|
return "\n\n---\n\n".join(contexte_final)
|
||||||
Reference in new issue
Block a user