diff --git a/README.md b/README.md index 892820f..952a6b7 100644 --- a/README.md +++ b/README.md @@ -1,93 +1,61 @@ # Aethas38 - Multi-IA Orchestrateur (Minecraft-Tech Edition) Plateforme SaaS d'IA modulaire : Orchestrateur local, routeur intelligent, sécurisé et facturable. +**Architecture réseau :** Déploiement via Docker derrière Nginx Proxy Manager (NPM) sur `https://ia.aethas38.duckdns.org`. + +## 📜 Licence & Droits d'Utilisation (EULA) +Ce projet est distribué sous une licence "Source Available" propriétaire (EULA) rédigée par Xavier Fernandez (Aethas38). +* **Modifications & Partage :** Les utilisateurs sont autorisés à modifier et améliorer le code, à condition de partager ces améliorations avec la communauté. +* **Restrictions strictes :** Il est **strictement interdit** de modifier ou supprimer les crédits de l'auteur originel, de retirer le module de dons dédié au créateur, ou de désactiver la télémétrie de sécurité (notification d'installation avec IP/Nom admin envoyée à `admin@mail.aethas38.duckdns.org`). L'installation requiert l'acceptation explicite de ces termes. ## 📋 To-Do List (Roadmap) ### Phase 1 & 2 : Infrastructure & Backend de Base ✅ -- [x] Installation Docker, Nginx, Pare-feu, Gitea/GitHub -- [x] Serveur Local Ollama (Qwen 3B) + FastHTML -- [x] Routeur Multi-IA (Groq, Gemini, Local) avec système de cascade et directives d'aiguillage strictes -- [x] Continuité de service : IA de secours (Fallback automatique sur Groq) en cas de panne d'une API primaire +- [x] Installation Docker, Nginx (NPM), Pare-feu, Gitea/GitHub +- [x] Serveur Local Ollama (Qwen 3B) + FastHTML (Adapté aux processeurs limités type AMD Phenom) +- [x] Routeur Multi-IA (OpenRouter, Gemini, Local) avec système de cascade et directives d'aiguillage strictes +- [x] Continuité de service : IA de secours automatique ### Phase 3 : Refonte UI & Expérience Utilisateur ✅ - [x] Thème "Minecraft-Tech" (Inspiré serveurs/redstone) compatible Mobile (Responsive) - [x] Historique (Sidebar) avec Renommage, Épinglage, Suppression et Navigation isolée par session - [x] Zone de saisie intelligente (Textarea auto-adaptatif, Drag & Drop avec pills/miniatures, Collage multi-fichiers jusqu'à 10) -- [x] Export modulaire et propre (PDF Pro avec fond blanc, DOC Word, TXT, JSON, et blocs de code en ZIP) avec nommage dynamique intelligent basé sur la requête utilisateur (ex: `frise_temporalite_minecraft.pdf`) -- [x] Boutons de partage direct (WhatsApp, Email) avec nettoyage automatique des balises HTML brutes -- [x] Script de nettoyage automatique : Suppression des discussions de > 365 jours +- [x] Export modulaire et propre (PDF, DOC, TXT, JSON, ZIP) +- [x] Boutons de partage direct (WhatsApp, Email) - [x] Indicateur d'avancement dynamique (Loader Néon) pendant le traitement des IA -- [x] Architecture modulaire propre (Dossier `modules/` isolant Database, Scraper, AI Engine, Router et UI) +- [x] Architecture modulaire propre (Dossier `modules/`) -### Phase 4 : Gestion des Utilisateurs & Sécurité -- [ ] Céer un lien Paypal pour les dons des utilisateurs. -- [ ] Mettre en place une bibliothèque logiciel à installer avec le serveur (déporter tout ce qui peut l'être comme la création de pdf, docx, html, etc.) -- [ ] Choix entre l'utilisation de la version payante ou gratuite. Routage suivant le choix. -- [ ] Système de connexion sécurisé (Mots de passe cryptés) -- [ ] Fail2Ban (Blocage 15 mins après 5 erreurs) -- [ ] Intégration SMTP (`mail.aethas38.duckdns.org`) pour mot de passe oublié et notifications de thèmes spécifiques -- [ ] Gestion des rôles : Admin (Xavier, Céline), Famille (Anaëlle, Audric, Renan), Testeur (Nogapra) et Externes. Testeur juste accès à la partie gratuite. -- [ ] Prévoir un script automatique envoyant un mail sympathique aux utilisateurs lors de leur anniversaire. +### Phase 4 : Gestion des Utilisateurs & Sécurité Légale +- [ ] Créer un lien Paypal pour les dons des utilisateurs (Incluant un bouton de don inaltérable pour le créateur Aethas38). +- [ ] Mettre en place une bibliothèque logicielle autonome sur le serveur (création PDF, DOCX, etc.). +- [ ] Routage automatique (Gratuit vs Payant) sélectionné par l'utilisateur. +- [ ] Système de connexion sécurisé avec configuration du premier lancement (DOB depuis 1900, Email, Clés API). L'utilisateur Xavier a obligatoirement le rôle "Dieu tout puissant" (Admin global). +- [ ] Sécurité Légère : Fail2Ban, protection Bruteforce et DDoS. **Blocage total des accès VPN**. +- [ ] Conformité légale (RGPD) : Journalisation stricte des IP par client conservée 1 an. +- [ ] Multilinguisme : Adaptation automatique de la langue du site via la géolocalisation de l'IP. ### Phase 5 : Sécurité Financière & Facturation Exacte 💰 -- [ ] Modèle Excel de calcul des coûts serveur (1x 1000W H24, Internet 60€/mois). Prendre en compte le tarif réglemanté de l'électricité en France et la consommation réel du serveur. -- [ ] Simulateur de coût avant requête : L'estimation doit être exacte pour éviter les défauts de paiement -- [ ] Gestion des comptes et provisions (CB) avec test du restant financier avant validation -- [ ] Règles d'exceptions Administrateurs & Famille (Pas de provision nécessaire, rattachés au master-compte Xavier/Céline) -- [ ] Majoration invisible de 15% appliquée automatiquement pour les comptes Externes -- [ ] Compteur en temps réel mis à jour après la requête basé sur le prix annoncé après traitement par les fournisseurs "Pay As You Go" (PAYG) -- [ ] Routage Conditionnel Payant : Utiliser *toutes* les IA en adéquation avec le thème de la requête +- [ ] Simulateur de coût avant requête : L'estimation doit être exacte pour éviter les défauts de paiement. +- [ ] Cryptage absolu de toutes les données sensibles et bancaires. +- [ ] Module de conversion des devises en temps réel (Taux du jour) pour un affichage transparent. +- [ ] **Utilisateurs Privilégiés (Zéro Marge) :** Xavier, Céline, Anaëlle, Renan et Audric. Autorisation de virements manuels pour la cagnotte. +- [ ] **Marge Commerciale :** Majoration automatique via la formule `Prix_Facture_HT = Cout_API_OpenRouter_HT / 0.85` (soit 15% de marge) pour les comptes externes, prenant en compte le statut auto-entrepreneur (TVA). +- [ ] Export comptable Excel (TCD) par utilisateur via Pandas/Openpyxl et archivage PDF automatisé. ### Phase 6 : Nouvelles Capacités IA (Spécialisations & Modèles) 🤖 -*La mise en forme finale des retours est assurée par l'abonnement Gemini.* +*Note : L'infrastructure bascule sur OpenRouter pour palier aux décommissionnements constants des autres fournisseurs.* | Domaine de tâche | Modèle / Moteur | Fournisseur / Hébergement | Rôle principal | | :--- | :--- | :--- | :--- | -| **Orchestration & Tri** | Qwen 2.5 (3B/7B quantizé) | Local (GTX 1650 / Ollama) | Analyse l'intention, gère le chat rapide et route vers la bonne IA | -| **Prog. & Java 21** | Claude 3.5 Sonnet / Qwen Coder | Anthropic / OpenRouter | Correction bugs, KubeJS, modernisation de mods (Pay-as-you-go) | -| **Serveur / Logs** | Llama 3.3 (8B / 70B) | Groq API | Analyse crashs Prism Launcher, Bash, Docker (Gratuit / Rapide) | -| **Logique & Quêtes** | DeepSeek R1 (Distillé) | DeepSeek API / Gratuit | Structuration logique des modpacks et FTB Quests | -| **Images HD / Vidéo** | Gemini 2.0 Flash / FLUX.1 | Google AI Studio & Fal.ai | Analyse d'images/vidéos et génération d'assets 2K | -| **Bureautique** | À définir | À définir | Excel (Macros, formules complexes) | +| **Orchestration & Tri** | Qwen 2.5 (3B) | Local (GTX 1650 / Ollama) | Analyse l'intention, gère le chat rapide et route vers la bonne IA | +| **Bureautique & Code** | Llama 3.1 / Qwen 2.5 Coder | OpenRouter API (Gratuit) | Programmation, scripts, macros VBA, mathématiques | +| **Images HD / Fichiers** | Gemini 2.0 Flash / Pro | Google AI Studio | Analyse d'images/vidéos et documents joints | -### Phase 7 : RAG & Maintenance -- [ ] "RAG" : Base de données vectorielle (ChromaDB) pour permettre l'apprentissage et la mémorisation de l'IA locale -- [ ] Script de surveillance de l'espace disque du serveur. Affichage d'une barre d'état (statuts des disques, remplissage, utilisations pour Xavier) -- [ ] Création de logs centralisés consultables et téléchargeables par l'Admin - -### Phase 8 : Déploiement Public & Configuration -- [ ] Assistant de configuration (Wizard) au premier lancement pour insérer les clés API, configurer le SMTP, etc. -- [ ] Liens de documentation intégrés pour créer ses propres clés API -- [ ] Hébergement sur Gitea/Github des versions "Install Initial" ou "Update" pour Docker +### Phase 7 & 8 : Maintenance & Déploiement +- [ ] Script de surveillance de l'espace disque du serveur (Beszel / Psutil) réservé à l'Admin. +- [ ] Sauvegarde automatique : Compression du site toutes les 6 heures vers GDrive (`25-BACKUP SITE`), 4 versions conservées. +- [ ] Hébergement sur Gitea/Github des versions "Install Initial" ou "Update" pour Docker. Licence identique sur les deux plateformes. +- [ ] Création d'un Wiki détaillé multilingue pour l'installation personnelle. ## 📷 Vidéosurveillance & Détection Intelligente - -L'écosystème de vision par ordinateur appliqué à la sécurité s'articule autour de la détection d'objets en temps réel pour garantir des alertes immédiates[cite: 35]. - -### 1. Frigate NVR (Détection Locale & Temps Réel) -* **Rôle principal** : Solution standard incontournable pour analyser des flux vidéo RTSP 24h/24 en local, sans saturer le processeur et sans dépendre du cloud[cite: 35]. -* **Matériel recommandé** : Ajout d'un accélérateur matériel **Google Coral TPU** (M.2 ou USB) pour encaisser le traitement lourd de l'IA sans impacter le CPU du serveur[cite: 35]. -* **Modèles de détection** : - * **Modèle par défaut** : Basé sur MobileNet SSD, optimisé pour les Edge TPU, détectant les classes standard (personnes, voitures, chats, chiens)[cite: 35]. - * **Modèles personnalisés (YOLO)** : Injection possible de modèles au format `.onnx` (issus de YOLOv5, v8 ou v11) pour des éléments spécifiques (colis, animaux précis)[cite: 35]. - * **Frigate+** : Service payant d'annotation de faux positifs pour réentraîner un modèle sur-mesure ultra-précis pour le Coral TPU[cite: 35]. - ---- - -## 🏠 Home Assistant & Analyse Sémantique (LLM Multimodaux) - -L'utilisation de Modèles de Langage Multimodaux (LMM) permet de comprendre en détail le contenu d'une scène et d'envoyer des notifications contextuelles riches[cite: 35]. - -### 1. Solutions Cloud (Précision Maximale) -* **Google Gemini (Flash / Pro)** : Choix populaire et redoutable doté de quotas gratuits généreux, capable de décrire une image avec une précision chirurgicale (ex. : « Un livreur dépose un colis étiqueté Amazon sur le paillasson »)[cite: 35]. -* **OpenAI GPT-4o / GPT-4o-mini** : Alternative payante performante pour analyser le contexte d'une image et générer des notifications smartphone dynamiques[cite: 35]. - -### 2. Solutions Locales (Confidentialité / 100% Offline) -* **Qwen2-VL** : L'un des meilleurs modèles ouverts (open-weights) en vision pour analyser finement les détails d'une caméra de sécurité[cite: 35]. -* **Llama 3.2 Vision** : Modèle rapide et idéal pour un déploiement local sur une machine dotée d'un GPU performant[cite: 35]. -* **Moondream** : Modèle minuscule et ultrarapide conçu spécifiquement pour la vision sur des architectures modestes[cite: 35]. - -### 3. Architecture Hybride Recommandée -* **Niveau 1 (Sécurité & Réactivité - 0ms de latence cloud)** : Frigate couplé au Google Coral TPU surveille les flux en continu et déclenche instantanément des actions physiques (lumières, alarmes) via Home Assistant dès qu'un humain est détecté[cite: 35]. -* **Niveau 2 (Confort & Notification - Analyse sémantique)** : Home Assistant capture une image (snapshot) et l'envoie à un LLM multimodal (Gemini pour le cloud ou Qwen2-VL en local) pour générer une notification push riche décrivant la situation[cite: 35]. \ No newline at end of file +*(Voir configuration Frigate locale et Google Coral TPU existante)* \ No newline at end of file diff --git a/modules/ai_engine.py b/modules/ai_engine.py index 6980efa..d903ad6 100644 --- a/modules/ai_engine.py +++ b/modules/ai_engine.py @@ -1,11 +1,8 @@ from modules.logger import log_event from modules.ai_gemini import interroger_gemini -from modules.ai_groq import interroger_groq -from modules.ai_deepseek import interroger_deepseek -from modules.ai_mistral import interroger_mistral -from modules.ai_huggingface import interroger_huggingface -from modules.ai_cloudflare import interroger_cloudflare from modules.ai_local import interroger_local_ollama +# Le nouveau module que nous allons créer à la prochaine étape +from modules.ai_openrouter import interroger_openrouter SYSTEM_CONFIDENTIALITY_INSTRUCTION = ( "RÈGLE DE CONFIDENTIALITÉ ABSOLUE : Tu es un assistant intégré à la plateforme privée Aethas38. " @@ -15,21 +12,27 @@ SYSTEM_CONFIDENTIALITY_INSTRUCTION = ( ) def executer_requete_ia(fournisseur, prompt): - """Moteur central gérant les consignes de sécurité et la cascade intelligente.""" + """Moteur central gérant les consignes de sécurité et la cascade intelligente vers OpenRouter.""" prompt_securise = f"{SYSTEM_CONFIDENTIALITY_INSTRUCTION}\n\nRequête utilisateur :\n{prompt}" - # 🔄 Ordre de cascade intelligent défini par l'orchestrateur (repli automatique) - if fournisseur == "gemini": ordre_repli = [interroger_gemini, interroger_groq, interroger_mistral, interroger_deepseek, interroger_huggingface, interroger_cloudflare, interroger_local_ollama] - elif fournisseur == "groq": ordre_repli = [interroger_groq, interroger_mistral, interroger_deepseek, interroger_gemini, interroger_huggingface, interroger_cloudflare, interroger_local_ollama] - elif fournisseur == "deepseek": ordre_repli = [interroger_deepseek, interroger_gemini, interroger_groq, interroger_mistral, interroger_local_ollama] - elif fournisseur == "mistral": ordre_repli = [interroger_mistral, interroger_groq, interroger_gemini, interroger_huggingface, interroger_local_ollama] - elif fournisseur == "huggingface": ordre_repli = [interroger_huggingface, interroger_cloudflare, interroger_groq, interroger_gemini, interroger_local_ollama] - elif fournisseur == "cloudflare": ordre_repli = [interroger_cloudflare, interroger_huggingface, interroger_groq, interroger_gemini, interroger_local_ollama] - else: ordre_repli = [interroger_local_ollama, interroger_gemini, interroger_groq] + # 🔄 Ordre de cascade recentré sur OpenRouter (Gratuit), Gemini et le Local + if fournisseur == "gemini": + ordre_repli = [interroger_gemini, interroger_openrouter, interroger_local_ollama] + elif fournisseur == "openrouter_code": + ordre_repli = [interroger_openrouter, interroger_gemini, interroger_local_ollama] + elif fournisseur == "openrouter_chat": + ordre_repli = [interroger_openrouter, interroger_gemini, interroger_local_ollama] + else: + ordre_repli = [interroger_local_ollama, interroger_openrouter, interroger_gemini] for fonction_api in ordre_repli: try: - texte, couleur, nom_fournisseur, nom_modele = fonction_api(prompt_securise) + # Transfert du 'fournisseur' cible pour qu'OpenRouter sache s'il doit appeler un modèle Code ou Chat + if fonction_api.__name__ == 'interroger_openrouter': + texte, couleur, nom_fournisseur, nom_modele = fonction_api(prompt_securise, type_modele=fournisseur) + else: + texte, couleur, nom_fournisseur, nom_modele = fonction_api(prompt_securise) + if texte: return texte, couleur, nom_fournisseur, nom_modele except Exception as e: diff --git a/modules/ai_openrouter.py b/modules/ai_openrouter.py index 64be4bb..0b5aab9 100644 --- a/modules/ai_openrouter.py +++ b/modules/ai_openrouter.py @@ -1,36 +1,63 @@ import os +import time +import openai from openai import OpenAI from modules.logger import log_event -def interroger_openrouter(prompt_securise): - """Module dédié à OpenRouter.ai pour accéder à +100 modèles gratuitement.""" - api_key = os.getenv("OPENROUTER_API_KEY") - if not api_key: raise Exception("Clé API OpenRouter manquante.") +# Initialisation du client OpenRouter avec l'API compatible OpenAI +client = OpenAI( + base_url="https://openrouter.ai/api/v1", + api_key=os.getenv("OPENROUTER_API_KEY", "VOTRE_CLE_ICI") # À définir dans le .env +) + +def interroger_openrouter(prompt, type_modele="openrouter_chat", max_retries=3): + """ + Interroge l'API OpenRouter avec gestion des erreurs 402 (Plafond) et 429 (Rate Limit). + Sélectionne un modèle gratuit selon l'intention (Chat ou Code). + """ - # Client compatible OpenAI pointant vers l'agrégateur OpenRouter - client = OpenAI(base_url="https://openrouter.ai/api/v1", api_key=api_key) - - # Liste de modèles 100% gratuits et performants sur OpenRouter - modeles = [ - "meta-llama/llama-3.1-8b-instruct:free", - "mistralai/mistral-7b-instruct:free", - "google/gemma-2-9b-it:free", - "microsoft/phi-3-mini-128k-instruct:free" - ] - - for modele in modeles: + # Sélection des modèles 100% gratuits et performants sur OpenRouter + if type_modele == "openrouter_code": + nom_modele_api = "qwen/qwen-2.5-coder-32b-instruct:free" + nom_affichage = "OpenRouter (Qwen Coder - Gratuit)" + couleur = "#10a37f" # Vert émeraude + else: + nom_modele_api = "meta-llama/llama-3.1-8b-instruct:free" + nom_affichage = "OpenRouter (Llama 3.1 - Gratuit)" + couleur = "#4a90e2" # Bleu clair + + for tentative in range(max_retries): try: - resp = client.chat.completions.create( - model=modele, - messages=[ - {"role": "system", "content": "Réponds en français et en format Markdown."}, - {"role": "user", "content": prompt_securise} - ] + start_time = time.time() + response = client.chat.completions.create( + model=nom_modele_api, + messages=[{"role": "user", "content": prompt}] ) - if resp and resp.choices: - log_event("INFO", f"OPENROUTER-{modele}", "Succès de la requête.") - return resp.choices[0].message.content, "#8b5cf6", "OPENROUTER (Gratuit)", modele + texte = response.choices[0].message.content + return texte, couleur, "OpenRouter", nom_affichage + + except openai.RateLimitError as e: + temps_attente = 2 ** tentative + log_event("WARNING", "OPENROUTER", f"Limite de taux atteinte (429). Essai {tentative + 1}/{max_retries}. Attente de {temps_attente}s...") + time.sleep(temps_attente) + if tentative == max_retries - 1: + log_event("ERROR", "OPENROUTER", "Échec définitif suite aux limites de taux (429).") + raise Exception("Service temporairement saturé. Veuillez réessayer.") + + except openai.APIStatusError as e: + if e.status_code == 402: + log_event("CRITICAL", "OPENROUTER", "Erreur 402 : Fonds insuffisants ou limite de clé atteinte.") + raise Exception("Action requise : Limite de facturation atteinte sur OpenRouter.") + else: + log_event("ERROR", "OPENROUTER", f"Code {e.status_code} : {e.message}") + raise Exception(f"Erreur API OpenRouter : {e.status_code}") + + except openai.APIConnectionError as e: + log_event("ERROR", "OPENROUTER", f"Erreur réseau : {e}") + raise Exception("Impossible de joindre les serveurs d'OpenRouter.") + except Exception as e: - log_event("WARNING", f"OPENROUTER-{modele}", f"Erreur: {e}") + log_event("ERROR", "OPENROUTER", f"Erreur inattendue : {e}") + raise e - raise Exception("Tous les modèles gratuits OpenRouter ont échoué.") \ No newline at end of file + return None, None, None, None \ No newline at end of file diff --git a/modules/chat_handler.py b/modules/chat_handler.py index 83a72bd..bd871fa 100644 --- a/modules/chat_handler.py +++ b/modules/chat_handler.py @@ -33,26 +33,24 @@ async def handle_chat_request(request, session): liste_fichiers_str = ', '.join(file_names) if file_names else 'Aucun fichier' log_event("INFO", "SYSTEM", f"Requête reçue. Fichiers joints : {liste_fichiers_str}") - # L'IA Local (Qwen) orchestre la décision ! + # L'IA Local (Qwen) orchestre la décision ! Focus sur l'efficience. sec_prompt = f"""Tu es l'Orchestrateur système. Analyse la requête et choisis le meilleur fournisseur IA : - - "gemini" : (OBLIGATOIRE si fichiers joints), rédaction complexe, comparaisons ou images. - - "groq" : texte ultra-rapide. - - "deepseek" : code, mathématiques, logique complexe. - - "mistral" : rédaction française soignée. - - "huggingface" : modèles open-source. - - "cloudflare" : requêtes générales. - - "local" : questions basiques, salutations. - Renvoie STRICTEMENT un JSON : {{"intention": "Résumé...", "fournisseur": "gemini|groq|deepseek|mistral|huggingface|cloudflare|local"}} + - "gemini" : (OBLIGATOIRE si fichiers joints), rédaction complexe, comparaisons ou recherches web. + - "openrouter_chat" : requêtes générales, texte rapide, traduction, bureautique (Modèles gratuits). + - "openrouter_code" : programmation, scripts, mathématiques, logique (Modèles gratuits). + - "local" : salutations basiques, questions très simples. + Renvoie STRICTEMENT un JSON : {{"intention": "Résumé...", "fournisseur": "gemini|openrouter_chat|openrouter_code|local"}} Requête : {prompt}""" try: + # Qwen 2.5 3B reste le meilleur compromis VRAM/Efficience pour votre GTX 1650 texte_routeur, _, _, _ = interroger_local_ollama(sec_prompt, "qwen2.5:3b") decision = nettoyer_decision_router(texte_routeur) except Exception: decision = {"intention": "Analyse de secours", "fournisseur": "gemini"} intention = decision.get('intention', 'Analyse') - fournisseur = decision.get('fournisseur', 'gemini').lower() + fournisseur = decision.get('fournisseur', 'openrouter_chat').lower() # Sécurité Absolue Fichiers -> Gemini (Fenêtre de contexte maximale) if file_names: diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..8ae0e31 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,11 @@ +python-fasthtml +openai +google-generativeai +psutil +pandas +openpyxl +reportlab +requests +beautifulsoup4 +python-dotenv +uvicorn \ No newline at end of file