Améliorations

This commit is contained in:
Fabrication du Numérique 2025-06-03 12:52:33 +02:00
parent 69272a44d6
commit 255361e9aa
5 changed files with 94 additions and 45 deletions

View File

@ -567,6 +567,8 @@ def build_minerai_sections(md: str) -> str:
md, md,
flags=re.DOTALL flags=re.DOTALL
) )
# suppression pour le dernier minerai dans la fiche IHH
md = re.sub(r"# Tableaux de synthèse.*<!---- AUTO-END:SECTION-IHH-TRAITEMENT -->", "", md, flags=re.DOTALL)
except Exception as e: except Exception as e:
st.error(f"Erreur lors de la génération des sections IHH: {e}") st.error(f"Erreur lors de la génération des sections IHH: {e}")

View File

@ -173,7 +173,7 @@ def interface_ia_nalyse(G_temp):
if liens_chemins: if liens_chemins:
G_final = exporter_graphe_filtre(G_temp, liens_chemins) G_final = exporter_graphe_filtre(G_temp, liens_chemins)
if st.button(str(_("pages.ia_nalyse.submit_request"))): if st.button(str(_("pages.ia_nalyse.submit_request")), icon=":material/send:"):
soumettre_batch(st.session_state.username, G_final) soumettre_batch(st.session_state.username, G_final)
st.rerun() st.rerun()
else: else:
@ -181,15 +181,15 @@ def interface_ia_nalyse(G_temp):
elif resultat["statut"] == "terminé" and resultat["telechargement"]: elif resultat["statut"] == "terminé" and resultat["telechargement"]:
if not st.session_state.get("telechargement_confirme"): if not st.session_state.get("telechargement_confirme"):
st.download_button(str(_("buttons.download")), resultat["telechargement"], file_name="analyse.zip") st.download_button(str(_("buttons.download")), resultat["telechargement"], file_name="analyse.zip", icon=":material/download:")
if st.button(str(_("pages.ia_nalyse.confirm_download"))): if st.button(str(_("pages.ia_nalyse.confirm_download")), icon=":material/task_alt:"):
nettoyage_post_telechargement(st.session_state.username) nettoyage_post_telechargement(st.session_state.username)
st.session_state["telechargement_confirme"] = True st.session_state["telechargement_confirme"] = True
st.rerun() st.rerun()
else: else:
st.success("Résultat supprimé. Vous pouvez relancer une nouvelle analyse.") st.success("Résultat supprimé. Vous pouvez relancer une nouvelle analyse.")
if st.button(str(_("buttons.refresh"))): if st.button(str(_("buttons.refresh")), icon=":material/refresh:"):
st.rerun() st.rerun()
else: else:
if st.button(str(_("buttons.refresh"))): if st.button(str(_("buttons.refresh")), icon=":material/refresh:"):
st.rerun() st.rerun()

View File

