Spaces:
Sleeping
Sleeping
import streamlit as st | |
import base64 | |
import os | |
from datetime import datetime | |
import pytz | |
import logging | |
from utils.admin import supabase # Pour load_theme_preference et save_theme_preference | |
from utils.logging_utils import log_to_file | |
# Fonction pour charger la préférence de thème depuis la base de données | |
def load_theme_preference(): | |
"""Charge la préférence de thème depuis la base de données""" | |
if 'user' in st.session_state and st.session_state['user']: | |
user_id = st.session_state['user'].get('id') | |
if user_id: | |
try: | |
response = supabase.table("notification_preferences").select("theme").eq("user_id", user_id).execute() | |
if response.data: | |
theme = response.data[0]['theme'] | |
log_to_file(f"Thème '{theme}' chargé pour l'utilisateur {user_id}") | |
return theme | |
except Exception as e: | |
log_to_file(f"Erreur lors du chargement du thème : {str(e)}", logging.ERROR) | |
return 'Clair' # Thème par défaut | |
# Fonction pour sauvegarder la préférence de thème dans la base de données | |
def save_theme_preference(theme): | |
"""Sauvegarde la préférence de thème dans la base de données""" | |
if 'user' in st.session_state and st.session_state['user']: | |
user_id = st.session_state['user'].get('id') | |
if user_id: | |
try: | |
# Vérifier si une préférence existe déjà | |
existing_preference = supabase.table("notification_preferences").select("*").eq("user_id", user_id).execute() | |
if existing_preference.data: | |
# Mettre à jour la ligne existante | |
supabase.table("notification_preferences").update({"theme": theme}).eq("user_id", user_id).execute() | |
else: | |
# Insérer une nouvelle ligne | |
supabase.table("notification_preferences").insert({"user_id": user_id, "theme": theme}).execute() | |
st.session_state.user_theme = theme | |
log_to_file(f"Thème '{theme}' sauvegardé pour l'utilisateur {user_id}") | |
except Exception as e: | |
log_to_file(f"Erreur lors de la sauvegarde du thème : {str(e)}", logging.ERROR) | |
def apply_theme(theme): | |
# Définition des couleurs communes selon le thème choisi (sombre ou clair) | |
# Texte principal : Gris clair (#E0E0E0) pour le thème sombre, Gris foncé (#4a4a4a) pour le thème clair | |
text_color = "#E0E0E0" if theme == "Sombre" else "#4a4a4a" | |
# Couleur de fond de la page : Gris très foncé (#1E1E1E) pour le thème sombre, blanc cassé (#f7f9fc) pour le thème clair | |
bg_color = "#1E1E1E" if theme == "Sombre" else "#f7f9fc" | |
# Couleur de fond des zones de saisie (inputs) : Gris foncé (#333333) pour le thème sombre, gris très clair avec une légère teinte bleue (#eef3f7) pour le thème clair | |
input_bg_color= "#333333" if theme == "Sombre" else "#eef3f7" | |
# Couleur de fond des zones de saisie (inputs) : Gris foncé (#333333) pour le thème sombre, rouge saumon clair (#ffcccb pour le thème clair | |
input_text_area_inactive = "#333333" if theme == "Sombre" else "#ffcccb" | |
# Couleur de fond des zones de saisie active (inputs) : Gris foncé (#999999) pour le thème sombre, Blanc pur (#ffffff) pour le thème clair | |
input_text_area_active = "#666666" if theme == "Sombre" else "#ffffff" | |
# Définir la couleur du curseur (caret) selon le thème | |
caret_color = "white" if theme == "Sombre" else "black" # Blanc pour le thème sombre, noir pour le thème clair | |
# Couleur de fond de la barre latérale : Gris très foncé (#2D2D2D) pour le thème sombre, gris bleu très clair ( #e3e9f1) pour le thème clair | |
sidebar_bg_color = "#2D2D2D" if theme == "Sombre" else " #e3e9f1" | |
# Couleurs spécifiques pour les messages utilisateur et assistant : | |
# Messages de l'utilisateur : Bleu foncé (#0E4C92) pour le thème sombre, Bleu clair désaturé (#d1e7ff) pour le thème clair | |
user_msg_bg = "#0E4C92" if theme == "Sombre" else "#d1e7ff" | |
# Messages de l'assistant : Vert foncé (#1A472A) pour le thème sombre, Gris perle (#f0f0f0) pour le thème clair | |
assistant_msg_bg = "#1A472A" if theme == "Sombre" else "#f0f0f0" | |
# Couleurs pour les boutons et éléments interactifs : | |
# Fond des boutons : Bleu acier (#4682B4) pour le thème sombre, Or (#FFD700) pour le thème clair | |
button_bg = "#4682B4" if theme == "Sombre" else "#FFD700" | |
# Texte des boutons : Blanc (#FFFFFF) pour le thème sombre, Vert mer (#8FBC8F) pour le thème clair | |
button_text = "white" if theme == "Sombre" else "#8FBC8F" | |
# Fond du selectbox : Bleu foncé (#0E4C92) pour le thème sombre, gris très clair avec une légère teinte bleue (#eef3f7) pour le thème clair | |
select_bg = "#ff5e4d" if theme == "Sombre" else "#eef3f7" | |
# Fond du selectbox : Bleu foncé (#0E4C92) pour le thème sombre, Gris clair (#e6f7ff) pour le thème clair | |
select_option_bg = "#1c39bb" if theme == "Sombre" else "#e6f7ff" | |
select_text_color = "black" if theme == "Sombre" else "#333333" # Couleur du texte du selectbox | |
# Génération des styles CSS pour Streamlit | |
st.markdown(f""" | |
<style> | |
/* Styles généraux */ | |
.stApp {{ | |
background-color: {bg_color}; /* Couleur de fond générale */ | |
color: {text_color} !important; /* Couleur de texte principale */ | |
}} | |
/* Styles pour les messages de chat */ | |
.stChatMessage {{ | |
background-color: {input_bg_color} !important; /* Fond des messages */ | |
color: {text_color} !important; /* Couleur de texte dans les messages */ | |
}} | |
.stChatMessage.user {{ background-color: {user_msg_bg} !important; }} /* Fond des messages utilisateur */ | |
.stChatMessage.assistant {{ background-color: {assistant_msg_bg} !important; }} /* Fond des messages assistant */ | |
.stChatMessage * {{ color: {text_color} !important; }} /* Couleur de texte dans tous les éléments des messages */ | |
/* Style pour le conteneur de la zone de saisie */ | |
[data-testid="stBottomBlockContainer"] {{ | |
background-color: {input_bg_color} !important; /* Fond de la zone de saisie */ | |
}} | |
/* Styles pour la zone de saisie et son conteneur interne */ | |
.stChatInput, | |
.stChatInput > div, | |
.stChatInput textarea {{ | |
background-color: {input_text_area_inactive} !important; /* Fond de la zone de saisie */ | |
border-color: {"#555555" if theme == "Sombre" else "#b0e0e6"} !important; /* Bordure des champs de saisie */ | |
color: {text_color} !important; /* Texte dans la zone de saisie */ | |
}} | |
.stChatInput textarea:focus {{ | |
background-color: {input_text_area_active} !important; /* Fond quand la zone est active */ | |
color: {text_color} !important; /* Texte actif */ | |
caret-color: {caret_color} !important; /* Couleur du curseur actif */ | |
box-shadow: none !important; /* Pas de halo lumineux lors de la saisie */ | |
}} | |
/* Style pour le bouton d'envoi */ | |
.stChatInput button {{ | |
background-color: {button_bg} !important; /* Fond des boutons */ | |
color: {button_text} !important; /* Couleur du texte des boutons */ | |
}} | |
/* Styles pour la barre latérale */ | |
[data-testid="stSidebar"] {{ | |
background-color: {sidebar_bg_color}; /* Couleur de fond de la barre latérale */ | |
color: {text_color}; /* Texte de la barre latérale */ | |
}} | |
[data-testid="stSidebar"] .st-bw, | |
[data-testid="stSidebar"] h3 {{ color: {text_color} !important; }} /* Couleur des titres et textes dans la barre latérale */ | |
/* Styles pour les boutons */ | |
.stButton > button {{ | |
background-color: {button_bg}; /* Fond des boutons généraux */ | |
color: {button_text}; /* Couleur du texte des boutons */ | |
}} | |
/* Styles pour les expandeurs */ | |
.streamlit-expanderHeader {{ | |
background-color: {input_bg_color}; /* Fond des en-têtes d'expandeur */ | |
color: {text_color}; /* Couleur du texte des en-têtes d'expandeur */ | |
transition: all 0.3s ease-out; /* Transition fluide pour l'expansion */ | |
}} | |
.streamlit-expanderHeader[aria-expanded="true"] {{ transform: translateX(10px); }} /* Effet de déplacement quand l'expandeur est ouvert */ | |
.streamlit-expanderContent {{ | |
background-color: {"#1E90FF" if theme == "Sombre" else "#F0F0F0"} !important; /* Couleur de fond du contenu de l'expandeur */ | |
padding: 10px; | |
border-radius: 5px; /* Coins arrondis du contenu de l'expandeur */ | |
}} | |
/* Styles pour le selectbox */ | |
.stSelectbox > div > div:first-child, | |
.stSelectbox > div > div:nth-child(2), | |
.stSelectbox ul {{ | |
background-color: {select_bg} !important; /* Fond des éléments du selectbox */ | |
color: {"white" if theme == "Sombre" else "#333333"} !important; /* Couleur du texte des éléments du selectbox */ | |
}} | |
.stSelectbox ul li:hover, .stSelectbox ul li[aria-selected="true"] {{ | |
background-color: {"#ffe4e1" if theme == "Sombre" else "#e6f7ff"} !important; /* Fond des éléments au survol et sélectionnés */ | |
}} | |
/* Styles pour le selectbox */ | |
[data-testid="stSelectboxVirtualDropdown"], .st-emotion-cache-1o2fhjg.e1811lun0 {{ | |
background-color: {select_option_bg} !important; /* Fond des éléments du selectbox */ | |
color: {select_text_color} !important; /* Couleur du texte des options */ | |
}} | |
[data-testid="stSelectboxVirtualDropdown"] li[aria-selected="true"], .st-emotion-cache-1o2fhjg.e1811lun0[aria-selected="true"] {{ | |
background-color: {"#1A6BBF" if theme == "Sombre" else "#ffcccb"} !important; /* Fond des options sélectionnées */ | |
}} | |
[data-testid="stSelectboxVirtualDropdown"] li:hover {{ | |
background-color: {"#1A6BBF" if theme == "Sombre" else "#ffa07a"} !important; /* Fond au survol des options */ | |
}} | |
/* Styles pour les boutons de feedback */ | |
.stChatMessage .stButton > button {{ | |
background-color: transparent !important; /* Fond transparent pour les boutons dans les messages */ | |
border: none !important; | |
box-shadow: none !important; | |
padding: 0 !important; | |
}} | |
.stChatMessage .stButton > button:hover {{ | |
background-color: rgba(0, 0, 0, 0.05) !important; /* Léger changement de fond au survol */ | |
}} | |
/* Styles pour les boutons de la barre latérale */ | |
[data-testid="stSidebar"] .stButton > button {{ | |
background-color: {"#1E90FF" if theme == "Sombre" else "#FFD700"} !important; /* Fond des boutons spécifiques dans la barre latérale */ | |
color: {button_text} !important; /* Couleur du texte des boutons dans la barre latérale */ | |
border: inherit !important; | |
box-shadow: inherit !important; | |
padding: inherit !important; | |
}} | |
/* Assurez-vous que tous les textes sont lisibles */ | |
body, p, h1, h2, h3, h4, h5, h6, span, div {{ | |
color: {"#E0E0E0" if theme == "Sombre" else "#4a4a4a"} !important; /* Couleur des textes dans tout le contenu de la page, */ | |
}} | |
</style> | |
""", unsafe_allow_html=True) | |
# ajout de logo sur l'en -tête de l'application (cette focntion est appelé dans inject_custom_css(theme)) | |
def get_base64_encoded_image(image_file): | |
with open(image_file, "rb") as img_file: | |
return base64.b64encode(img_file.read()).decode('utf-8') | |
# ajout de logo sur l'en -tête de l'application et animation du logo | |
def inject_custom_css(theme): | |
# Définition des paramètres visuels en fonction du thème | |
is_dark_theme = theme == "Sombre" | |
# Sélection du logo et des couleurs selon le thème | |
logo_file = "assets/logo2.svg" if is_dark_theme else "assets/logo.svg" | |
background_color = "#333333" if is_dark_theme else "#eef3f7" | |
text_color = "#E0E0E0" if is_dark_theme else "#333333" | |
# Encodage du logo en base64 | |
logo_base64 = get_base64_encoded_image(logo_file) | |
st.markdown( | |
f""" | |
<style> | |
@keyframes rotate {{ | |
from {{ | |
transform: rotate(0deg); | |
}} | |
to {{ | |
transform: rotate(360deg); | |
}} | |
}} | |
.stApp header {{ | |
display: flex; | |
align-items: center; | |
background-color: {background_color} !important; | |
padding-left: 240px !important; | |
}} | |
.stApp header::before {{ | |
content: ""; | |
background-image: url("data:image/svg+xml;base64,{logo_base64}"); | |
background-repeat: no-repeat; | |
background-position: center; | |
background-size: contain; | |
width: 190px; | |
height: 190px; | |
position: absolute; | |
left: 350px; | |
animation: rotate 10s linear infinite; | |
}} | |
.stApp header::after {{ | |
content: "Colibri IA: la précision d'un colibri, la puissance d'un assistant"; | |
font-size: 15px; | |
font-weight: normal; | |
color: {text_color}; | |
margin-left: 250px; | |
background-color: rgba(0, 0, 0, 0.02) !important; | |
}} | |
</style> | |
""", | |
unsafe_allow_html=True,) | |
# ajout de logo sur la sidebar avec un texte simulant un en-tête | |
def add_sidebar_logo(theme): | |
# Définition des couleurs en fonction du thème | |
text_color = "#E0E0E0" if theme == "Sombre" else "#333333" | |
# #E0E0E0 : Gris très clair, presque blanc (pour le thème sombre) | |
# #333333 : Gris très foncé, presque noir (pour le thème clair) | |
# Utilisation d'un contexte 'with' pour la barre latérale | |
with st.sidebar: | |
# Ajout du logo (identique pour les deux thèmes) | |
st.image("assets/logo.png", width=150) | |
# Ajout du titre avec la couleur appropriée | |
st.markdown( | |
f""" | |
<h2 style="color:{text_color};">Colibri Assistant</h2> | |
""", | |
unsafe_allow_html=True | |
) | |
# Ajout d'une ligne de séparation | |
st.write("---") | |
def apply_chat_styles(theme): | |
light_user_bg = "#d1e7ff" # bleu clair désaturé (arrière-plan des messages utilisateur en thème clair) | |
light_assistant_bg = "#f0f0f0" # Gris perle (arrière-plan des messages assistant en thème clair) | |
dark_user_bg = "#0E4C92" # #0E4C92 = bleu foncé (arrière-plan des messages utilisateur en thème sombre) | |
dark_assistant_bg = "#1A472A" # #1A472A = vert foncé (arrière-plan des messages assistant en thème sombre) | |
user_bg = dark_user_bg if theme == "Sombre" else light_user_bg # Utilise la couleur bleu foncé en thème sombre ou bleu clair désaturé en thème clair pour l'utilisateur | |
assistant_bg = dark_assistant_bg if theme == "Sombre" else light_assistant_bg # Utilise la couleur vert foncé en thème sombre ou Gris perle en thème clair pour l'assistant | |
text_color = "#E0E0E0" if theme == "Sombre" else "#000000" # Utilise la couleur gris clair (#E0E0E0) en thème sombre ou noir (#000000) en thème clair pour le texte | |
st.markdown(f""" | |
<style> | |
[data-testid="stChatMessage"] {{ | |
width: fit-content !important; | |
max-width: 80% !important; | |
padding: 10px !important; | |
border-radius: 15px !important; | |
margin-bottom: 10px !important; | |
clear: both !important; | |
}} | |
[data-testid="stChatMessage"]:has([data-testid="stChatMessageAvatarUser"]) {{ | |
background-color: {user_bg} !important; # Arrière-plan des messages utilisateur (dépend du thème) | |
border-radius: 15px 15px 0 15px !important; | |
margin-left: auto !important; | |
margin-right: 10px !important; | |
text-align: right !important; | |
float: right !important; | |
}} | |
[data-testid="stChatMessage"]:not(:has([data-testid="stChatMessageAvatarUser"])) {{ | |
background-color: {assistant_bg} !important; # Arrière-plan des messages assistant (dépend du thème) | |
border-radius: 15px 15px 15px 0 !important; | |
margin-right: auto !important; | |
margin-left: 10px !important; | |
text-align: left !important; | |
float: left !important; | |
}} | |
[data-testid="stChatMessage"] * {{ | |
color: {text_color} !important; # Couleur du texte (dépend du thème) | |
}} | |
</style> | |
""", unsafe_allow_html=True) | |
def inject_custom_toggle_css(theme): | |
# Définition de la couleur du texte en fonction du thème | |
text_color = "#e0e0e0" if theme == "Sombre" else "#666666" | |
# #e0e0e0 : Gris très clair, presque blanc (pour le thème sombre) | |
# #666666 : Gris moyen foncé (pour le thème clair) | |
# CSS personnalisé pour le style des toggles | |
custom_css = f""" | |
<style> | |
/* Style pour le titre du toggle */ | |
.stExpander .stToggleButton label, | |
.streamlit-expanderHeader .stToggleButton label {{ | |
color: {text_color} !important; | |
font-weight: bold; | |
}} | |
</style> | |
""" | |
# Injection du CSS personnalisé dans la page Streamlit | |
st.markdown(custom_css, unsafe_allow_html=True) | |
def create_custom_footer(): | |
footer = """ | |
<style> | |
.footer { | |
position: fixed; | |
left: 0; | |
bottom: 0; | |
width: 100%; | |
background-color: #0E1117; # Couleur de fond sombre, ajustez selon votre thème | |
color: #FAFAFA; # Couleur du texte claire | |
text-align: center; | |
padding: 10px; | |
font-size: 14px; | |
} | |
</style> | |
<div class="footer"> | |
<p>© 2024 Votre Entreprise. Tous droits réservés.</p> | |
</div> | |
""" | |
st.markdown(footer, unsafe_allow_html=True) | |
# Fonction pour permettre à l'utilisateur de changer de thème avec un toggle | |
def theme_switcher(): | |
current_theme = st.session_state.get('user_theme', 'Clair') | |
# Utiliser des colonnes Streamlit pour l'alignement | |
col1, col2 = st.columns([0.9, 4]) # Ajustez les ratios selon vos besoins | |
with col1: | |
# Toggle sans label | |
is_dark = st.toggle("", value=current_theme == "Sombre", key=f"theme_toggle", label_visibility="collapsed") | |
with col2: | |
# Label personnalisé | |
title_color = "#FF6B6B" if current_theme == "Sombre" else "#1E90FF" | |
st.markdown(f'<p style="color: {title_color}; font-weight: normal; margin-top: 5px;">Thème sombre</i>', unsafe_allow_html=True) | |
new_theme = "Sombre" if is_dark else "Clair" | |
if new_theme != current_theme: | |
st.session_state.user_theme = new_theme | |
save_theme_preference(new_theme) | |
apply_theme(new_theme) | |
apply_chat_styles(new_theme) | |
st.rerun() | |
# Cette fonction supprimera certains styles par défaut de Streamlit qui pourraient interférer avec vos styles personnalisés. | |
def remove_streamlit_style(): | |
st.markdown(""" | |
<style> | |
#MainMenu {visibility: hidden;} | |
footer {visibility: hidden;} | |
</style> | |
""", unsafe_allow_html=True) | |
# Appelez cette fonction au début de votre improved_ui | |
def force_streamlit_style_update(): | |
st.markdown(""" | |
<script> | |
// Force Streamlit to re-evaluate the styles | |
window.parent.postMessage({ | |
type: "streamlit:setComponentValue", | |
value: true | |
}, "*") | |
</script> | |
""", unsafe_allow_html=True | |
) | |
# Fonction pour cacher les pages de navigation spécifiques (voir dossier pages) | |
def hide_pages(): | |
hide_pages_style = """ | |
<style> | |
/* Cache les liens de navigation spécifiques */ | |
.st-emotion-cache-79elbk .st-emotion-cache-1ekxtbt li:nth-child(2), /* admin page */ | |
.st-emotion-cache-79elbk .st-emotion-cache-1ekxtbt li:nth-child(3) { /* reset password */ | |
display: none !important; | |
} | |
/* Cache le séparateur si nécessaire */ | |
.st-emotion-cache-uzxc3z { | |
display: none !important; | |
} | |
/* Pour s'assurer que tous les liens sont cachés même si les classes changent */ | |
[data-testid="stSidebarNavItems"] li a[href*="/admin_page"], | |
[data-testid="stSidebarNavItems"] li a[href*="/reset_password"] { | |
display: none !important; | |
} | |
/* Cache les conteneurs parents si nécessaire */ | |
[data-testid="stSidebarNavItems"] li:has(a[href*="/admin_page"]), | |
[data-testid="stSidebarNavItems"] li:has(a[href*="/reset_password"]) { | |
display: none !important; | |
} | |
</style> | |
""" | |
st.markdown(hide_pages_style, unsafe_allow_html=True) | |
# styles pour le dashboard administrateur (tooltip et bouttons) | |
def apply_tooltip_and_button_styles(theme): | |
# Définition des couleurs en fonction du thème | |
text_color = "#E0E0E0" if theme == "Sombre" else "#333333" | |
background_color = "#333333" if theme == "Sombre" else "#fff" | |
border_color = "#ccc" if theme == "Sombre" else "#333" | |
button_background_color = "#4682B4" if theme == "Sombre" else "#FFD700" | |
button_text_color = "white" if theme == "Sombre" else "#8FBC8F" | |
# Injection des styles CSS pour les tooltips et le bouton de soumission du formulaire | |
st.markdown( | |
f""" | |
<style> | |
/* Style pour le conteneur principal du tooltip */ | |
.st-emotion-cache-oj1fi {{ | |
background-color: {background_color} !important; | |
color: {text_color} !important; | |
border: 1px solid {border_color} !important; | |
}} | |
/* Style pour le contenu du tooltip */ | |
.stTooltipIcon {{ | |
background-color: {background_color} !important; | |
color: {text_color} !important; | |
}} | |
/* Style pour le texte du tooltip */ | |
.st-emotion-cache-1whk732 {{ | |
color: {text_color} !important; | |
}} | |
/* Style pour l'icône du tooltip */ | |
.stTooltipIcon svg {{ | |
stroke: {text_color} !important; | |
}} | |
/* Style pour la couche externe du popup */ | |
div[data-baseweb="tooltip"] {{ | |
background-color: {background_color} !important; | |
border: 1px solid {border_color} !important; | |
padding: 5px 10px !important; | |
border-radius: 4px !important; | |
font-size: 12px !important; | |
z-index: 999999 !important; | |
}} | |
/* Style pour la couche interne du popup et son contenu */ | |
div[data-baseweb="tooltip"] > div, | |
div[data-baseweb="tooltip"] > div > div {{ | |
background-color: {background_color} !important; | |
color: {text_color} !important; | |
}} | |
/* Force la couleur du texte sur toutes les couches possibles */ | |
div[data-baseweb="tooltip"] *, | |
div[role="tooltip"] * {{ | |
color: {text_color} !important; | |
background-color: {background_color} !important; | |
}} | |
/* Style pour le bouton de soumission du formulaire */ | |
div[data-testid="stFormSubmitButton"] button {{ | |
background-color: {button_background_color} !important; | |
color: {button_text_color} !important; | |
border: none !important; | |
padding: 0.5rem 1rem !important; | |
border-radius: 0.5rem !important; | |
font-weight: bold !important; | |
transition: all 0.3s ease !important; | |
}} | |
/* Style pour le bouton de soumission du formulaire lorsqu'il est survolé */ | |
div[data-testid="stFormSubmitButton"] button:hover {{ | |
border: 1px solid red !important; # Ajoutez cette ligne pour définir la bordure rouge au survol | |
opacity: 0.8 !important; | |
}} | |
</style> | |
""", | |
unsafe_allow_html=True | |
) |