commit bc700dfb442e4769c3884114faf78a9ab621ce9d Author: Xavier Date: Sun Aug 16 08:09:59 2026 +0200 Initialisation ultra propre d'Aethas38 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..864e746 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +__pycache__/ +venv/ +.env +.sesskey \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..df8739f --- /dev/null +++ b/README.md @@ -0,0 +1,38 @@ +# Aethas38 - Multi-IA Orchestrator + +Système d'IA modulaire avec orchestrateur local et routeur intelligent. + +## 📋 To-Do List (Roadmap) + +### Phase 1 : Infrastructure & Environnement ✅ +- [x] Désactiver interface graphique serveur (mode headless) +- [x] Installation Docker, Compose et Nginx Proxy Manager +- [x] Configuration réseau (Pare-feu / Ports) +- [x] Initialisation dépôts Gitea/GitHub + +### Phase 2 : Orchestrateur Local (Backend) ⏳ +- [x] Installation Ollama + Qwen 2.5 3B (Serveur) +- [x] Développement de l'interface de base FastHTML +- [x] Connexion réussie entre PC de dev et Serveur IA +- [X] Développement du script de Routage (Gateway) +- [ ] Intégration des APIs tierces (Groq, Gemini, etc.) +- [ ] Système de gestion de file d'attente (Queue List) +- [ ] Création du système d'interdiction automatique (Fichiers refusés) + +### Phase 3 : Front-Office (FastHTML) +- [ ] Création UI légère (Thème Aethas) +- [ ] Implémentation du switch Gratuit/Payant +- [ ] Dashboard Finance (Analyse consommation tokens) +- [ ] Système d'inscription et validation Admin + +### Phase 4 : Déploiement & Sécurité +- [ ] Mise en conteneur Docker +- [ ] Mise en production sur aethas38.duckdns.org +- [ ] Tests de charge et vérification coûts + +--- +## 💡 Informations Techniques +* **Orchestrateur :** Local (Ollama / Qwen 2.5 3B) +* **Framework Interface :** FastHTML +* **Langage :** Python 3.12 (Environnement Virtuel) +* **Serveur :** Debian (Headless, GTX 1650 4Go VRAM) \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000..1c42fc2 --- /dev/null +++ b/main.py @@ -0,0 +1,85 @@ +import os +import json +from dotenv import load_dotenv +from fasthtml.common import * +from openai import OpenAI + +# Chargement du coffre-fort des clés API +load_dotenv() + +# Petit test pour vérifier que Python trouve bien les clés au démarrage +print("Vérification des API :") +print("- Groq chargée :", "✅" if os.getenv("GROQ_API_KEY") else "❌") +print("- Gemini chargée :", "✅" if os.getenv("GEMINI_API_KEY") else "❌") + +# Initialisation de l'application FastHTML +app, rt = fast_app() + +# Configuration du client local (Qwen) +client = OpenAI( + base_url="http://192.168.1.20:11434/v1", + api_key="ollama" +) + +# Route principale : l'interface utilisateur +@rt('/') +def get(): + return Titled("Aethas38 - Orchestrateur", + Main( + H1("Interface de Test - Qwen 2.5 (3B)"), + Form( + Input(type="text", name="prompt", placeholder="Posez votre question à Qwen...", style="width: 100%; padding: 10px; margin-bottom: 10px;"), + Button("Envoyer la requête", type="submit", style="padding: 10px 20px; cursor: pointer;"), + hx_post="/chat", # Envoie la requête à la route /chat + hx_target="#result", # Injecte la réponse dans la div "result" + hx_indicator="#loading" # Affiche un indicateur de chargement + ), + Div("Traitement en cours par le serveur Aethas38...", id="loading", cls="htmx-indicator", style="color: gray; font-style: italic; margin-top: 10px;"), + Div(id="result", style="margin-top: 20px; padding: 15px; border: 1px solid #444; border-radius: 5px; background-color: #222; color: white;"), + cls="container" + ) + ) + +# Route API : Traitement de la requête par l'IA +@rt('/chat') +def post(prompt: str): + try: + # 1. Le Prompt Système amélioré pour éviter les pièges + router_prompt = """Tu es l'Aiguilleur (Routeur) du projet Aethas38. + Analyse la demande de l'utilisateur et choisis le fournisseur d'IA le plus adapté selon ces règles strictes : + - "groq" : programmation, code, scripts, mathématiques, logique, informatique. + - "gemini" : rédaction, recettes de cuisine, culture générale, histoire, résumés, art. + - "local" : UNIQUEMENT pour les salutations (bonjour, test, coucou) ou les banalités très courtes. + + Format de réponse obligatoire : un objet JSON strict. AUCUN texte d'accompagnement. + Exemple 1 : {"intention": "créer un script", "fournisseur": "groq"} + Exemple 2 : {"intention": "recette de gâteau", "fournisseur": "gemini"} + """ + + # 2. On interroge notre Qwen local (la GTX 1650 bosse !) + response = client.chat.completions.create( + model="qwen2.5:3b", + messages=[ + {"role": "system", "content": router_prompt}, + {"role": "user", "content": prompt} + ], + temperature=0.1 # Température basse pour qu'il soit très précis et formel + ) + + # 3. On récupère et on lit sa décision brute + raw_decision = response.choices[0].message.content + + # 4. On l'affiche sur l'interface de test (temporaire, pour voir la magie opérer) + return Div( + P(f"🗣️ Votre question : {prompt}", style="color: #888;"), + P("🧠 Décision de l'Orchestrateur (Qwen) :", style="color: #00d2ff; font-weight: bold; margin-top: 10px;"), + Pre(raw_decision, style="background: #111; padding: 10px; border-radius: 5px; color: #0f0;"), + style="border-left: 4px solid #00d2ff; padding-left: 15px; margin-top: 15px;" + ) + + except Exception as e: + return P(f"Erreur de l'orchestrateur : {e}", style="color: red; font-weight: bold;") + +# Lancement du serveur local +if __name__ == '__main__': + serve(port=5001) \ No newline at end of file