Public Access
maj auto 1
This commit is contained in:
1 parent
a8f9ab28ed
commit
d47bd67391
2 files changed
+151
-72
No files matched your search
@@ -7,6 +7,7 @@ import requests
|
||||
from bs4 import BeautifulSoup
|
||||
from dotenv import load_dotenv
|
||||
from fasthtml.common import *
|
||||
from starlette.responses import FileResponse
|
||||
from openai import OpenAI
|
||||
from groq import Groq
|
||||
from google import genai
|
||||
@@ -25,6 +26,26 @@ def load_history():
|
||||
def save_history(history):
|
||||
with open(HISTORY_FILE, 'w', encoding='utf-8') as f: json.dump(history, f, indent=4)
|
||||
|
||||
# --- SCRIPT DE NETTOYAGE AUTO ---
|
||||
def nettoyer_vieilles_discussions():
|
||||
history = load_history()
|
||||
now = time.time()
|
||||
un_an_en_secondes = 365 * 24 * 60 * 60
|
||||
a_supprimer = []
|
||||
|
||||
for chat_id, data in history.items():
|
||||
if not data.get('pinned', False):
|
||||
if now - data.get('timestamp', now) > un_an_en_secondes:
|
||||
a_supprimer.append(chat_id)
|
||||
|
||||
if a_supprimer:
|
||||
for chat_id in a_supprimer:
|
||||
del history[chat_id]
|
||||
save_history(history)
|
||||
print(f"🧹 AETHAS CORE : Nettoyage auto terminé. {len(a_supprimer)} discussion(s) de plus de 365 jours supprimée(s).")
|
||||
|
||||
nettoyer_vieilles_discussions()
|
||||
|
||||
svg_favicon = "%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Cstyle%3E@keyframes pulse { 0% { opacity: 1; stroke-width: 5; } 50% { opacity: 0.5; stroke-width: 7; } 100% { opacity: 1; stroke-width: 5; } } .neon { animation: pulse 2s infinite; transform-origin: 50px 50px; transform: rotate(45deg); }%3C/style%3E%3Crect width='100' height='100' fill='%23121212'/%3E%3Cg class='neon'%3E%3Crect x='25' y='25' width='50' height='50' fill='none' stroke='%2300e5ff'/%3E%3Cpath d='M25 50 L75 50 M50 25 L50 75' stroke='%23b300ff'/%3E%3Ccircle cx='50' cy='50' r='8' fill='%23e0e0e0'/%3E%3C/g%3E%3C/svg%3E"
|
||||
|
||||
theme_hdrs = (
|
||||
@@ -43,11 +64,10 @@ theme_hdrs = (
|
||||
.sidebar-history { flex: 1; overflow-y: auto; margin-top: 15px; margin-bottom: 15px; }
|
||||
.sidebar-footer { flex-shrink: 0; border-top: 1px solid #333; padding-top: 15px; text-align: center; }
|
||||
|
||||
/* CORRECTION: Boutons disposés en colonne proprement */
|
||||
.nav-buttons { display: flex; flex-direction: column; gap: 10px; margin-bottom: 20px; }
|
||||
.new-chat-btn { display:block; text-align:center; text-decoration:none; background: transparent; border: 1px solid var(--accent-blue); color: var(--accent-blue); padding: 10px; border-radius: 5px; cursor: pointer; font-weight: bold; transition: 0.2s; }
|
||||
.new-chat-btn:hover { background: rgba(0, 229, 255, 0.1); }
|
||||
.export-btn { background: #2a2a35; border: 1px solid #444; color: white; padding: 10px; border-radius: 5px; cursor: pointer; transition: 0.2s; font-size: 1em; text-align:center;}
|
||||
.export-btn { background: #2a2a35; border: 1px solid #444; color: white; padding: 10px; border-radius: 5px; cursor: pointer; transition: 0.2s; font-size: 1em; text-align:center; text-decoration:none; display:block;}
|
||||
.export-btn:hover { background: #444; }
|
||||
|
||||
.history-item { display: flex; justify-content: space-between; align-items: center; padding: 10px; border-bottom: 1px solid #222; font-size: 0.9em; transition: 0.2s; }
|
||||
@@ -86,64 +106,107 @@ theme_hdrs = (
|
||||
|
||||
.btn-submit { background: linear-gradient(135deg, var(--accent-blue), var(--accent-purple)); color: white; border: none; width: 36px !important; height: 36px !important; min-width: 36px !important; max-width: 36px !important; border-radius: 50%; display: flex; align-items: center; justify-content: center; cursor: pointer; font-size: 1.1em; flex-shrink: 0 !important; box-sizing: border-box; }
|
||||
.btn-submit:active { transform: scale(0.95); }
|
||||
|
||||
.htmx-indicator { display: none; }
|
||||
.htmx-request .htmx-indicator { display: flex; }
|
||||
.htmx-request.htmx-indicator { display: flex; }
|
||||
|
||||
.tech-loader-container { display: flex; align-items: center; gap: 15px; color: var(--accent-blue); font-style: italic; background: var(--bg-panel); padding: 15px 20px; border-radius: 15px 15px 15px 0; border: 1px dashed var(--accent-blue); width: fit-content; margin-bottom: 20px; font-size: 0.9em; box-shadow: 0 0 10px rgba(0, 229, 255, 0.1); }
|
||||
.tech-spinner { width: 20px; height: 20px; border: 3px solid rgba(0, 229, 255, 0.2); border-top-color: var(--accent-blue); border-radius: 50%; animation: spin 1s linear infinite; }
|
||||
@keyframes spin { to { transform: rotate(360deg); } }
|
||||
"""),
|
||||
|
||||
Script("""
|
||||
function renderMarkdown() {
|
||||
document.querySelectorAll('.markdown-raw').forEach(el => {
|
||||
let container = el.nextElementSibling;
|
||||
container.innerHTML = marked.parse(el.textContent);
|
||||
el.classList.remove('markdown-raw');
|
||||
|
||||
container.querySelectorAll('pre').forEach(pre => {
|
||||
let code = pre.querySelector('code');
|
||||
let lang = code.className.replace('language-', '') || 'texte';
|
||||
let header = document.createElement('div');
|
||||
header.className = 'code-header';
|
||||
header.innerHTML = `<span style="color:#00e5ff; font-weight:bold;">${lang.toUpperCase()}</span><div><button onclick="copyCode(this)">📋 Copier</button></div>`;
|
||||
pre.parentNode.insertBefore(header, pre);
|
||||
hljs.highlightElement(code);
|
||||
try {
|
||||
document.querySelectorAll('.markdown-raw').forEach(el => {
|
||||
if (el.dataset.rendered) return;
|
||||
let container = el.nextElementSibling;
|
||||
|
||||
if (typeof marked !== 'undefined') {
|
||||
container.innerHTML = marked.parse(el.textContent);
|
||||
} else {
|
||||
container.innerText = el.textContent;
|
||||
}
|
||||
|
||||
el.dataset.rendered = "true";
|
||||
el.classList.remove('markdown-raw');
|
||||
|
||||
container.querySelectorAll('pre').forEach(pre => {
|
||||
try {
|
||||
let code = pre.querySelector('code');
|
||||
if(code) {
|
||||
let rawLang = code.className.replace('language-', '') || 'texte';
|
||||
let lang = rawLang.toUpperCase();
|
||||
let header = document.createElement('div');
|
||||
header.className = 'code-header';
|
||||
header.innerHTML = '<span style="color:#00e5ff; font-weight:bold;">' + lang + '</span><div><button onclick="copyCode(this)">📋 Copier</button></div>';
|
||||
pre.parentNode.insertBefore(header, pre);
|
||||
if (typeof hljs !== 'undefined') hljs.highlightElement(code);
|
||||
}
|
||||
} catch(err) { console.warn("Aethas - Erreur formatage code", err); }
|
||||
});
|
||||
});
|
||||
});
|
||||
let chat = document.getElementById('chat-history');
|
||||
chat.scrollTop = chat.scrollHeight;
|
||||
let chat = document.getElementById('chat-history');
|
||||
if (chat) chat.scrollTop = chat.scrollHeight;
|
||||
} catch(globalErr) {
|
||||
console.error("Aethas - Erreur fatale rendu Markdown", globalErr);
|
||||
}
|
||||
}
|
||||
|
||||
// --- SCRIPTS D'EXPORTATION ---
|
||||
function downloadResponsePDF(btn) {
|
||||
let content = btn.closest('.ai-bubble').querySelector('.markdown-rendered');
|
||||
let originalColor = content.style.color;
|
||||
let originalBg = content.style.backgroundColor;
|
||||
|
||||
// Forçage du texte en noir sur blanc pour le PDF
|
||||
content.style.color = '#000000';
|
||||
content.style.backgroundColor = '#ffffff';
|
||||
content.style.padding = '20px';
|
||||
|
||||
let opt = {
|
||||
margin: 10,
|
||||
filename: 'Aethas38_Reponse.pdf',
|
||||
image: { type: 'jpeg', quality: 0.98 },
|
||||
html2canvas: { scale: 2, backgroundColor: '#ffffff' },
|
||||
jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' }
|
||||
};
|
||||
|
||||
html2pdf().set(opt).from(content).save().then(() => {
|
||||
content.style.color = originalColor;
|
||||
content.style.backgroundColor = originalBg;
|
||||
content.style.padding = '';
|
||||
});
|
||||
try {
|
||||
let renderedNode = btn.closest('.ai-bubble').querySelector('.markdown-rendered');
|
||||
let rawNode = btn.closest('.ai-bubble').querySelector('.markdown-raw');
|
||||
let originalContent = (renderedNode && renderedNode.innerHTML.trim() !== "") ? renderedNode : rawNode;
|
||||
|
||||
let content = originalContent.cloneNode(true);
|
||||
let wrapper = document.createElement('div');
|
||||
wrapper.style.backgroundColor = '#ffffff';
|
||||
wrapper.style.padding = '20px';
|
||||
wrapper.style.fontFamily = 'Arial, sans-serif';
|
||||
wrapper.style.color = '#000000';
|
||||
|
||||
content.querySelectorAll('*').forEach(el => {
|
||||
el.style.color = '#000000';
|
||||
if (el.tagName === 'PRE' || el.tagName === 'CODE' || el.tagName === 'TABLE' || el.tagName === 'TH' || el.tagName === 'TD') {
|
||||
el.style.backgroundColor = '#f4f4f4';
|
||||
el.style.borderColor = '#aaaaaa';
|
||||
el.style.borderWidth = '1px';
|
||||
el.style.borderStyle = 'solid';
|
||||
el.style.borderCollapse = 'collapse';
|
||||
} else {
|
||||
el.style.backgroundColor = 'transparent';
|
||||
}
|
||||
});
|
||||
|
||||
wrapper.appendChild(content);
|
||||
|
||||
let opt = {
|
||||
margin: 10,
|
||||
filename: 'Aethas38_Reponse.pdf',
|
||||
image: { type: 'jpeg', quality: 0.98 },
|
||||
html2canvas: { scale: 2, backgroundColor: '#ffffff', useCORS: true },
|
||||
jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' }
|
||||
};
|
||||
html2pdf().set(opt).from(wrapper).save();
|
||||
} catch (err) {
|
||||
alert("Erreur lors de la génération du PDF.");
|
||||
}
|
||||
}
|
||||
|
||||
function downloadResponseTXT(btn) {
|
||||
let content = btn.closest('.ai-bubble').querySelector('.markdown-rendered');
|
||||
let blob = new Blob([content.innerText], {type: 'text/plain;charset=utf-8'});
|
||||
let rendered = btn.closest('.ai-bubble').querySelector('.markdown-rendered').innerText;
|
||||
let raw = btn.closest('.ai-bubble').querySelector('.markdown-raw').innerText;
|
||||
let finalContent = rendered ? rendered : raw;
|
||||
let blob = new Blob([finalContent], {type: 'text/plain;charset=utf-8'});
|
||||
let link = document.createElement('a'); link.href = URL.createObjectURL(blob); link.download = 'Aethas38_Reponse.txt';
|
||||
document.body.appendChild(link); link.click(); document.body.removeChild(link);
|
||||
}
|
||||
|
||||
function downloadResponseDOC(btn) {
|
||||
let content = btn.closest('.ai-bubble').querySelector('.markdown-rendered').innerHTML;
|
||||
let renderedNode = btn.closest('.ai-bubble').querySelector('.markdown-rendered');
|
||||
let content = (renderedNode && renderedNode.innerHTML.trim() !== "") ? renderedNode.innerHTML : btn.closest('.ai-bubble').querySelector('.markdown-raw').innerText;
|
||||
let preHtml = "<html xmlns:o='urn:schemas-microsoft-com:office:office' xmlns:w='urn:schemas-microsoft-com:office:word' xmlns='http://www.w3.org/TR/REC-html40'><head><meta charset='utf-8'><title>Aethas Export</title></head><body style='font-family: Arial, sans-serif; color: #000000; background-color: #ffffff;'>";
|
||||
let postHtml = "</body></html>";
|
||||
let blob = new Blob(['\\ufeff', preHtml + content + postHtml], { type: 'application/msword' });
|
||||
@@ -152,8 +215,10 @@ theme_hdrs = (
|
||||
}
|
||||
|
||||
function downloadResponseJSON(btn) {
|
||||
let content = btn.closest('.ai-bubble').querySelector('.markdown-rendered').innerText;
|
||||
let data = { "timestamp": new Date().toISOString(), "content": content };
|
||||
let rendered = btn.closest('.ai-bubble').querySelector('.markdown-rendered').innerText;
|
||||
let raw = btn.closest('.ai-bubble').querySelector('.markdown-raw').innerText;
|
||||
let finalContent = rendered ? rendered : raw;
|
||||
let data = { "timestamp": new Date().toISOString(), "content": finalContent };
|
||||
let blob = new Blob([JSON.stringify(data, null, 2)], {type: 'application/json;charset=utf-8'});
|
||||
let link = document.createElement('a'); link.href = URL.createObjectURL(blob); link.download = 'Aethas38_Reponse.json';
|
||||
document.body.appendChild(link); link.click(); document.body.removeChild(link);
|
||||
@@ -167,29 +232,36 @@ theme_hdrs = (
|
||||
setTimeout(() => btn.innerText = "📋 Copier", 2000);
|
||||
}
|
||||
|
||||
function exportChat() {
|
||||
let chat = document.getElementById('chat-history');
|
||||
if(!chat) return;
|
||||
let blob = new Blob([chat.innerText], {type: 'text/plain;charset=utf-8'});
|
||||
let link = document.createElement('a'); link.href = URL.createObjectURL(blob); link.download = 'Aethas38_Discussion_Globale.txt';
|
||||
document.body.appendChild(link); link.click(); document.body.removeChild(link);
|
||||
}
|
||||
|
||||
function handleFileSelection(input) {
|
||||
let previewList = document.getElementById('file-preview-list');
|
||||
previewList.innerHTML = '';
|
||||
if (input.files) {
|
||||
for (let i = 0; i < input.files.length; i++) {
|
||||
let pill = document.createElement('div'); pill.className = 'file-pill'; pill.innerHTML = `📎 ${input.files[i].name}`;
|
||||
let pill = document.createElement('div'); pill.className = 'file-pill'; pill.innerHTML = '📎 ' + input.files[i].name;
|
||||
previewList.appendChild(pill);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function autoResize(textarea) {
|
||||
if(!textarea) return;
|
||||
textarea.style.height = 'auto';
|
||||
textarea.style.height = textarea.scrollHeight + 'px';
|
||||
}
|
||||
|
||||
function shareWhatsApp(btn) {
|
||||
let rendered = btn.closest('.ai-bubble').querySelector('.markdown-rendered').innerText;
|
||||
let raw = btn.closest('.ai-bubble').querySelector('.markdown-raw').innerText;
|
||||
let content = rendered ? rendered : raw;
|
||||
window.open('https://api.whatsapp.com/send?text=' + encodeURIComponent("🤖 *Aethas38 (IA) :*\n\n" + content), '_blank');
|
||||
}
|
||||
|
||||
function shareEmail(btn) {
|
||||
let rendered = btn.closest('.ai-bubble').querySelector('.markdown-rendered').innerText;
|
||||
let raw = btn.closest('.ai-bubble').querySelector('.markdown-raw').innerText;
|
||||
let content = rendered ? rendered : raw;
|
||||
window.open('mailto:?subject=Réponse Aethas38 IA&body=' + encodeURIComponent(content), '_self');
|
||||
}
|
||||
""")
|
||||
)
|
||||
|
||||
@@ -206,8 +278,11 @@ 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:
|
||||
chat = gemini_client.chats.create(model=nom_modele, config={"system_instruction": "Réponds toujours dans la langue de l'utilisateur."})
|
||||
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
|
||||
@@ -217,7 +292,6 @@ def rechercher_sur_google(requete):
|
||||
try:
|
||||
from googlesearch import search
|
||||
urls = []
|
||||
# Modification ici : num_results=5 au lieu de 3
|
||||
for url in search(requete, num_results=5, lang="fr"):
|
||||
urls.append(url)
|
||||
return urls
|
||||
@@ -276,6 +350,8 @@ def render_ai_msg(text, intention, nom_fournisseur, nom_modele, couleur):
|
||||
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"
|
||||
)
|
||||
|
||||
@@ -322,7 +398,7 @@ def get(session):
|
||||
messages_ui.append(render_ai_msg(msg['content'], msg.get('intention', ''), msg.get('fournisseur', ''), msg.get('modele', ''), msg.get('couleur', '#333')))
|
||||
|
||||
if messages_ui:
|
||||
messages_ui.append(Script("setTimeout(renderMarkdown, 100);"))
|
||||
messages_ui.append(Script("setTimeout(renderMarkdown, 150);"))
|
||||
|
||||
return Title("Aethas38 - Mine_AI"), Body(
|
||||
Div(
|
||||
@@ -330,7 +406,7 @@ def get(session):
|
||||
Div(H2("AETHAS 38", style="color:#00e5ff; margin:0; text-align:center;"), P("Tech Core", style="font-size:0.7em; color:#888; text-align:center;"), margin_bottom="20px"),
|
||||
Div(
|
||||
A("+ Nouvelle discussion", href="/new_chat", cls="new-chat-btn"),
|
||||
Button("💾 Exporter JSON", cls="export-btn", onclick="exportChat()", title="Télécharger la conversation Globale"),
|
||||
A("💾 Exporter JSON", href="/export_json", target="_blank", cls="export-btn", title="Télécharger la conversation Globale"),
|
||||
cls="nav-buttons"
|
||||
),
|
||||
cls="sidebar-top"
|
||||
@@ -344,7 +420,13 @@ def get(session):
|
||||
),
|
||||
|
||||
Div(
|
||||
Div(*messages_ui, id="chat-history", cls="chat-container"),
|
||||
Div(*messages_ui, id="chat-history", cls="chat-container", style="padding-bottom: 20px;"),
|
||||
|
||||
Div(
|
||||
Div(Div(cls="tech-spinner"), Span("Aethas Core analyse la requête..."), cls="tech-loader-container"),
|
||||
id="global-loader", cls="htmx-indicator", style="max-width: 1000px; margin: 0 auto; width: 100%; padding: 0 20px; box-sizing: border-box; padding-bottom: 120px;"
|
||||
),
|
||||
|
||||
Div(
|
||||
Form(
|
||||
Input(type="hidden", name="chat_id", value=chat_id),
|
||||
@@ -362,6 +444,7 @@ def get(session):
|
||||
hx_post="/chat",
|
||||
hx_target="#chat-history",
|
||||
hx_swap="beforeend",
|
||||
hx_indicator="#global-loader",
|
||||
hx_on__after_request="this.reset(); document.getElementById('file-preview-list').innerHTML=''; document.getElementById('prompt-input').style.height='auto';",
|
||||
enctype="multipart/form-data",
|
||||
style="width: 100%; display: flex; justify-content: center;"
|
||||
@@ -389,7 +472,6 @@ async def post(request, session: dict):
|
||||
|
||||
history = load_history()
|
||||
|
||||
# --- 1. INTELLIGENCE DE SÉCURITÉ DU ROUTEUR (Smarter Interceptor) ---
|
||||
security_check_prompt = f"""Tu es l'Aiguilleur du système Aethas38. Ton rôle EXCLUSIF est d'analyser et de router la demande.
|
||||
|
||||
RÈGLE DE SÉCURITÉ ABSOLUE : Les recherches web, les serveurs Minecraft, les modpacks (ex: ATM10) SONT AUTORISÉS.
|
||||
@@ -411,7 +493,6 @@ async def post(request, session: dict):
|
||||
intention = decision.get('intention', '')
|
||||
fournisseur = decision.get("fournisseur", "local").lower()
|
||||
|
||||
# Si Qwen détecte un VRAI danger
|
||||
if intention == "Alerte Securite":
|
||||
if chat_id not in history:
|
||||
history[chat_id] = {"title": "Alerte Sécurité...", "pinned": False, "timestamp": time.time(), "messages": []}
|
||||
@@ -423,7 +504,6 @@ async def post(request, session: dict):
|
||||
|
||||
return render_user_msg(prompt), render_ai_msg(reponse_securite, "Alerte Sécurité", "AETHAS CORE", "Cyber-Sec", "#ff0044"), Script("renderMarkdown();"), render_sidebar()
|
||||
|
||||
# --- 2. TRAITEMENT CLASSIQUE ---
|
||||
urls_to_scrape = re.findall(r'https?://[^\s]+', prompt)
|
||||
mots_cles = ["cherche sur", "recherche sur", "sur internet", "sur le web", "sur le net"]
|
||||
if any(mot in prompt.lower() for mot in mots_cles):
|
||||
@@ -451,25 +531,18 @@ async def post(request, session: dict):
|
||||
if web_content:
|
||||
full_prompt += f"\n\n[INSTRUCTION SYSTÈME STRICTE : Ne dis JAMAIS que tu ne peux pas naviguer sur internet ou télécharger des fichiers. Le système a déjà fait la recherche web pour toi. Voici le contenu brut extrait des sites. Utilise-le IMPÉRATIVEMENT pour formuler ta réponse sans mentionner tes propres limitations :]\n{web_content}"
|
||||
|
||||
prompt_tokens = len(full_prompt.split()) * 2
|
||||
completion_tokens = 0
|
||||
|
||||
# Fonction d'appel à Groq centralisée pour éviter la duplication de code
|
||||
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."}, {"role": "user", "content": prompt_text}],
|
||||
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"
|
||||
|
||||
if fournisseur == "gemini":
|
||||
try:
|
||||
# On tente Gemini en premier
|
||||
reponse_finale, nom_modele = interroger_gemini_cascade(full_prompt)
|
||||
couleur, nom_fournisseur = "#3b82f6", "GOOGLE GEMINI"
|
||||
completion_tokens = len(reponse_finale.split()) * 2
|
||||
except Exception as e_gemini:
|
||||
# 🔄 IA DE SECOURS : Si Gemini échoue, on bascule silencieusement sur Groq
|
||||
print(f"⚠️ Alerte système : Gemini indisponible ({e_gemini}). Bascule sur l'IA de secours (Groq)...")
|
||||
intention = intention + " (Secours Groq)"
|
||||
try:
|
||||
@@ -487,7 +560,7 @@ async def post(request, session: dict):
|
||||
|
||||
else:
|
||||
try:
|
||||
ia_response = local_client.chat.completions.create(model="qwen2.5:3b", messages=[{"role": "system", "content": "Réponds dans la langue de l'utilisateur."}, {"role": "user", "content": full_prompt}])
|
||||
ia_response = local_client.chat.completions.create(model="qwen2.5:3b", messages=[{"role": "system", "content": "Réponds dans la langue de l'utilisateur. Utilise le Markdown."}, {"role": "user", "content": full_prompt}])
|
||||
reponse_finale, couleur, nom_fournisseur, nom_modele = ia_response.choices[0].message.content, "#10b981", "SERVEUR LOCAL", "qwen2.5:3b"
|
||||
except Exception as e:
|
||||
reponse_finale, couleur, nom_fournisseur, nom_modele = f"Erreur Serveur Local : {e}", "#ff0000", "ERREUR LOCAL", "Qwen HS"
|
||||
@@ -560,5 +633,10 @@ def post(chat_id: str):
|
||||
save_history(history)
|
||||
return render_sidebar()
|
||||
|
||||
# --- ROUTE : EXPORT JSON COMPLET ---
|
||||
@rt('/export_json')
|
||||
def get():
|
||||
return FileResponse(HISTORY_FILE, media_type='application/json', filename='Aethas38_Discussion_Globale.json')
|
||||
|
||||
if __name__ == '__main__':
|
||||
serve(port=5001)
|
||||
Reference in new issue
Block a user