colibri.assistant.ai / utils /theme_utils.py
Gouzi Mohaled
Ajoute des fichiers et sous-dossiers supplémentaires
fe4792e
raw
history blame
23.7 kB
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
)