Public Access
MAJ Phase 10 : Support KubeJS, bouton RAG UI et Modale d'upload admin
Build and Push Docker Image / build-and-push (push) Successful in 37s
Build and Push Docker Image / build-and-push (push) Successful in 37s
This commit is contained in:
1 parent
f17ef384f6
commit
a2261ab8dd
3 files changed
+79
-5
No files matched your search
@@ -3,6 +3,7 @@ from dotenv import load_dotenv
|
||||
load_dotenv() # Force la lecture du fichier .env en local
|
||||
import uuid
|
||||
import json
|
||||
import threading
|
||||
from fasthtml.common import *
|
||||
from starlette.staticfiles import StaticFiles
|
||||
from starlette.responses import FileResponse, Response, HTMLResponse, RedirectResponse
|
||||
@@ -10,13 +11,14 @@ from starlette.middleware.base import BaseHTTPMiddleware
|
||||
|
||||
from modules.theme import get_theme_hdrs
|
||||
from modules.database import nettoyer_vieilles_discussions, HISTORY_FILE, load_history, save_history
|
||||
from modules.ui_components import render_main_page, render_sidebar, render_login_page
|
||||
from modules.ui_components import render_main_page, render_sidebar, render_login_page, render_rag_upload_modal
|
||||
from modules.chat_handler import handle_chat_request
|
||||
from modules.security import verifier_et_bloquer_vpn, journaliser_ip
|
||||
from modules.auth_manager import IDENTIFIANTS_ADMIN, verifier_mot_de_passe
|
||||
from modules.logger import log_event
|
||||
from modules.billing_manager import charger_soldes, sauvegarder_soldes
|
||||
from modules.rag_manager import auto_apprendre_rag
|
||||
from modules.vector_rag import indexer_dossier_thematique
|
||||
|
||||
# Lancement du module d'auto-mise à jour en arrière-plan
|
||||
import modules.model_updater
|
||||
@@ -152,5 +154,42 @@ def post(prompt: str, reponse: str, theme: str):
|
||||
auto_apprendre_rag(prompt, reponse, theme)
|
||||
return Span("✅ Indexé", cls="msg-action-btn", style="background-color: #4caf50; color: white; border: none; cursor: default;")
|
||||
|
||||
# --- NOUVELLES ROUTES POUR L'UPLOAD MODAL DU RAG ---
|
||||
@rt('/admin/rag_modal')
|
||||
def get(session):
|
||||
if session.get('user', '') != 'xavier':
|
||||
return HTMLResponse("Accès refusé.")
|
||||
return render_rag_upload_modal()
|
||||
|
||||
@rt('/api/upload_rag')
|
||||
async def post(request, session):
|
||||
if session.get('user', '') != 'xavier':
|
||||
return Span("❌ Accès refusé", style="color: red;")
|
||||
|
||||
form = await request.form()
|
||||
theme = form.get("theme")
|
||||
fichiers = form.getlist("fichiers_rag")
|
||||
|
||||
if not theme or not fichiers:
|
||||
return Span("❌ Thème ou fichiers manquants", style="color: red;")
|
||||
|
||||
dossier_cible = f"/DATA/AppData/MULTI-IA-AETHAS38/RAG/{theme}"
|
||||
os.makedirs(dossier_cible, exist_ok=True)
|
||||
|
||||
fichiers_sauves = 0
|
||||
for f in fichiers:
|
||||
if f.filename:
|
||||
chemin_fichier = os.path.join(dossier_cible, f.filename)
|
||||
contenu = await f.read()
|
||||
with open(chemin_fichier, "wb") as out:
|
||||
out.write(contenu)
|
||||
fichiers_sauves += 1
|
||||
|
||||
if fichiers_sauves > 0:
|
||||
threading.Thread(target=indexer_dossier_thematique, args=(theme,)).start()
|
||||
return Span(f"✅ {fichiers_sauves} fichier(s) sauvé(s). Indexation FAISS démarrée en arrière-plan !", style="color: #4caf50;")
|
||||
else:
|
||||
return Span("❌ Aucun fichier valide détecté.", style="color: red;")
|
||||
|
||||
if __name__ == '__main__':
|
||||
serve(port=5001)
|
||||
@@ -17,7 +17,6 @@ def get_openrouter_stats():
|
||||
def render_user_msg(text):
|
||||
return Div(P(text, style="margin:0; font-weight:bold; white-space: pre-wrap;"), cls="user-bubble")
|
||||
|
||||
# --- LA FONCTION CORRIGÉE AVEC SES 10 ARGUMENTS ---
|
||||
def render_ai_msg(text, intention, nom_fournisseur, nom_modele, couleur, execution_time=None, trace=None, prompt_associe="", thematique="general", msg_id=""):
|
||||
time_badge = Span(f"⏱️ {execution_time}s", style="margin-right: 10px; color:#aaa; font-size:0.8em;") if execution_time else ""
|
||||
|
||||
@@ -33,7 +32,6 @@ def render_ai_msg(text, intention, nom_fournisseur, nom_modele, couleur, executi
|
||||
time_badge, style="border-bottom: 1px solid #333; padding-bottom: 10px; margin-bottom: 10px; display: flex; flex-wrap: wrap; gap: 5px;"
|
||||
)
|
||||
|
||||
# --- BOUTON FORCER RAG (HTMX) ---
|
||||
bouton_forcer = ""
|
||||
if msg_id and prompt_associe and thematique != "aucun":
|
||||
safe_prompt = prompt_associe.replace('"', '\\"').replace('\n', ' ')
|
||||
@@ -110,7 +108,6 @@ def render_main_page(chat_id, utilisateur_nom="xavier", role="Super Admin"):
|
||||
.catch(() => { serverDown = true; console.log("Serveur hors ligne..."); });
|
||||
}, 5000);
|
||||
|
||||
// Script pour gérer l'avertissement de gratuité sur les médias
|
||||
function checkMediaPaymentWarning() {
|
||||
const mediaMode = document.querySelector('input[name="media_mode"]:checked').value;
|
||||
const isPayant = document.getElementById('mode-payant-toggle').checked;
|
||||
@@ -155,6 +152,7 @@ def render_main_page(chat_id, utilisateur_nom="xavier", role="Super Admin"):
|
||||
Div(
|
||||
A("+ Nouvelle discussion", href="/new_chat", cls="new-chat-btn"),
|
||||
A("💾 Exporter JSON", href="/export_json", target="_blank", cls="export-btn"),
|
||||
Button("📚 Gestion RAG", hx_get="/admin/rag_modal", hx_target="body", hx_swap="beforeend", cls="export-btn", style="background-color: #2196f3; color: white; border-color: #2196f3; margin-top: 5px; cursor: pointer;") if role.lower() in ["super admin", "admin"] else "",
|
||||
A("🚪 Déconnexion", href="/logout", cls="export-btn", style="background-color: #8b0000; color: white; border-color: #8b0000; margin-top: 5px;"),
|
||||
cls="nav-buttons", style="display: flex; flex-direction: column; gap: 10px;"
|
||||
), cls="sidebar-top"
|
||||
@@ -252,4 +250,41 @@ def render_popup_paiement(cout_estime, prompt_sauvegarde, chat_id, multi_ia_stat
|
||||
),
|
||||
id="popup-paiement",
|
||||
style="position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background: rgba(0,0,0,0.8); display: flex; align-items: center; justify-content: center; z-index: 9999;"
|
||||
)
|
||||
|
||||
def render_rag_upload_modal():
|
||||
"""Génère la fenêtre pop-up pour téléverser des documents dans le RAG."""
|
||||
themes = [
|
||||
"Minecraft_KubeJS", "Juridique_Loi_Francaise", "Serveur_Debian",
|
||||
"Bureautique_Excel", "Regles_Aethas38", "Education_Nationale", "Connaissances_Generales"
|
||||
]
|
||||
options = [Option(t.replace("_", " "), value=t) for t in themes]
|
||||
|
||||
return Div(
|
||||
Div(
|
||||
H3("📚 Administration RAG (Base Vectorielle)", style="color: #2196f3; margin-top: 0;"),
|
||||
P("Formats supportés : PDF, MD, TXT, JS, JSON, YML, CSV", style="color: #ccc; font-size: 0.9em;"),
|
||||
Form(
|
||||
Div(
|
||||
Label("1. Choisir la thématique :", style="font-weight: bold; color: white;"),
|
||||
Select(*options, name="theme", cls="input-field", style="margin-bottom: 15px;")
|
||||
),
|
||||
Div(
|
||||
Label("2. Sélectionner les fichiers :", style="font-weight: bold; color: white;"),
|
||||
Input(type="file", name="fichiers_rag", multiple=True, required=True, cls="input-field", style="margin-bottom: 15px; background: #222; padding: 10px; border: 1px dashed #2196f3; cursor: pointer;")
|
||||
),
|
||||
Div(
|
||||
Button("Annuler", type="button", onclick="document.getElementById('rag-modal').remove();", cls="btn-submit", style="background-color: #555; width: 48%;"),
|
||||
Button("Téléverser & Indexer", type="submit", cls="btn-submit", style="background-color: #2196f3; color: white; width: 48%;"),
|
||||
style="display: flex; justify-content: space-between;"
|
||||
),
|
||||
hx_post="/api/upload_rag",
|
||||
hx_target="#rag-upload-result",
|
||||
enctype="multipart/form-data"
|
||||
),
|
||||
Div(id="rag-upload-result", style="margin-top: 15px; text-align: center; font-weight: bold;"),
|
||||
style="background: #1a1a1a; padding: 25px; border-radius: 12px; border: 2px solid #2196f3; width: 500px; max-width: 90vw; box-shadow: 0 10px 30px rgba(0,0,0,0.8);"
|
||||
),
|
||||
id="rag-modal",
|
||||
style="position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background: rgba(0,0,0,0.8); display: flex; align-items: center; justify-content: center; z-index: 9999;"
|
||||
)
|
||||
@@ -46,7 +46,7 @@ def indexer_dossier_thematique(thematique: str):
|
||||
reader = pypdf.PdfReader(chemin_complet)
|
||||
for page in reader.pages:
|
||||
texte += page.extract_text() or ""
|
||||
elif fichier.lower().endswith(('.md', '.txt')):
|
||||
elif fichier.lower().endswith(('.md', '.txt', '.yml', '.yaml', '.js', '.json', '.csv', '.toml', '.properties')):
|
||||
with open(chemin_complet, 'r', encoding='utf-8') as f:
|
||||
texte = f.read()
|
||||
|
||||
|
||||
Reference in new issue
Block a user