Public Access
maj auto 3
This commit is contained in:
1 parent
4fb378a4c5
commit
f5dc6bf951
5 files changed
-306
No files matched your search
@@ -1,33 +0,0 @@
|
|||||||
import os
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
from openai import OpenAI
|
|
||||||
from groq import Groq
|
|
||||||
from google import genai
|
|
||||||
|
|
||||||
# Chargement des variables d'environnement en premier
|
|
||||||
load_dotenv()
|
|
||||||
|
|
||||||
local_client = OpenAI(base_url="http://192.168.1.20:11434/v1", api_key="ollama")
|
|
||||||
groq_client = Groq(api_key=os.getenv("GROQ_API_KEY"))
|
|
||||||
gemini_client = genai.Client(api_key=os.getenv("GEMINI_API_KEY"))
|
|
||||||
|
|
||||||
def interroger_gemini_cascade(prompt):
|
|
||||||
modeles_a_tester = ["gemini-3.1-pro-preview", "gemini-3.1-pro", "gemini-2.5-pro", "gemini-3.7-flash", "gemini-3.6-flash"]
|
|
||||||
for nom_modele in modeles_a_tester:
|
|
||||||
try:
|
|
||||||
config = {"system_instruction": "Réponds toujours dans la langue de l'utilisateur. Utilise exclusivement le format Markdown pour les tableaux et la mise en forme. N'utilise JAMAIS de code LaTeX."}
|
|
||||||
chat = gemini_client.chats.create(model=nom_modele, config=config)
|
|
||||||
ia_response = chat.send_message(prompt)
|
|
||||||
if not ia_response.text:
|
|
||||||
raise Exception("Réponse vide de Google.")
|
|
||||||
return ia_response.text, nom_modele
|
|
||||||
except Exception:
|
|
||||||
continue
|
|
||||||
raise Exception("Tous les modèles Gemini sont indisponibles actuellement.")
|
|
||||||
|
|
||||||
def appeler_groq_api(prompt_text):
|
|
||||||
resp = groq_client.chat.completions.create(
|
|
||||||
messages=[{"role": "system", "content": "Réponds dans la langue de l'utilisateur. Tu as accès aux recherches web fournies. Utilise uniquement Markdown. Pas de code LaTeX."}, {"role": "user", "content": prompt_text}],
|
|
||||||
model="llama-3.3-70b-versatile"
|
|
||||||
)
|
|
||||||
return resp.choices[0].message.content, "#f97316", "GROQ", "llama-3.3-70b"
|
|
||||||
-27
@@ -1,27 +0,0 @@
|
|||||||
import os
|
|
||||||
import json
|
|
||||||
import time
|
|
||||||
|
|
||||||
HISTORY_FILE = "aethas_history.json"
|
|
||||||
|
|
||||||
def load_history():
|
|
||||||
if not os.path.exists(HISTORY_FILE):
|
|
||||||
with open(HISTORY_FILE, 'w', encoding='utf-8') as f:
|
|
||||||
json.dump({}, f)
|
|
||||||
with open(HISTORY_FILE, 'r', encoding='utf-8') as f:
|
|
||||||
return json.load(f)
|
|
||||||
|
|
||||||
def save_history(history):
|
|
||||||
with open(HISTORY_FILE, 'w', encoding='utf-8') as f:
|
|
||||||
json.dump(history, f, indent=4)
|
|
||||||
|
|
||||||
def nettoyer_vieilles_discussions():
|
|
||||||
history = load_history()
|
|
||||||
now = time.time()
|
|
||||||
un_an_en_secondes = 365 * 24 * 60 * 60
|
|
||||||
a_supprimer = [cid for cid, data in history.items() if not data.get('pinned', False) and now - data.get('timestamp', now) > un_an_en_secondes]
|
|
||||||
if a_supprimer:
|
|
||||||
for cid in a_supprimer:
|
|
||||||
del history[cid]
|
|
||||||
save_history(history)
|
|
||||||
print(f"🧹 AETHAS CORE : Nettoyage auto terminé. {len(a_supprimer)} discussion(s) supprimée(s).")
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
import json
|
|
||||||
import re
|
|
||||||
|
|
||||||
def nettoyer_decision_router(raw_text):
|
|
||||||
try:
|
|
||||||
clean = re.sub(r'```(?:json)?\s*', '', raw_text)
|
|
||||||
clean = clean.replace('```', '').strip()
|
|
||||||
start = clean.find('{')
|
|
||||||
end = clean.rfind('}') + 1
|
|
||||||
if start != -1 and end != 0:
|
|
||||||
return json.loads(clean[start:end])
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
return {"intention": "Analyse", "fournisseur": "gemini"}
|
|
||||||
-42
@@ -1,42 +0,0 @@
|
|||||||
import requests
|
|
||||||
from bs4 import BeautifulSoup
|
|
||||||
|
|
||||||
def rechercher_sur_google(requete):
|
|
||||||
try:
|
|
||||||
url = f"https://lite.duckduckgo.com/lite/"
|
|
||||||
data = {'q': requete}
|
|
||||||
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"}
|
|
||||||
resp = requests.post(url, data=data, headers=headers, timeout=5)
|
|
||||||
soup = BeautifulSoup(resp.text, 'html.parser')
|
|
||||||
|
|
||||||
urls = []
|
|
||||||
for a in soup.find_all('a', class_='result-link', href=True):
|
|
||||||
href = a['href']
|
|
||||||
if href.startswith('http') and 'duckduckgo' not in href:
|
|
||||||
urls.append(href)
|
|
||||||
if len(urls) >= 5:
|
|
||||||
break
|
|
||||||
if not urls:
|
|
||||||
for a in soup.find_all('a', href=True):
|
|
||||||
href = a['href']
|
|
||||||
if href.startswith('http') and 'duckduckgo' not in href and href not in urls:
|
|
||||||
urls.append(href)
|
|
||||||
if len(urls) >= 5:
|
|
||||||
break
|
|
||||||
return urls[:5]
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Erreur recherche web: {e}")
|
|
||||||
return []
|
|
||||||
|
|
||||||
def extraire_contenu_urls(urls_list):
|
|
||||||
scraped_text = ""
|
|
||||||
for url in urls_list:
|
|
||||||
try:
|
|
||||||
resp = requests.get(url, timeout=5, headers={"User-Agent": "Mozilla/5.0"})
|
|
||||||
soup = BeautifulSoup(resp.text, 'html.parser')
|
|
||||||
for script in soup(["script", "style", "nav", "footer"]):
|
|
||||||
script.extract()
|
|
||||||
scraped_text += f"\n\n--- Source web extraite ({url}) ---\n{soup.get_text(separator=' ', strip=True)[:3000]}"
|
|
||||||
except Exception as e:
|
|
||||||
scraped_text += f"\n\n[Impossible de récupérer {url}: {e}]"
|
|
||||||
return scraped_text
|
|
||||||
@@ -1,190 +0,0 @@
|
|||||||
import os
|
|
||||||
|
|
||||||
# Création du dossier de rangement
|
|
||||||
os.makedirs("modules", exist_ok=True)
|
|
||||||
|
|
||||||
# 1. database.py
|
|
||||||
with open("modules/database.py", "w", encoding="utf-8") as f:
|
|
||||||
f.write('''import os
|
|
||||||
import json
|
|
||||||
import time
|
|
||||||
|
|
||||||
HISTORY_FILE = "aethas_history.json"
|
|
||||||
|
|
||||||
def load_history():
|
|
||||||
if not os.path.exists(HISTORY_FILE):
|
|
||||||
with open(HISTORY_FILE, 'w', encoding='utf-8') as f:
|
|
||||||
json.dump({}, f)
|
|
||||||
with open(HISTORY_FILE, 'r', encoding='utf-8') as f:
|
|
||||||
return json.load(f)
|
|
||||||
|
|
||||||
def save_history(history):
|
|
||||||
with open(HISTORY_FILE, 'w', encoding='utf-8') as f:
|
|
||||||
json.dump(history, f, indent=4)
|
|
||||||
|
|
||||||
def nettoyer_vieilles_discussions():
|
|
||||||
history = load_history()
|
|
||||||
now = time.time()
|
|
||||||
un_an_en_secondes = 365 * 24 * 60 * 60
|
|
||||||
a_supprimer = [cid for cid, data in history.items() if not data.get('pinned', False) and now - data.get('timestamp', now) > un_an_en_secondes]
|
|
||||||
if a_supprimer:
|
|
||||||
for cid in a_supprimer:
|
|
||||||
del history[cid]
|
|
||||||
save_history(history)
|
|
||||||
print(f"🧹 AETHAS CORE : Nettoyage auto terminé. {len(a_supprimer)} discussion(s) supprimée(s).")
|
|
||||||
''')
|
|
||||||
|
|
||||||
# 2. scraper.py
|
|
||||||
with open("modules/scraper.py", "w", encoding="utf-8") as f:
|
|
||||||
f.write('''import requests
|
|
||||||
from bs4 import BeautifulSoup
|
|
||||||
|
|
||||||
def rechercher_sur_google(requete):
|
|
||||||
try:
|
|
||||||
url = "https://lite.duckduckgo.com/lite/"
|
|
||||||
data = {'q': requete}
|
|
||||||
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"}
|
|
||||||
resp = requests.post(url, data=data, headers=headers, timeout=5)
|
|
||||||
soup = BeautifulSoup(resp.text, 'html.parser')
|
|
||||||
|
|
||||||
urls = []
|
|
||||||
for a in soup.find_all('a', class_='result-link', href=True):
|
|
||||||
href = a['href']
|
|
||||||
if href.startswith('http') and 'duckduckgo' not in href:
|
|
||||||
urls.append(href)
|
|
||||||
if len(urls) >= 5:
|
|
||||||
break
|
|
||||||
if not urls:
|
|
||||||
for a in soup.find_all('a', href=True):
|
|
||||||
href = a['href']
|
|
||||||
if href.startswith('http') and 'duckduckgo' not in href and href not in urls:
|
|
||||||
urls.append(href)
|
|
||||||
if len(urls) >= 5:
|
|
||||||
break
|
|
||||||
return urls[:5]
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Erreur recherche web: {e}")
|
|
||||||
return []
|
|
||||||
|
|
||||||
def extraire_contenu_urls(urls_list):
|
|
||||||
scraped_text = ""
|
|
||||||
for url in urls_list:
|
|
||||||
try:
|
|
||||||
resp = requests.get(url, timeout=5, headers={"User-Agent": "Mozilla/5.0"})
|
|
||||||
soup = BeautifulSoup(resp.text, 'html.parser')
|
|
||||||
for script in soup(["script", "style", "nav", "footer"]):
|
|
||||||
script.extract()
|
|
||||||
scraped_text += f"\\n\\n--- Source web extraite ({url}) ---\\n{soup.get_text(separator=' ', strip=True)[:3000]}"
|
|
||||||
except Exception as e:
|
|
||||||
scraped_text += f"\\n\\n[Impossible de récupérer {url}: {e}]"
|
|
||||||
return scraped_text
|
|
||||||
''')
|
|
||||||
|
|
||||||
# 3. ai_engine.py (Contient les clients et l'accès OpenAI)
|
|
||||||
with open("modules/ai_engine.py", "w", encoding="utf-8") as f:
|
|
||||||
f.write('''import os
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
from openai import OpenAI
|
|
||||||
from groq import Groq
|
|
||||||
from google import genai
|
|
||||||
|
|
||||||
load_dotenv()
|
|
||||||
|
|
||||||
local_client = OpenAI(base_url="http://192.168.1.20:11434/v1", api_key="ollama")
|
|
||||||
groq_client = Groq(api_key=os.getenv("GROQ_API_KEY"))
|
|
||||||
gemini_client = genai.Client(api_key=os.getenv("GEMINI_API_KEY"))
|
|
||||||
|
|
||||||
def interroger_gemini_cascade(prompt):
|
|
||||||
modeles_a_tester = ["gemini-3.1-pro-preview", "gemini-3.1-pro", "gemini-2.5-pro", "gemini-3.7-flash", "gemini-3.6-flash"]
|
|
||||||
for nom_modele in modeles_a_tester:
|
|
||||||
try:
|
|
||||||
config = {"system_instruction": "Réponds toujours dans la langue de l'utilisateur. Utilise exclusivement le format Markdown pour les tableaux et la mise en forme. N'utilise JAMAIS de code LaTeX."}
|
|
||||||
chat = gemini_client.chats.create(model=nom_modele, config=config)
|
|
||||||
ia_response = chat.send_message(prompt)
|
|
||||||
if not ia_response.text:
|
|
||||||
raise Exception("Réponse vide de Google.")
|
|
||||||
return ia_response.text, nom_modele
|
|
||||||
except Exception:
|
|
||||||
continue
|
|
||||||
raise Exception("Tous les modèles Gemini sont indisponibles actuellement.")
|
|
||||||
|
|
||||||
def appeler_groq_api(prompt_text):
|
|
||||||
resp = groq_client.chat.completions.create(
|
|
||||||
messages=[{"role": "system", "content": "Réponds dans la langue de l'utilisateur. Tu as accès aux recherches web fournies. Utilise uniquement Markdown. Pas de code LaTeX."}, {"role": "user", "content": prompt_text}],
|
|
||||||
model="llama-3.3-70b-versatile"
|
|
||||||
)
|
|
||||||
return resp.choices[0].message.content, "#f97316", "GROQ", "llama-3.3-70b"
|
|
||||||
''')
|
|
||||||
|
|
||||||
# 4. router.py
|
|
||||||
with open("modules/router.py", "w", encoding="utf-8") as f:
|
|
||||||
f.write('''import json
|
|
||||||
import re
|
|
||||||
|
|
||||||
def nettoyer_decision_router(raw_text):
|
|
||||||
try:
|
|
||||||
clean = re.sub(r'```(?:json)?\\s*', '', raw_text)
|
|
||||||
clean = clean.replace('```', '').strip()
|
|
||||||
start = clean.find('{')
|
|
||||||
end = clean.rfind('}') + 1
|
|
||||||
if start != -1 and end != 0:
|
|
||||||
return json.loads(clean[start:end])
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
return {"intention": "Analyse", "fournisseur": "gemini"}
|
|
||||||
''')
|
|
||||||
|
|
||||||
# 5. ui_components.py (Gestion de l'affichage UI et sidebar)
|
|
||||||
with open("modules/ui_components.py", "w", encoding="utf-8") as f:
|
|
||||||
f.write('''from fasthtml.common import *
|
|
||||||
from modules.database import load_history
|
|
||||||
|
|
||||||
def render_user_msg(text):
|
|
||||||
return Div(P(text, style="margin:0; font-weight:bold; white-space: pre-wrap;"), cls="user-bubble")
|
|
||||||
|
|
||||||
def render_ai_msg(text, intention, nom_fournisseur, nom_modele, couleur):
|
|
||||||
encart_info = Div(
|
|
||||||
Span(f"🎯 {intention}", style="margin-right: 10px; color:#aaa; font-size:0.8em;"),
|
|
||||||
Span(f"🏢 {nom_fournisseur}", style="margin-right: 10px; color:#aaa; font-size:0.8em;"),
|
|
||||||
Span(f"🧠 {nom_modele}", style=f"margin-right: 10px; color:{couleur}; font-weight:bold; font-size:0.8em;"),
|
|
||||||
style="border-bottom: 1px solid #333; padding-bottom: 10px; margin-bottom: 15px; display: flex; flex-wrap: wrap; gap: 5px;"
|
|
||||||
)
|
|
||||||
|
|
||||||
actions = Div(
|
|
||||||
Button("📄 PDF", onclick="downloadResponsePDF(this)", cls="msg-action-btn", title="Télécharger en PDF"),
|
|
||||||
Button("📘 DOC", onclick="downloadResponseDOC(this)", cls="msg-action-btn", title="Télécharger en Word"),
|
|
||||||
Button("📝 TXT", onclick="downloadResponseTXT(this)", cls="msg-action-btn", title="Télécharger en Texte"),
|
|
||||||
Button("🗄️ JSON", onclick="downloadResponseJSON(this)", cls="msg-action-btn", title="Télécharger en JSON"),
|
|
||||||
Button("💬 WhatsApp", onclick="shareWhatsApp(this)", cls="msg-action-btn", title="Partager sur WhatsApp"),
|
|
||||||
Button("📧 Email", onclick="shareEmail(this)", cls="msg-action-btn", title="Envoyer par Email"),
|
|
||||||
cls="msg-actions"
|
|
||||||
)
|
|
||||||
|
|
||||||
return Div(
|
|
||||||
encart_info,
|
|
||||||
Div(text, cls="markdown-raw", style="display:none;"),
|
|
||||||
Div(cls="markdown-rendered", style="line-height: 1.6;"),
|
|
||||||
actions,
|
|
||||||
cls="ai-bubble", style=f"border-left: 4px solid {couleur};"
|
|
||||||
)
|
|
||||||
|
|
||||||
def render_sidebar():
|
|
||||||
history = load_history()
|
|
||||||
sorted_chats = sorted(history.items(), key=lambda x: (not x[1].get('pinned', False), -x[1].get('timestamp', 0)))
|
|
||||||
|
|
||||||
items = []
|
|
||||||
for chat_id, data in sorted_chats:
|
|
||||||
pin_icon = "📌" if data.get('pinned', False) else "📍"
|
|
||||||
items.append(
|
|
||||||
Div(
|
|
||||||
A(Span(data['title'], style="color:inherit;"), href=f"/load_chat/{chat_id}", cls="history-link"),
|
|
||||||
Button(pin_icon, cls="history-btn", hx_post=f"/pin/{chat_id}", hx_target="#sidebar-content", hx_swap="outerHTML"),
|
|
||||||
Button("✏️", cls="history-btn", hx_post=f"/rename/{chat_id}", hx_prompt="Nouveau nom :", hx_target="#sidebar-content", hx_swap="outerHTML"),
|
|
||||||
Button("🗑️", cls="history-btn", hx_post=f"/delete/{chat_id}", hx_target="#sidebar-content", hx_swap="outerHTML"),
|
|
||||||
cls="history-item", id=f"chat-item-{chat_id}"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
return Div(*items, id="sidebar-content", cls="sidebar-history", hx_swap_oob="true")
|
|
||||||
''')
|
|
||||||
|
|
||||||
print("📁 Dossier 'modules/' et sous-scripts générés avec succès !")
|
|
||||||
Reference in new issue
Block a user