Create verstionhtmlOK.py
Browse files- verstionhtmlOK.py +134 -0
verstionhtmlOK.py
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
import pandas as pd
|
| 3 |
+
import requests
|
| 4 |
+
from io import BytesIO
|
| 5 |
+
import plotly.express as px
|
| 6 |
+
import re
|
| 7 |
+
|
| 8 |
+
# 🖌️ Configurer le mode wide et le titre de la page
|
| 9 |
+
st.set_page_config(layout="wide", page_title="Veille Sanitaire SCA - BuSCA")
|
| 10 |
+
|
| 11 |
+
# 🖌️ Importer Google Fonts pour les polices personnalisées et réduire la largeur de la sidebar
|
| 12 |
+
st.markdown("""
|
| 13 |
+
<style>
|
| 14 |
+
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;700&display=swap');
|
| 15 |
+
* { font-family: 'Roboto', sans-serif; }
|
| 16 |
+
[data-testid="stSidebar"] {
|
| 17 |
+
background-color: #f0f0f0;
|
| 18 |
+
color: #333;
|
| 19 |
+
width: 200px; /* Réduire la largeur de la sidebar */
|
| 20 |
+
}
|
| 21 |
+
.stButton > button {
|
| 22 |
+
background-color: #1E88E5;
|
| 23 |
+
color: white;
|
| 24 |
+
border-radius: 8px;
|
| 25 |
+
transition: 0.3s;
|
| 26 |
+
}
|
| 27 |
+
.stButton > button:hover {
|
| 28 |
+
background-color: #1565C0;
|
| 29 |
+
}
|
| 30 |
+
.banner {
|
| 31 |
+
background-image: url('https://github.com/M00N69/BUSCAR/blob/main/logo%2002%20copie.jpg?raw=true');
|
| 32 |
+
background-size: cover;
|
| 33 |
+
height: 150px;
|
| 34 |
+
}
|
| 35 |
+
a { color: #1E88E5; text-decoration: none; }
|
| 36 |
+
a:hover { text-decoration: underline; }
|
| 37 |
+
</style>
|
| 38 |
+
<div class="banner"></div>
|
| 39 |
+
""", unsafe_allow_html=True)
|
| 40 |
+
|
| 41 |
+
# 🏷️ Titre principal et astuce d'utilisation (avec la flèche <)
|
| 42 |
+
st.title("🔍 Veille SCA, Surveillance de la Chaine Alimentaire: BuSCA")
|
| 43 |
+
st.warning("👉 **Astuce :** Cliquez sur la flèche **<** en haut à gauche pour ouvrir/fermer la barre latérale et mieux voir les résultats !")
|
| 44 |
+
|
| 45 |
+
# 📦 Fonction pour charger les données avec cache
|
| 46 |
+
@st.cache_data
|
| 47 |
+
def load_data():
|
| 48 |
+
file_url = "https://www.plateforme-sca.fr/media/11/download"
|
| 49 |
+
try:
|
| 50 |
+
response = requests.get(file_url)
|
| 51 |
+
response.raise_for_status()
|
| 52 |
+
df = pd.read_excel(BytesIO(response.content), engine='openpyxl')
|
| 53 |
+
return df
|
| 54 |
+
except Exception as e:
|
| 55 |
+
st.error(f"Erreur lors du chargement des données : {e}")
|
| 56 |
+
return pd.DataFrame()
|
| 57 |
+
|
| 58 |
+
# 📦 Charger les données
|
| 59 |
+
df = load_data()
|
| 60 |
+
|
| 61 |
+
if df.empty:
|
| 62 |
+
st.write("Impossible de charger les données.")
|
| 63 |
+
else:
|
| 64 |
+
df.columns = df.columns.str.strip() # Supprimer les espaces dans les noms de colonnes
|
| 65 |
+
|
| 66 |
+
# 🌟 Menu latéral amélioré avec filtres interactifs
|
| 67 |
+
with st.sidebar:
|
| 68 |
+
st.header("🛠️ Filtres")
|
| 69 |
+
busca_range = st.slider("📌 Plage de numéros de BuSCA", int(df['BuSCA'].min()), int(df['BuSCA'].max()), (int(df['BuSCA'].min()), int(df['BuSCA'].max())))
|
| 70 |
+
|
| 71 |
+
# ✅ Filtre Matrices
|
| 72 |
+
if 'Matrice (catégories)' in df.columns:
|
| 73 |
+
matrices = st.multiselect("🧬 Matrices", options=df['Matrice (catégories)'].unique())
|
| 74 |
+
else:
|
| 75 |
+
matrices = []
|
| 76 |
+
|
| 77 |
+
# ✅ Filtre Dangers
|
| 78 |
+
if 'Danger' in df.columns:
|
| 79 |
+
dangers = st.multiselect("⚠️ Dangers", options=df['Danger'].unique())
|
| 80 |
+
else:
|
| 81 |
+
dangers = []
|
| 82 |
+
|
| 83 |
+
# ✅ Filtre Sections
|
| 84 |
+
if 'Section' in df.columns:
|
| 85 |
+
sections = st.multiselect("📂 Sections", options=df['Section'].unique())
|
| 86 |
+
else:
|
| 87 |
+
sections = []
|
| 88 |
+
|
| 89 |
+
# ✅ Filtre par mots-clés
|
| 90 |
+
keywords = st.text_area("🔎 Recherche par mots-clés (séparés par des virgules)")
|
| 91 |
+
apply_filter = st.button("Appliquer les filtres")
|
| 92 |
+
|
| 93 |
+
# 🎯 Appliquer les filtres
|
| 94 |
+
if apply_filter:
|
| 95 |
+
with st.spinner('📊 Application des filtres...'):
|
| 96 |
+
if busca_range:
|
| 97 |
+
df = df[(df['BuSCA'] >= busca_range[0]) & (df['BuSCA'] <= busca_range[1])]
|
| 98 |
+
if matrices:
|
| 99 |
+
df = df[df['Matrice (catégories)'].isin(matrices)]
|
| 100 |
+
if dangers:
|
| 101 |
+
df = df[df['Danger'].isin(dangers)]
|
| 102 |
+
if sections:
|
| 103 |
+
df = df[df['Section'].isin(sections)]
|
| 104 |
+
if keywords:
|
| 105 |
+
keyword_list = [kw.strip().lower() for kw in keywords.split(',')]
|
| 106 |
+
keyword_patterns = [re.compile(r'\b' + re.escape(kw) + r's?\b', re.IGNORECASE) for kw in keyword_list]
|
| 107 |
+
df = df[df.apply(lambda row: any(pattern.search(str(row)) for pattern in keyword_patterns), axis=1)]
|
| 108 |
+
st.success("Filtres appliqués avec succès !")
|
| 109 |
+
|
| 110 |
+
# 🔗 Rendre les liens cliquables
|
| 111 |
+
def make_clickable(val, text):
|
| 112 |
+
if pd.notna(val) and val != '':
|
| 113 |
+
return f'<a target="_blank" href="{val}">{text}</a>'
|
| 114 |
+
return ''
|
| 115 |
+
|
| 116 |
+
if 'Lien' in df.columns:
|
| 117 |
+
df['Lien'] = df['Lien'].apply(lambda x: make_clickable(x, 'Lien1'))
|
| 118 |
+
if 'Lien2' in df.columns:
|
| 119 |
+
df['Lien2'] = df['Lien2'].apply(lambda x: make_clickable(x, 'Lien2'))
|
| 120 |
+
|
| 121 |
+
# 🗂️ Tableau interactif avec liens cliquables
|
| 122 |
+
st.markdown("### 🗂️ Tableau des Données")
|
| 123 |
+
st.write(df.to_html(escape=False, index=False), unsafe_allow_html=True)
|
| 124 |
+
|
| 125 |
+
# 🔗 Lien et logo dans la barre latérale
|
| 126 |
+
st.sidebar.markdown(
|
| 127 |
+
"""
|
| 128 |
+
<div style="text-align: center;">
|
| 129 |
+
<a href="https://www.visipilot.com" target="_blank">
|
| 130 |
+
<img src="https://raw.githubusercontent.com/M00N69/RAPPELCONSO/main/logo%2004%20copie.jpg" alt="Visipilot Logo" style="width: 200px; margin-top: 20px;">
|
| 131 |
+
</a>
|
| 132 |
+
</div>
|
| 133 |
+
""", unsafe_allow_html=True
|
| 134 |
+
)
|