@ -8,6 +8,7 @@ suivant la structure définie dans Remarques.md.
import streamlit as st import streamlit as st
import networkx as nx import networkx as nx
import uuid import uuid
import re
from utils.translations import _ from utils.translations import _
from utils.widgets import html_expander from utils.widgets import html_expander
from networkx.drawing.nx_agraph import write_dot from networkx.drawing.nx_agraph import write_dot
@ -169,6 +170,24 @@ def extraire_liens_filtres(chemins, niveaux, niveau_depart, niveau_arrivee, nive
liens.add((u, v)) liens.add((u, v))
return liens return liens
CORRESPONDANCE_COULEURS = {
"Rouge": "red",
"Orange": "orange",
"Vert": "green",
"FAIBLE": "green",
"MODÉRÉE": "orange",
"ÉLEVÉE à CRITIQUE": "red"
}
def remplacer_par_badge(markdown_text, correspondance=CORRESPONDANCE_COULEURS):
# Échappe les mots à remplacer s'ils contiennent des accents ou espaces
for mot, couleur in correspondance.items():
# Utilise des bords de mots (\b) pour éviter les remplacements partiels
pattern = r'\b' + re.escape(mot) + r'\b'
remplacement = f":{couleur}-badge[{mot}]"
markdown_text = re.sub(pattern, remplacement, markdown_text)
return markdown_text
def interface_plan_d_action(G_temp): def interface_plan_d_action(G_temp):
st.markdown(f"# {str(_('pages.plan_d_action.title'))}") st.markdown(f"# {str(_('pages.plan_d_action.title'))}")
@ -208,7 +227,7 @@ def interface_plan_d_action(G_temp):
G_final = exporter_graphe_filtre(G_temp, liens_chemins) G_final = exporter_graphe_filtre(G_temp, liens_chemins)
st.session_state["G_final"] = G_final st.session_state["G_final"] = G_final
# formulaire ou sélection # formulaire ou sélection
if st.button(str(_("pages.plan_d_action.submit_request")), icon=":material/play_arrow:"): if st.button(str(_("pages.plan_d_action.submit_request")), icon=":material/send:"):
# On déclenche la suite — mais on NE traite rien maintenant # On déclenche la suite — mais on NE traite rien maintenant
st.session_state["plan_d_action"] = 1 st.session_state["plan_d_action"] = 1
st.rerun() # force la réexécution immédiatement avec état mis à jour st.rerun() # force la réexécution immédiatement avec état mis à jour
@ -223,7 +242,7 @@ def interface_plan_d_action(G_temp):
data = extract_data_from_graph(graph, ref_graph) data = extract_data_from_graph(graph, ref_graph)
results = calculate_vulnerabilities(data, config) results = calculate_vulnerabilities(data, config)
report, file_names = generate_report(data, results, config) report, file_names = generate_report(data, results, config)
write_report(report, st.session_state["G_md"]) write_report(remplacer_par_badge(report), st.session_state["G_md"])
st.session_state["g_md_done"] = True # pour ne pas re-traiter à chaque affichage st.session_state["g_md_done"] = True # pour ne pas re-traiter à chaque affichage
# Affichage de linterface Streamlit # Affichage de linterface Streamlit

View File

@ -365,8 +365,10 @@ def afficher_bloc_ihh_isg(titre, ihh, isg, details_content=""):
# 1. Afficher vulnérabilité combinée en premier # 1. Afficher vulnérabilité combinée en premier
if "#### Vulnérabilité combinée IHH-ISG" in details_content: if "#### Vulnérabilité combinée IHH-ISG" in details_content:
st.markdown("#### Vulnérabilité combinée IHH-ISG") conteneur, = st.columns([1], gap="small", border=True)
afficher_section_texte(lines, "#### Vulnérabilité combinée IHH-ISG", "###") with conteneur:
st.markdown("#### Vulnérabilité combinée IHH-ISG")
afficher_section_texte(lines, "#### Vulnérabilité combinée IHH-ISG", "###")
# 2. Afficher ISG des pays impliqués # 2. Afficher ISG des pays impliqués
if "##### ISG des pays impliqués" in details_content: if "##### ISG des pays impliqués" in details_content:
@ -442,32 +444,34 @@ def afficher_section_texte(lines, section_start, section_end_marker=None):
def afficher_description(titre, description): def afficher_description(titre, description):
st.markdown(f"## {titre}") st.markdown(f"## {titre}")
if description: conteneur, = st.columns([1], gap="small", border=True)
lines = description.split('\n') with conteneur:
description_lines = [] if description:
lines = description.split('\n')
description_lines = []
# Extraire le premier paragraphe descriptif # Extraire le premier paragraphe descriptif
for line in lines: for line in lines:
line = line.strip() line = line.strip()
if not line: if not line:
if description_lines: # Si on a déjà du contenu, une ligne vide termine le paragraphe if description_lines: # Si on a déjà du contenu, une ligne vide termine le paragraphe
break
continue
# Arrêter aux titres de sections ou tableaux
if (line.startswith('####') or
line.startswith('|') or
line.startswith('**Unité')):
break break
continue description_lines.append(line)
# Arrêter aux titres de sections ou tableaux
if (line.startswith('####') or
line.startswith('|') or
line.startswith('**Unité')):
break
description_lines.append(line)
if description_lines: if description_lines:
# Rejoindre les lignes en un seul paragraphe # Rejoindre les lignes en un seul paragraphe
full_description = ' '.join(description_lines) full_description = ' '.join(description_lines)
st.markdown(full_description) st.markdown(full_description)
else:
st.markdown("Description non disponible")
else: else:
st.markdown("Description non disponible") st.markdown("Description non disponible")
else:
st.markdown("Description non disponible")
def afficher_caracteristiques_minerai(minerai, mineraux_data, details_content=""): def afficher_caracteristiques_minerai(minerai, mineraux_data, details_content=""):
st.markdown("### Caractéristiques générales") st.markdown("### Caractéristiques générales")
@ -480,8 +484,10 @@ def afficher_caracteristiques_minerai(minerai, mineraux_data, details_content=""
# 3. Afficher la vulnérabilité combinée ICS-IVC en dernier # 3. Afficher la vulnérabilité combinée ICS-IVC en dernier
if "#### Vulnérabilité combinée ICS-IVC" in details_content: if "#### Vulnérabilité combinée ICS-IVC" in details_content:
st.markdown("#### Vulnérabilité combinée ICS-IVC") conteneur, = st.columns([1], gap="small", border=True)
afficher_section_texte(lines, "#### Vulnérabilité combinée ICS-IVC", "####") with conteneur:
st.markdown("#### Vulnérabilité combinée ICS-IVC")
afficher_section_texte(lines, "#### Vulnérabilité combinée ICS-IVC", "####")
# 1. Afficher la section ICS complète # 1. Afficher la section ICS complète
if "#### ICS" in details_content: if "#### ICS" in details_content:
@ -558,11 +564,12 @@ def set_vulnerability(v1, v2, t1, t2, seuils):
return poids, couleur, v1_couleur, v2_couleur return poids, couleur, v1_couleur, v2_couleur
def colorer_couleurs(la_couleur): def colorer_couleurs(la_couleur):
if la_couleur.lower() == "rouge": t = la_couleur.lower()
if t == "rouge" or t == "difficile":
return f":red-badge[{la_couleur}]" return f":red-badge[{la_couleur}]"
if la_couleur.lower() == "orange": if t == "orange" or t == "modérée":
return f":orange-badge[{la_couleur}]" return f":orange-badge[{la_couleur}]"
if la_couleur.lower() == "vert": if t == "vert" or t == "facile":
return f":green-badge[{la_couleur}]" return f":green-badge[{la_couleur}]"
return la_couleur return la_couleur
@ -721,7 +728,7 @@ def initialiser_interface(filepath: str, config_path: str = "assets/config.yaml"
* pondération de la Substitution dans le calcul de la criticité globale : 2 * pondération de la Substitution dans le calcul de la criticité globale : 2
""") """)
st.markdown("---") st.markdown("## Préconisations et indicateurs")
with st.expander("Préconisations et indicateurs génériques"): with st.expander("Préconisations et indicateurs génériques"):
col_left, col_right = st.columns([1, 1], gap="small", border=True) col_left, col_right = st.columns([1, 1], gap="small", border=True)
@ -730,7 +737,7 @@ def initialiser_interface(filepath: str, config_path: str = "assets/config.yaml"
st.markdown("Mise en œuvre : \n") st.markdown("Mise en œuvre : \n")
for niveau, contenu in PRECONISATIONS.items(): for niveau, contenu in PRECONISATIONS.items():
if niveau in niveau_criticite: if niveau in niveau_criticite:
contenu_md = f"* {niveau}\n" contenu_md = f"* {colorer_couleurs(niveau)}\n"
for p in PRECONISATIONS[niveau]: for p in PRECONISATIONS[niveau]:
contenu_md += f" - {p}\n" contenu_md += f" - {p}\n"
st.markdown(contenu_md) st.markdown(contenu_md)
@ -739,7 +746,7 @@ def initialiser_interface(filepath: str, config_path: str = "assets/config.yaml"
st.markdown("Mise en œuvre : \n") st.markdown("Mise en œuvre : \n")
for niveau, contenu in INDICATEURS.items(): for niveau, contenu in INDICATEURS.items():
if niveau in niveau_criticite: if niveau in niveau_criticite:
contenu_md = f"* {niveau}\n" contenu_md = f"* {colorer_couleurs(niveau)}\n"
for p in INDICATEURS[niveau]: for p in INDICATEURS[niveau]:
contenu_md += f" - {p}\n" contenu_md += f" - {p}\n"
st.markdown(contenu_md) st.markdown(contenu_md)
@ -760,15 +767,21 @@ def initialiser_interface(filepath: str, config_path: str = "assets/config.yaml"
niveau_criticite_operation["Extraction"] = affectation_poids(poids_E) niveau_criticite_operation["Extraction"] = affectation_poids(poids_E)
for operation in ["Assemblage", "Fabrication", "Traitement", "Extraction"]: for operation in ["Assemblage", "Fabrication", "Traitement", "Extraction"]:
if operation == "Assemblage":
item = sel_prod
elif operation == "Fabrication":
item = sel_comp
else:
item = sel_miner
with st.expander(f"Préconisations et indicateurs spécifiques - {operation}"): with st.expander(f"Préconisations et indicateurs spécifiques - {operation}"):
st.markdown(f"### {operation}") st.markdown(f"### {operation} -> :blue-background[{item}]")
col_left, col_right = st.columns([1, 1], gap="small", border=True) col_left, col_right = st.columns([1, 1], gap="small", border=True)
with col_left: with col_left:
st.markdown("#### Préconisations :\n\n") st.markdown("#### Préconisations :\n\n")
st.markdown("Mise en œuvre : \n") st.markdown("Mise en œuvre : \n")
for niveau, contenu in PRECONISATIONS[operation].items(): for niveau, contenu in PRECONISATIONS[operation].items():
if niveau in niveau_criticite_operation[operation]: if niveau in niveau_criticite_operation[operation]:
contenu_md = f"* {niveau}\n" contenu_md = f"* {colorer_couleurs(niveau)}\n"
for p in PRECONISATIONS[operation][niveau]: for p in PRECONISATIONS[operation][niveau]:
contenu_md += f" - {p}\n" contenu_md += f" - {p}\n"
st.markdown(contenu_md) st.markdown(contenu_md)
@ -777,12 +790,12 @@ def initialiser_interface(filepath: str, config_path: str = "assets/config.yaml"
st.markdown("Mise en œuvre : \n") st.markdown("Mise en œuvre : \n")
for niveau, contenu in INDICATEURS[operation].items(): for niveau, contenu in INDICATEURS[operation].items():
if niveau in niveau_criticite_operation[operation]: if niveau in niveau_criticite_operation[operation]:
contenu_md = f"* {niveau}\n" contenu_md = f"* {colorer_couleurs(niveau)}\n"
for p in INDICATEURS[operation][niveau]: for p in INDICATEURS[operation][niveau]:
contenu_md += f" - {p}\n" contenu_md += f" - {p}\n"
st.markdown(contenu_md) st.markdown(contenu_md)
st.markdown("---") st.markdown("## Détails des opérations")
with st.expander(f"{sel_prod} et Assemblage"): with st.expander(f"{sel_prod} et Assemblage"):
assemblage_details = details_sections.get(f"{sel_prod}_assemblage", "") assemblage_details = details_sections.get(f"{sel_prod}_assemblage", "")
@ -802,9 +815,7 @@ def initialiser_interface(filepath: str, config_path: str = "assets/config.yaml"
extraction_details = details_sections.get(f"{sel_miner}_extraction", "") extraction_details = details_sections.get(f"{sel_miner}_extraction", "")
afficher_bloc_ihh_isg("Extraction", mineraux[sel_miner]["IHH_Extraction"], mineraux[sel_miner]["ISG_Extraction"], extraction_details) afficher_bloc_ihh_isg("Extraction", mineraux[sel_miner]["IHH_Extraction"], mineraux[sel_miner]["ISG_Extraction"], extraction_details)
traitement_details = details_sections.get(f"{sel_miner}_traitement", "") traitement_details = details_sections.get(f"{sel_miner}_traitement", "").removesuffix("\n---\n")
afficher_bloc_ihh_isg("Traitement", mineraux[sel_miner]["IHH_Traitement"], mineraux[sel_miner]["ISG_Traitement"], traitement_details) afficher_bloc_ihh_isg("Traitement", mineraux[sel_miner]["IHH_Traitement"], mineraux[sel_miner]["ISG_Traitement"], traitement_details)
afficher_caracteristiques_minerai(sel_miner, mineraux[sel_miner], minerai_general) afficher_caracteristiques_minerai(sel_miner, mineraux[sel_miner], minerai_general)
st.markdown("---")

View File

@ -137,6 +137,7 @@ ASUS_Taiwan_Assemblage_OrdiBureau [fillcolor="#d1e0ff", label=ASUS, niveau=12];
HP_Chine_Assemblage_OrdiBureau [fillcolor="#d1e0ff", label="HP China", niveau=12]; HP_Chine_Assemblage_OrdiBureau [fillcolor="#d1e0ff", label="HP China", niveau=12];
Lenovo_Chine_Assemblage_OrdiBureau [fillcolor="#d1e0ff", label=Lenovo, niveau=12]; Lenovo_Chine_Assemblage_OrdiBureau [fillcolor="#d1e0ff", label=Lenovo, niveau=12];
OrdiPortable [fillcolor="#a0d6ff", label="Ordinateur portable", niveau=0]; OrdiPortable [fillcolor="#a0d6ff", label="Ordinateur portable", niveau=0];
StationTravailPortable [fillcolor="#a0d6ff", label="Station de travail portable", niveau=0];
Assemblage_OrdiPortable [fillcolor="#ffd699", ihh_acteurs=14, ihh_pays=35, label=Assemblage, niveau=10]; Assemblage_OrdiPortable [fillcolor="#ffd699", ihh_acteurs=14, ihh_pays=35, label=Assemblage, niveau=10];
Bresil_Assemblage_OrdiPortable [fillcolor="#e6f2ff", label=Brésil, niveau=11]; Bresil_Assemblage_OrdiPortable [fillcolor="#e6f2ff", label=Brésil, niveau=11];
Chine_Assemblage_OrdiPortable [fillcolor="#e6f2ff", label=Chine, niveau=11]; Chine_Assemblage_OrdiPortable [fillcolor="#e6f2ff", label=Chine, niveau=11];
@ -2476,6 +2477,22 @@ OrdiPortable -> SSDM2;
OrdiPortable -> ProcesseurX86; OrdiPortable -> ProcesseurX86;
OrdiPortable -> SSD25; OrdiPortable -> SSD25;
OrdiPortable -> Assemblage_OrdiPortable; OrdiPortable -> Assemblage_OrdiPortable;
StationTravailPortable -> Audio;
StationTravailPortable -> Camera;
StationTravailPortable -> Capteurs;
StationTravailPortable -> Connecteurs;
StationTravailPortable -> EcranOLED;
StationTravailPortable -> Boitier;
StationTravailPortable -> Connectivite;
StationTravailPortable -> Batterie;
StationTravailPortable -> MemoireRAM;
StationTravailPortable -> CarteMere;
StationTravailPortable -> ProcesseurARM;
StationTravailPortable -> SSD25;
StationTravailPortable -> Television;
StationTravailPortable -> Assemblage_OrdiPortable;
Assemblage_OrdiPortable -> Bresil_Assemblage_OrdiPortable [color=purple, fontcolor=purple, label="3%", poids=1]; Assemblage_OrdiPortable -> Bresil_Assemblage_OrdiPortable [color=purple, fontcolor=purple, label="3%", poids=1];
Assemblage_OrdiPortable -> Chine_Assemblage_OrdiPortable [color=purple, fontcolor=purple, label="56%", poids=2]; Assemblage_OrdiPortable -> Chine_Assemblage_OrdiPortable [color=purple, fontcolor=purple, label="56%", poids=2];
Assemblage_OrdiPortable -> Vietnam_Assemblage_OrdiPortable [color=purple, fontcolor=purple, label="11%", poids=1]; Assemblage_OrdiPortable -> Vietnam_Assemblage_OrdiPortable [color=purple, fontcolor=purple, label="11%", poids=1];