diff --git a/README.md b/README.md index b950a38..880bb8e 100644 --- a/README.md +++ b/README.md @@ -71,8 +71,11 @@ Pour fonctionner de manière optimale, l'Orchestrateur Local nécessite au minim - [x] Modération préventive "Anti-Zèle" : Filtrage par IA Locale tolérant la fiction et les jeux vidéo. - [x] Système d'Avertissements (Strikes) automatisé et preuve d'audit manuscrite. -### Phase 10 : Base de Connaissances Intelligente (RAG) 📚 +### Phase 10 : Base de Connaissances Vectorielle (RAG FAISS) 📚 - [x] Initialisation de l'arborescence dynamique (`RAG/`) sur le stockage RAID. -- [x] Injection dynamique des documents Markdown et Texte directement dans la fenêtre de contexte des LLMs. -- [x] Auto-Apprentissage Infaillible : Le système génère automatiquement des fichiers `.md` de son propre savoir après validation. Inclusion d'un dossier "Connaissances_Generales" pour capter 100% des requêtes. -- [ ] Interface UI : Ajout d'une vue Administrateur pour téléverser de nouveaux documents RAG. \ No newline at end of file +- [x] Moteur Vectoriel Local : Remplacement de la lecture brute par une base **FAISS** haute performance. +- [x] Embeddings IA : Vectorisation mathématique via modèle local (Ollama / `nomic-embed-text`) pour une recherche sémantique ultra-rapide. +- [x] Ingestion Multi-Formats : Support étendu aux PDF institutionnels et aux fichiers de code/configuration (`.js`, `.yml`, `.json`, `.md`, `.txt`) pour la documentation de mods (ex: KubeJS). +- [x] Superviseur IA (Arrière-plan) : Évaluation silencieuse de la pertinence technique des réponses avant indexation via Threading (zéro latence pour l'utilisateur). +- [x] Forçage Manuel (UI) : Ajout d'un bouton HTMX "💾 Mémoriser" pour forcer l'apprentissage vectoriel à la volée. +- [ ] Interface UI : Ajout d'une vue Administrateur pour téléverser de nouveaux documents RAG directement depuis le navigateur. \ No newline at end of file diff --git a/main.py b/main.py index 351f400..7964d8e 100644 --- a/main.py +++ b/main.py @@ -191,5 +191,27 @@ async def post(request, session): else: return Span("❌ Aucun fichier valide détecté.", style="color: red;") +from modules.export_utils import generer_export_comptable + +# --- NOUVELLE ROUTE POUR L'EXPORT COMPTABLE EXCEL --- +@rt('/admin/export_comptable') +def get(session): + if session.get('user', '') != 'xavier': + return HTMLResponse("Accès refusé. Droits d'administration requis.") + + try: + chemin_fichier = generer_export_comptable() + if os.path.exists(chemin_fichier): + return FileResponse( + chemin_fichier, + filename=os.path.basename(chemin_fichier), + media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" + ) + else: + return HTMLResponse("Erreur : Impossible de générer le fichier Excel.", status_code=500) + except Exception as e: + log_event("ERROR", "FINANCE", f"Échec de l'export : {e}") + return HTMLResponse(f"Erreur système lors de l'export : {e}", status_code=500) + if __name__ == '__main__': serve(port=5001) \ No newline at end of file diff --git a/modules/export_utils.py b/modules/export_utils.py index 3548bd4..8b66d81 100644 --- a/modules/export_utils.py +++ b/modules/export_utils.py @@ -1,10 +1,87 @@ -# modules/export_utils.py +import os import json +import pandas as pd +from datetime import datetime +from modules.logger import log_event -def generer_donnees_json(contenu): - """Prépare la structure de données pour l'export JSON.""" - return { - "app": "Aethas38 Core", - "timestamp": time.time() if 'time' in globals() else None, - "content": contenu - } \ No newline at end of file +DOSSIER_FINANCE = "/DATA/AppData/MULTI-IA-AETHAS38/Finances" +FICHIER_AUDIT = os.path.join(DOSSIER_FINANCE, "aethas_financial_audit.json") + +def initialiser_dossier_finance(): + os.makedirs(DOSSIER_FINANCE, exist_ok=True) + if not os.path.exists(FICHIER_AUDIT): + with open(FICHIER_AUDIT, 'w', encoding='utf-8') as f: + json.dump([], f) + +def generer_export_comptable(): + """ + Génère un Livre des Recettes Excel conforme URSSAF via Pandas. + Idéal pour le calcul direct du Chiffre d'Affaires à déclarer. + """ + initialiser_dossier_finance() + chemin_export = os.path.join(DOSSIER_FINANCE, f"Livre_Recettes_URSSAF_{datetime.now().strftime('%Y_%m')}.xlsx") + + try: + with open(FICHIER_AUDIT, 'r', encoding='utf-8') as f: + donnees_brutes = json.load(f) + except Exception: + donnees_brutes = [] + + # Formatage strict pour la comptabilité d'auto-entrepreneur + lignes_comptables = [] + + if not donnees_brutes: + # Génération d'une ligne d'exemple légale si le fichier est vide + lignes_comptables.append({ + "Date d'encaissement": datetime.now().strftime("%Y-%m-%d"), + "Référence (N° Facture / Chat ID)": "EXEMPLE-001", + "Client (Utilisateur)": "Exemple_Client", + "Nature de la prestation": "Services techniques IA (Prestation de services)", + "Coût API Brut HT (€)": 0.05, + "Marge Commerciale (€)": 0.45, + "Montant encaissé HT (€)": 0.50 + }) + else: + for transaction in donnees_brutes: + cout_brut = float(transaction.get("cout_api", 0.0)) + montant_facture = float(transaction.get("montant_facture", 0.0)) + + lignes_comptables.append({ + "Date d'encaissement": transaction.get("date", datetime.now().strftime("%Y-%m-%d")), + "Référence (N° Facture / Chat ID)": transaction.get("id", "N/A"), + "Client (Utilisateur)": transaction.get("utilisateur", "Inconnu"), + "Nature de la prestation": f"Requête IA - {transaction.get('modele', 'Multi-modèle')}", + "Coût API Brut HT (€)": cout_brut, + "Marge Commerciale (€)": montant_facture - cout_brut, + "Montant encaissé HT (€)": montant_facture + }) + + # Création du DataFrame Pandas + df = pd.DataFrame(lignes_comptables) + + # Calcul des totaux pour le TCD + total_ca = df["Montant encaissé HT (€)"].sum() + total_marge = df["Marge Commerciale (€)"].sum() + + # Création du fichier Excel avec onglets multiples via Openpyxl + with pd.ExcelWriter(chemin_export, engine='openpyxl') as writer: + df.to_excel(writer, sheet_name="Livre des Recettes", index=False) + + # Onglet de synthèse analytique + resume = pd.DataFrame({ + "Indicateur Financier": ["Chiffre d'Affaires Total (Déclaration URSSAF)", "Coûts d'Infrastructure (API)", "Bénéfice Net Estimé"], + "Montant (€)": [total_ca, df["Coût API Brut HT (€)"].sum(), total_marge] + }) + resume.to_excel(writer, sheet_name="Synthèse_Fiscale", index=False) + + # Accès aux feuilles pour le formatage esthétique + workbook = writer.book + worksheet = writer.sheets["Livre des Recettes"] + worksheet.insert_rows(1) + worksheet.cell(row=1, column=1, value="AETHAS38 - Siège : Charvieu-Chavagneux (38230) - Registre des recettes") + worksheet.column_dimensions['A'].width = 18 + worksheet.column_dimensions['C'].width = 20 + worksheet.column_dimensions['D'].width = 45 + + log_event("INFO", "FINANCE", f"Export comptable généré : {chemin_export}") + return chemin_export \ No newline at end of file diff --git a/modules/ui_components.py b/modules/ui_components.py index b9c95d2..a999cf5 100644 --- a/modules/ui_components.py +++ b/modules/ui_components.py @@ -1,4 +1,5 @@ import os +from tkinter import Button import requests from fasthtml.common import * from modules.database import load_history @@ -153,6 +154,7 @@ def render_main_page(chat_id, utilisateur_nom="xavier", role="Super Admin"): 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("📊 Export URSSAF (Excel)", href="/admin/export_comptable", cls="export-btn", style="background-color: #4caf50; color: white; border-color: #4caf50; margin-top: 5px; text-decoration: none; text-align: center;") 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" diff --git a/requirements.txt b/requirements.txt index 512c4a9..5bd6414 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,8 +5,8 @@ openai google-genai requests beautifulsoup4 -pandas -openpyxl +pandas==2.2.0 +openpyxl==3.1.2 reportlab psutil cryptography