Spaces:
Sleeping
Sleeping
Gouzi Mohaled
modification du fichier admin_pahe.py, adapatation de la logique d'extraction de l'url du chatbt selon qu'on est dans un contexte de développement ou de production
1b56d06
import streamlit as st | |
from typing import Dict, List, Optional, Tuple, Any, Callable, Awaitable | |
import pandas as pd | |
from datetime import datetime | |
import pytz | |
import re | |
import json | |
import asyncio | |
import os | |
from dotenv import load_dotenv | |
from urllib.parse import urlparse | |
from utils.admin import ( | |
get_all_users, | |
toggle_user_status, | |
change_user_role, | |
get_user_stats, | |
update_user_info, | |
get_user_permissions, | |
update_user_permissions, | |
supabase | |
) | |
from utils.theme_utils import apply_tooltip_and_button_styles | |
from utils.async_flowise import AsyncFlowiseClient | |
class FlowiseStreamingClient: | |
def __init__(self): | |
""" | |
Initialise le client de streaming pour les assistants Flowise | |
""" | |
self.flowise_client = AsyncFlowiseClient() | |
self.assistant_types = list(self.flowise_client.api_urls.keys()) | |
async def get_service_health(self) -> dict: | |
""" | |
Vérifie la santé des services Flowise | |
Returns: | |
dict: Un dictionnaire avec le statut de chaque assistant | |
""" | |
return await self.flowise_client.check_health() | |
async def stream_assistant_response( | |
self, | |
question: str, | |
assistant_type: str | |
) -> dict: | |
""" | |
Génère une réponse en streaming d'un assistant Flowise | |
Args: | |
question (str): La question à poser | |
assistant_type (str): Le type d'assistant à utiliser | |
Returns: | |
dict: Réponse finale de l'assistant | |
""" | |
# Vérifier si l'assistant type est valide | |
if assistant_type not in self.assistant_types: | |
return {"error": f"Type d'assistant non valide : {assistant_type}"} | |
full_response = "" | |
error = None | |
try: | |
response_stream = self.flowise_client.query_assistant_stream(question, assistant_type) | |
async for chunk in response_stream: | |
try: | |
chunk_data = json.loads(chunk) | |
if 'error' in chunk_data: | |
error = chunk_data['error'] | |
break | |
if 'data' in chunk_data: | |
# Extraire la partie de la réponse qui est nouvelle | |
new_part = chunk_data['data'][len(full_response):] | |
full_response = chunk_data['data'] | |
# Ajouter le nouveau morceau de réponse à l'historique du chat | |
add_message("assistant", new_part) | |
st.rerun() # Mettre à jour l'interface utilisateur | |
except json.JSONDecodeError: | |
error = "Erreur de décodage du chunk de réponse" | |
break | |
except Exception as e: | |
error = str(e) | |
# Fermer le client si nécessaire | |
await self.flowise_client.close() | |
# Retourner la réponse complète ou l'erreur | |
if error: | |
return {"error": error} | |
return {"answer": full_response} | |
def get_available_assistants(self) -> List[str]: | |
""" | |
Récupère la liste des assistants disponibles | |
Returns: | |
List[str]: Liste des types d'assistants | |
""" | |
return self.assistant_types | |
# Fonction d'exemple pour afficher le streaming dans la console | |
async def console_stream_callback(chunk: str): | |
""" | |
Callback par défaut pour afficher le streaming dans la console | |
Args: | |
chunk (str): Le nouveau morceau de réponse | |
""" | |
print(chunk, end='', flush=True) | |
def render_user_permissions(user_id: int): | |
""" | |
Affiche et gère les permissions d'accès aux assistants pour un utilisateur. | |
""" | |
current_permissions = get_user_permissions(user_id) | |
col1, col2 = st.columns(2) | |
with col1: | |
st.write("##### Colibri Vitalité ❣️") | |
is_sante_authorized = current_permissions.get('insuranceSANTE', False) | |
new_sante_state = st.toggle( | |
"Autoriser l'accès", | |
value=is_sante_authorized, | |
key=f"perm_{user_id}_sante" | |
) | |
if new_sante_state != is_sante_authorized: | |
success, msg = update_user_permissions(user_id, 'insuranceSANTE', new_sante_state) | |
if success: | |
st.success("✅ Accès mis à jour") | |
else: | |
st.error(f"❌ Erreur: {msg}") | |
st.write("##### Colibri Carburant 🚘") | |
is_car_authorized = current_permissions.get('insuranceCAR', False) | |
new_car_state = st.toggle( | |
"Autoriser l'accès", | |
value=is_car_authorized, | |
key=f"perm_{user_id}_car" | |
) | |
if new_car_state != is_car_authorized: | |
success, msg = update_user_permissions(user_id, 'insuranceCAR', new_car_state) | |
if success: | |
st.success("✅ Accès mis à jour") | |
else: | |
st.error(f"❌ Erreur: {msg}") | |
st.write("##### Colibri Batisseur 🏠") | |
is_btp_authorized = current_permissions.get('insuranceBTP', False) | |
new_btp_state = st.toggle( | |
"Autoriser l'accès", | |
value=is_btp_authorized, | |
key=f"perm_{user_id}_btp" | |
) | |
if new_btp_state != is_btp_authorized: | |
success, msg = update_user_permissions(user_id, 'insuranceBTP', new_btp_state) | |
if success: | |
st.success("✅ Accès mis à jour") | |
else: | |
st.error(f"❌ Erreur: {msg}") | |
with col2: | |
st.write("##### Colibri Equipage 🪪") | |
is_RH_authorized = current_permissions.get('RH', False) | |
new_RH_state = st.toggle( | |
"Autoriser l'accès", | |
value=is_RH_authorized, | |
key=f"perm_{user_id}_RH" | |
) | |
if new_RH_state != is_RH_authorized: | |
success, msg = update_user_permissions(user_id, 'RH', new_RH_state) | |
if success: | |
st.success("✅ Accès mis à jour") | |
else: | |
st.error(f"❌ Erreur: {msg}") | |
st.write("##### Colibri Tatillon 👨🏻✈️") | |
is_Pilotage_authorized = current_permissions.get('Pilotage', False) | |
new_Pilotage_state = st.toggle( | |
"Autoriser l'accès", | |
value=is_Pilotage_authorized, | |
help="Cet assistant permet de consulter et modifier les données de la base de données. Il est réservé aux administrateurs.", | |
key=f"perm_{user_id}_Pilotage" | |
) | |
if new_Pilotage_state != is_Pilotage_authorized: | |
success, msg = update_user_permissions(user_id, 'Pilotage', new_Pilotage_state) | |
if success: | |
st.success("✅ Accès mis à jour") | |
else: | |
st.error(f"❌ Erreur: {msg}") | |
def init_chat_history(): | |
"""Initialise l'historique du chat s'il n'existe pas""" | |
if "chat_history" not in st.session_state: | |
st.session_state.chat_history = [] | |
if "is_processing" not in st.session_state: | |
st.session_state.is_processing = False | |
if "message_feedback" not in st.session_state: | |
st.session_state.message_feedback = {} | |
def clean_message_content(content: str) -> str: | |
"""Nettoie le contenu du message des métadonnées JSON""" | |
try: | |
# Si le contenu est au format JSON | |
if content.strip().startswith('{'): | |
data = json.loads(content) | |
# Si c'est un message utilisateur, extraire la requête | |
if 'next_inputs' in data and 'query' in data['next_inputs']: | |
return data['next_inputs']['query'] | |
# Si c'est une réponse de l'assistant | |
if 'data' in data: | |
return data['data'] | |
return content | |
except: | |
return content | |
def add_message(role: str, content: str): | |
"""Ajoute un message à l'historique du chat""" | |
message_id = str(len(st.session_state.chat_history)) | |
cleaned_content = clean_message_content(content) | |
st.session_state.chat_history.append({ | |
"role": role, | |
"content": cleaned_content, | |
"message_id": message_id | |
}) | |
def update_message_feedback(message_id: str, feedback: str): | |
"""Met à jour le feedback d'un message""" | |
st.session_state.message_feedback[message_id] = feedback | |
def display_chat(): | |
"""Affiche l'historique du chat avec un style cohérent""" | |
for message in st.session_state.chat_history: | |
with st.chat_message(message["role"]): | |
st.markdown(message["content"]) | |
if message["role"] == "assistant": | |
message_id = message.get("message_id", "") | |
col1, col2, col3 = st.columns([1, 1, 10]) | |
with col1: | |
if st.button("👍", key=f"like_{message_id}"): | |
update_message_feedback(message_id, "positive") | |
st.rerun() | |
with col2: | |
if st.button("👎", key=f"dislike_{message_id}"): | |
update_message_feedback(message_id, "negative") | |
st.rerun() | |
with col3: | |
if message_id in st.session_state.message_feedback: | |
feedback = st.session_state.message_feedback[message_id] | |
st.write(f"Feedback: {'Positif' if feedback == 'positive' else 'Négatif'}") | |
async def render_admin_dashboard(): | |
"""Affiche le tableau de bord administrateur""" | |
if 'user' not in st.session_state or st.session_state['user'].get('role') != 'admin': | |
st.error("Accès non autorisé. Cette page est réservée aux administrateurs.") | |
return | |
current_theme = st.session_state.get('user_theme', 'Clair') | |
apply_tooltip_and_button_styles(current_theme) | |
if st.button("← Retour à l'interface principale"): | |
st.session_state['show_admin'] = False | |
st.rerun() | |
st.title("Dashboard Administrateur") | |
# Création des onglets avec le nouvel onglet de streaming | |
tab_users, tab_restrictions, tab_chatbot, tab_chatreact, testfooter, = st.tabs([ | |
"👥 Gestion Utilisateurs", | |
"🔒 Restrictions d'accès", | |
"💬 Chatbot", | |
"📡 Chat React", | |
" 🧪 Test Footer" | |
]) | |
# Onglet Gestion Utilisateurs | |
with tab_users: | |
stats = get_user_stats() | |
col1, col2, col3 = st.columns(3) | |
with col1: | |
st.metric("Total Utilisateurs", stats["total_users"]) | |
with col2: | |
st.metric("Utilisateurs Actifs", stats["active_users"]) | |
with col3: | |
st.metric("Administrateurs", stats["admin_users"]) | |
st.subheader("Gestion des Utilisateurs") | |
search_term = st.text_input("Rechercher un utilisateur par email ou nom:", "") | |
users = get_all_users() | |
if users: | |
df = pd.DataFrame(users) | |
if 'created_at' in df.columns: | |
df['created_at'] = pd.to_datetime(df['created_at']).dt.strftime('%Y-%m-%d %H:%M') | |
if 'last_login' in df.columns: | |
df['last_login'] = pd.to_datetime(df['last_login']).dt.strftime('%Y-%m-%d %H:%M') | |
display_columns = ['id', 'email', 'nom', 'prenom', 'role', 'is_active', 'created_at', 'last_login'] | |
if search_term: | |
df = df[ | |
df['email'].str.contains(search_term, case=False) | | |
df['nom'].str.contains(search_term, case=False) | | |
df['prenom'].str.contains(search_term, case=False) | |
] | |
st.dataframe(df[display_columns], use_container_width=True) | |
selected_user_email = st.selectbox( | |
"Sélectionner un utilisateur", | |
options=df['email'].tolist() | |
) | |
if selected_user_email: | |
selected_user = df[df['email'] == selected_user_email].iloc[0] | |
user_id = selected_user['id'] | |
col1, col2 = st.columns(2) | |
with col1: | |
with st.expander("Paramètres du compte", expanded=True): | |
new_status = st.toggle( | |
"Compte actif", | |
value=selected_user['is_active'], | |
key=f"toggle_{user_id}" | |
) | |
if new_status != selected_user['is_active']: | |
success, msg = toggle_user_status(user_id, new_status) | |
if success: | |
st.success(msg) | |
else: | |
st.error(msg) | |
new_role = st.selectbox( | |
"Rôle utilisateur", | |
options=['user', 'admin'], | |
index=0 if selected_user['role'] == 'user' else 1, | |
key=f"role_{user_id}" | |
) | |
if new_role != selected_user['role']: | |
success, msg = change_user_role(user_id, new_role) | |
if success: | |
st.success(msg) | |
else: | |
st.error(msg) | |
with st.expander("Informations détaillées", expanded=False): | |
col3, col4 = st.columns(2) | |
with col3: | |
new_nom = st.text_input( | |
"Nom", | |
value=selected_user['nom'], | |
key=f"nom_{user_id}" | |
) | |
new_email = st.text_input( | |
"Email", | |
value=selected_user['email'], | |
key=f"email_{user_id}" | |
) | |
st.text_input( | |
"Date de création", | |
value=selected_user['created_at'], | |
disabled=True | |
) | |
with col4: | |
new_prenom = st.text_input( | |
"Prénom", | |
value=selected_user['prenom'], | |
key=f"prenom_{user_id}" | |
) | |
st.text_input( | |
"Rôle", | |
value=selected_user['role'], | |
disabled=True | |
) | |
st.text_input( | |
"Dernière connexion", | |
value=selected_user.get('last_login', 'Jamais'), | |
disabled=True | |
) | |
st.write("##### Informations professionnelles") | |
professional_info = selected_user.get('professional_info', {}) | |
if isinstance(professional_info, str): | |
try: | |
professional_info = json.loads(professional_info) | |
except: | |
professional_info = {} | |
col5, col6 = st.columns(2) | |
with col5: | |
new_profession = st.text_input( | |
"Profession", | |
value=professional_info.get('profession', ''), | |
key=f"prof_{user_id}" | |
) | |
with col6: | |
new_entreprise = st.text_input( | |
"Entreprise", | |
value=professional_info.get('entreprise', ''), | |
key=f"entr_{user_id}" | |
) | |
if st.button("Mettre à jour les informations", key=f"update_{user_id}"): | |
if not re.match(r"[^@]+@[^@]+\.[^@]+", new_email): | |
st.error("Format d'email invalide") | |
return | |
if new_email != selected_user['email']: | |
existing_email = supabase.table("users").select("id").eq("email", new_email).neq("id", user_id).execute() | |
if existing_email.data: | |
st.error("Cet email est déjà utilisé par un autre utilisateur") | |
return | |
updated_info = { | |
"nom": new_nom, | |
"prenom": new_prenom, | |
"email": new_email, | |
"professional_info": { | |
"profession": new_profession, | |
"entreprise": new_entreprise | |
} | |
} | |
success, msg = update_user_info(user_id, updated_info) | |
if success: | |
st.success("Informations mises à jour avec succès") | |
st.rerun() | |
else: | |
st.error(f"Erreur lors de la mise à jour : {msg}") | |
with col2: | |
with st.expander("Gestion des accès aux assistants", expanded=False): | |
render_user_permissions(user_id) | |
else: | |
st.warning("Aucun utilisateur trouvé.") | |
# Onglet Restrictions d'accès | |
with tab_restrictions: | |
st.header("Restrictions d'accès") | |
current_restrictions = supabase.table("access_restrictions").select("*").eq("is_active", True).execute() | |
restrictions = current_restrictions.data[0] if current_restrictions.data else {} | |
with st.form("access_restrictions_form"): | |
st.subheader("🌐 Domaines email autorisés") | |
st.info("Définissez les domaines email autorisés pour l'inscription. Un domaine par ligne.") | |
domains_text = st.text_area( | |
"Domaines autorisés", | |
value="\n".join(restrictions.get('allowed_email_domains', [])), | |
help="Exemple: entreprise.com \nautreentreprise.fr", | |
placeholder="Entrez les domaines (un par ligne)" | |
) | |
st.subheader("🌐 Adresses IP autorisées") | |
st.info("Définissez les adresses IP autorisées pour l'inscription. Une adresse par ligne.") | |
ip_ranges_text = st.text_area( | |
"Adresses IP autorisées", | |
value="\n".join(restrictions.get('allowed_ip_ranges', [])), | |
help="Exemple: 192.168.1.1 \n10.0.0.1", | |
placeholder="Entrez les adresses IP (une par ligne)" | |
) | |
col1, col2, spacer1, col4 = st.columns([4,4,6,3]) | |
with col1: | |
is_email_active = st.toggle( | |
"Activer les restrictions d'email", | |
value=restrictions.get('is_email_active', False), | |
help="Activer/Désactiver les restrictions d'accès par email" | |
) | |
with col2: | |
is_ip_active = st.toggle( | |
"Activer les restrictions d'IP", | |
value=restrictions.get('is_ip_active', False), | |
help="Activer/Désactiver les restrictions d'accès par IP" | |
) | |
with col4: | |
st.markdown("###") | |
submit_button = st.form_submit_button("💾 Enregistrer les restrictions") | |
if submit_button: | |
try: | |
domains = [ | |
d.strip().lower() | |
for d in domains_text.split('\n') | |
if d.strip() and '.' in d.strip() | |
] | |
ip_ranges = [ | |
ip.strip() | |
for ip in ip_ranges_text.split('\n') | |
if ip.strip() | |
] | |
update_data = { | |
"allowed_email_domains": domains, | |
"allowed_ip_ranges": ip_ranges, | |
"is_email_active": is_email_active, | |
"is_ip_active": is_ip_active, | |
"updated_at": datetime.now(pytz.UTC).isoformat() | |
} | |
if current_restrictions.data: | |
supabase.table("access_restrictions").update( | |
update_data | |
).eq("id", current_restrictions.data[0]['id']).execute() | |
else: | |
supabase.table("access_restrictions").insert(update_data).execute() | |
st.success("✅ Restrictions mises à jour avec succès!") | |
if is_email_active and domains: | |
st.info(f"Domaines autorisés : {', '.join(domains)}") | |
elif is_email_active and not domains: | |
st.warning("⚠️ Aucun domaine spécifié - l'inscription sera bloquée pour tous les domaines") | |
else: | |
st.info("ℹ️ Les restrictions d'email sont désactivées - tous les domaines sont autorisés") | |
if is_ip_active and ip_ranges: | |
st.info(f"Adresses IP autorisées : {', '.join(ip_ranges)}") | |
elif is_ip_active and not ip_ranges: | |
st.warning("⚠️ Aucune adresse IP spécifiée - l'inscription sera bloquée pour toutes les adresses IP") | |
else: | |
st.info("ℹ️ Les restrictions d'IP sont désactivées - toutes les adresses IP sont autorisées") | |
except Exception as e: | |
st.error(f"❌ Erreur lors de la mise à jour des restrictions : {str(e)}") | |
if restrictions.get('is_email_active') or restrictions.get('is_ip_active'): | |
st.subheader("📊 Statistiques des restrictions") | |
try: | |
users = supabase.table("users").select("email").execute() | |
if users.data: | |
domains_count = {} | |
for user in users.data: | |
domain = user['email'].split('@')[1].lower() | |
domains_count[domain] = domains_count.get(domain, 0) + 1 | |
st.markdown("##### Répartition des utilisateurs par domaine") | |
for domain, count in domains_count.items(): | |
status = "✅" if not restrictions.get('allowed_email_domains') or domain in restrictions.get('allowed_email_domains', []) else "❌" | |
st.text(f"{status} {domain}: {count} utilisateur(s)") | |
except Exception as e: | |
st.error(f"Erreur lors du calcul des statistiques : {str(e)}") | |
with tab_chatbot: | |
st.subheader("💬 Chatbot") | |
def add_flowise_chat(): | |
assistant_type = st.selectbox( | |
"Sélectionner l'assistant", | |
options=['SANTE', 'CAR', 'BTP', 'RH', 'PILOTAGE'], | |
format_func=lambda x: { | |
'SANTE': 'Colibri Vitalité ❣️', | |
'CAR': 'Colibri Carburant 🚘', | |
'BTP': 'Colibri Batisseur 🏠', | |
'RH': 'Colibri Equipage 🪪', | |
'PILOTAGE': 'Colibri Tatillon 👨🏻✈️' | |
}[x], | |
key="chatbot_assistant_select" | |
) | |
# Définir le titre du chatbot en fonction de l'assistant sélectionné | |
assistant_titles = { | |
'SANTE': 'Colibri Vitalité', | |
'CAR': 'Colibri Carburant', | |
'BTP': 'Colibri Batisseur', | |
'RH': 'Colibri Equipage', | |
'PILOTAGE': 'Colibri Tatillon' | |
} | |
chatbot_title = assistant_titles.get(assistant_type, 'Flowise Bot') | |
# Récupérer l'URL complète de l'API depuis la variable d'environnement | |
api_url_var = f"FLOWISE_API_URL_{assistant_type}" | |
api_url = os.getenv(api_url_var) | |
if not api_url: | |
st.error(f"URL de l'API non trouvée pour l'assistant {assistant_type}") | |
return None | |
url_parts = urlparse(api_url) | |
base_url = f"{url_parts.scheme}://{url_parts.netloc}" | |
chatflowid = url_parts.path.split('/')[-1] | |
# Détermination du contexte et de l'apiHost | |
if base_url.startswith("http://"): | |
# Contexte développement | |
apiHost = "http://localhost:3000" | |
else: | |
# Contexte production | |
apiHost = base_url | |
# Configuration du chatbot en HTML | |
st.components.v1.html(f''' | |
<script type="module"> | |
import Chatbot from 'https://cdn.jsdelivr.net/npm/flowise-embed/dist/web.js'; | |
Chatbot.init({{ | |
chatflowid: '{chatflowid}', | |
apiHost: '{apiHost}', | |
chatflowConfig: {{ | |
// topK: 2 | |
}}, | |
observersConfig: {{ | |
// (optional) Allows you to execute code in parent based upon signal observations within the chatbot. | |
// The userinput field submitted to bot ("" when reset by bot) | |
observeUserInput: (userInput) => {{ | |
console.log({{ userInput }}); | |
}}, | |
// The bot message stack has changed | |
observeMessages: (messages) => {{ | |
console.log({{ messages }}); | |
}}, | |
// The bot loading signal changed | |
observeLoading: (loading) => {{ | |
console.log({{ loading }}); | |
}}, | |
}}, | |
theme: {{ | |
button: {{ | |
backgroundColor: '#3B81F6', | |
right: 20, | |
bottom: 20, | |
size: 48, | |
// small | medium | large | number | |
dragAndDrop: true, | |
iconColor: 'white', | |
customIconSrc: 'https://raw.githubusercontent.com/walkxcode/dashboard-icons/main/svg/google-messages.svg', | |
autoWindowOpen: {{ | |
autoOpen: true, | |
//parameter to control automatic window opening | |
openDelay: 2, | |
// Optional parameter for delay time in seconds | |
autoOpenOnMobile: false, | |
//parameter to control automatic window opening in mobile | |
}}, | |
}}, | |
tooltip: {{ | |
showTooltip: true, | |
tooltipMessage: 'Bonjour !', | |
tooltipBackgroundColor: 'black', | |
tooltipTextColor: 'white', | |
tooltipFontSize: 16, | |
}}, | |
disclaimer: {{ | |
title: 'Avertissement', | |
message: 'By using this chatbot, you agree to the <a target="_blank" href="https://ecg-pereire-assurances.com/mentions-legales/">Terms & Condition</a>', | |
}}, | |
chatWindow: {{ | |
showTitle: true, | |
showAgentMessages: true, | |
title: '{chatbot_title}', | |
titleAvatarSrc: 'https://raw.githubusercontent.com/walkxcode/dashboard-icons/main/svg/google-messages.svg', | |
welcomeMessage: 'Hello! This is custom welcome message', | |
errorMessage: 'This is a custom error message', | |
backgroundColor: '#ffffff', | |
backgroundImage: 'enter image path or link', | |
// If set, this will overlap the background color of the chat window. | |
height: 700, | |
width: 400, | |
fontSize: 16, | |
starterPrompts: ['What is a bot?', 'Who are you?'], | |
// It overrides the starter prompts set by the chat flow passed | |
starterPromptFontSize: 15, | |
clearChatOnReload: false, | |
// If set to true, the chat will be cleared when the page reloads | |
sourceDocsTitle: 'Sources:', | |
renderHTML: true, | |
botMessage: {{ | |
backgroundColor: '#f7f8ff', | |
textColor: '#303235', | |
showAvatar: true, | |
avatarSrc: 'https://raw.githubusercontent.com/zahidkhawaja/langchain-chat-nextjs/main/public/parroticon.png', | |
}}, | |
userMessage: {{ | |
backgroundColor: '#3B81F6', | |
textColor: '#ffffff', | |
showAvatar: true, | |
avatarSrc: 'https://raw.githubusercontent.com/zahidkhawaja/langchain-chat-nextjs/main/public/usericon.png', | |
}}, | |
textInput: {{ | |
placeholder: 'Type your question', | |
backgroundColor: '#ffffff', | |
textColor: '#303235', | |
sendButtonColor: '#3B81F6', | |
//maxChars: 50, | |
maxCharsWarningMessage: 'You exceeded the characters limit. Please input less than 50 characters.', | |
autoFocus: true, | |
// If not used, autofocus is disabled on mobile and enabled on desktop. true enables it on both, false disables it on both. | |
sendMessageSound: true, | |
// sendSoundLocation: "send_message.mp3", | |
// If this is not used, the default sound effect will be played if sendSoundMessage is true. | |
receiveMessageSound: true, | |
// receiveSoundLocation: "receive_message.mp3", | |
// If this is not used, the default sound effect will be played if receiveSoundMessage is true. | |
}}, | |
feedback: {{ | |
color: '#303235', | |
}}, | |
dateTimeToggle: {{ | |
date: true, | |
time: true, | |
}}, | |
footer: {{ | |
textColor: '#303235', | |
text: 'Powered by', | |
company: 'Colibri', | |
companyLink: 'https://ecg-pereire-assurances.com', | |
}}, | |
}}, | |
}}, | |
}}); | |
</script> | |
''', height=800) | |
add_flowise_chat() | |
with tab_chatreact: | |
def add_flowise_chatreact(): | |
assistant_type = st.selectbox( | |
"Sélectionner l'assistant", | |
options=['SANTE', 'CAR', 'BTP', 'RH', 'PILOTAGE'], | |
format_func=lambda x: { | |
'SANTE': 'Colibri Vitalité ❣️', | |
'CAR': 'Colibri Carburant 🚘', | |
'BTP': 'Colibri Batisseur 🏠', | |
'RH': 'Colibri Equipage 🪪', | |
'PILOTAGE': 'Colibri Tatillon 👨🏻✈️' | |
}[x], | |
key="chatbot_full_assistant_select" | |
) | |
# Définir le titre du chatbot en fonction de l'assistant sélectionné | |
assistant_titles = { | |
'SANTE': 'Colibri Vitalité', | |
'CAR': 'Colibri Carburant', | |
'BTP': 'Colibri Batisseur', | |
'RH': 'Colibri Equipage', | |
'PILOTAGE': 'Colibri Tatillon' | |
} | |
chatbot_title = assistant_titles.get(assistant_type, 'Flowise Bot') | |
# Récupérer l'URL complète de l'API depuis la variable d'environnement | |
api_url_var = f"FLOWISE_API_URL_{assistant_type}" | |
api_url = os.getenv(api_url_var) | |
if not api_url: | |
st.error(f"URL de l'API non trouvée pour l'assistant {assistant_type}") | |
return None | |
url_parts = urlparse(api_url) | |
base_url = f"{url_parts.scheme}://{url_parts.netloc}" | |
chatflowid = url_parts.path.split('/')[-1] | |
# Détermination du contexte et de l'apiHost | |
if base_url.startswith("http://"): | |
# Contexte développement | |
apiHost = "http://localhost:3000" | |
else: | |
# Contexte production | |
apiHost = base_url | |
# Configuration du chatbot en HTML | |
st.components.v1.html(f''' | |
<flowise-fullchatbot></flowise-fullchatbot> | |
<body style="margin: 0"> | |
<script type="module"> | |
import Chatbot from "https://cdn.jsdelivr.net/npm/flowise-embed/dist/web.js"; | |
Chatbot.initFull({{ | |
chatflowid: "{chatflowid}", | |
apiHost: "{apiHost}", | |
theme: {{ | |
chatWindow: {{ | |
showTitle: true, | |
title: "{chatbot_title}", | |
titleAvatarSrc: 'https://raw.githubusercontent.com/walkxcode/dashboard-icons/main/svg/google-messages.svg', | |
showAgentMessages: true, | |
welcomeMessage: 'Hello! This is custom welcome message', | |
errorMessage: 'This is a custom error message', | |
backgroundColor: "#ffffff", | |
backgroundImage: '', | |
fontSize: 16, | |
starterPromptFontSize: 15, | |
clearChatOnReload: false, | |
botMessage: {{ | |
backgroundColor: "#f7f8ff", | |
textColor: "#303235", | |
showAvatar: true, | |
avatarSrc: "https://raw.githubusercontent.com/zahidkhawaja/langchain-chat-nextjs/main/public/parroticon.png", | |
}}, | |
userMessage: {{ | |
backgroundColor: "#3B81F6", | |
textColor: "#ffffff", | |
showAvatar: true, | |
avatarSrc: "https://raw.githubusercontent.com/zahidkhawaja/langchain-chat-nextjs/main/public/usericon.png", | |
}}, | |
textInput: {{ | |
placeholder: 'Tapez votre question ici...', | |
backgroundColor: '#ffffff', | |
textColor: '#303235', | |
sendButtonColor: '#3B81F6', | |
autoFocus: true, | |
sendMessageSound: true, | |
receiveMessageSound: true, | |
}}, | |
feedback: {{ | |
color: '#303235', | |
}}, | |
footer: {{ | |
textColor: '#303235', | |
text: 'Powered by', | |
company: 'Colibri', | |
companyLink: 'https://ecg-pereire-assurances.com/', | |
}} | |
}} | |
}} | |
}}); | |
</script> | |
''', height=800) | |
add_flowise_chatreact() | |
with testfooter: | |
st.components.v1.html(''' | |
<flowise-fullchatbot></flowise-fullchatbot> | |
<body style="margin: 0"> | |
<script type="module"> | |
import Chatbot from "https://cdn.jsdelivr.net/npm/flowise-embed/dist/web.js"; | |
Chatbot.initFull({ | |
chatflowid: "b624c96f-cb22-4112-bdb2-51ea8d0bac09", | |
apiHost: "https://reztilop-flowise-colibri.hf.space", | |
theme: { | |
chatWindow: { | |
showTitle: true, | |
title: 'Flowise Bot', | |
titleAvatarSrc: 'https://raw.githubusercontent.com/walkxcode/dashboard-icons/main/svg/google-messages.svg', | |
showAgentMessages: true, | |
welcomeMessage: 'Hello! This is custom welcome message', | |
errorMessage: 'This is a custom error message', | |
backgroundColor: "#ffffff", | |
backgroundImage: '', | |
//height: 700, | |
//width: 400, | |
fontSize: 16, | |
starterPromptFontSize: 15, | |
clearChatOnReload: false, | |
botMessage: { | |
backgroundColor: "#f7f8ff", | |
textColor: "#303235", | |
showAvatar: true, | |
avatarSrc: "https://raw.githubusercontent.com/zahidkhawaja/langchain-chat-nextjs/main/public/parroticon.png", | |
}, | |
userMessage: { | |
backgroundColor: "#3B81F6", | |
textColor: "#ffffff", | |
showAvatar: true, | |
avatarSrc: "https://raw.githubusercontent.com/zahidkhawaja/langchain-chat-nextjs/main/public/usericon.png", | |
}, | |
textInput: { | |
placeholder: 'Tapez votre question ici...', | |
backgroundColor: '#ffffff', | |
textColor: '#303235', | |
sendButtonColor: '#3B81F6', | |
//maxChars: 50, | |
//maxCharsWarningMessage: 'You exceeded the characters limit. Please input less than 50 characters.', | |
autoFocus: true, | |
sendMessageSound: true, | |
receiveMessageSound: true, | |
}, | |
feedback: { | |
color: '#303235', | |
}, | |
footer: { | |
textColor: '#303235', | |
text: 'Powered by', | |
company: 'Clibri', | |
companyLink: 'https://ecg-pereire-assurances.com/', | |
} | |
} | |
} | |
}); | |
</script> | |
''', height=800) | |
# Exécution de la fonction principale | |
if __name__ == "__main__": | |
asyncio.run(render_admin_dashboard()) | |