Typage des fonctions de pda et documentation

This commit is contained in:
Fabrication du Numérique 2025-06-04 21:24:56 +02:00
parent 4bb06a4801
commit 35aa7d12fa
13 changed files with 432 additions and 177 deletions

View File

@ -1,5 +1,8 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
import networkx as nx
"""
Script pour générer un rapport factorisé des vulnérabilités critiques
suivant la structure définie dans Remarques.md.
@ -37,7 +40,16 @@ from app.plan_d_action import (
inverse_niveau_labels = {v: k for k, v in niveau_labels.items()}
def interface_plan_d_action(G_temp):
def interface_plan_d_action(G_temp: nx.Graph) -> None:
"""Interface pour planifier l'action de sélection des minerais.
Args:
G_temp (nx.Graph): Le graphe temporaire à analyser.
Returns:
None: Modifie le state du Streamlit avec les données nécessaires
pour la génération du rapport factorisé des vulnérabilités critiques.
"""
if "sel_prod" not in st.session_state:
st.session_state.sel_prod = None

View File

@ -132,7 +132,7 @@ INDICATEURS = {
"Capacité libre des EMS (%) rapportée chaque vendredi."
],
'Modérée': [
"Part du second fondeur dans la production du composant audio (%).",
"Part du second fondeur dans la production du composant (%).",
"Nombre de PCB « design-for-substitution » validés."
],
'Difficile': [

View File

@ -1,6 +1,15 @@
import re
def parse_chains_md(filepath: str) -> tuple[dict, dict, dict, list, dict, dict]:
"""Lit et analyse un fichier Markdown contenant des informations sur les chaînes minérales.
Args:
filepath (str): Chemin vers le fichier Markdown à analyser.
Returns:
tuple: Un ensemble de dictionnaires et listes contenant les données extraites du fichier,
incluant les produits, composants, mineraux, chaînes et leurs descriptions détaillées.
"""
re_start_section = re.compile(r"^##\s*Chaînes\s+avec\s+risque\s+critique", re.IGNORECASE)
re_other_h2 = re.compile(r"^##\s+(?!(Chaînes\s+avec\s+risque\s+critique))")
re_chain_heading = re.compile(r"^###\s*(.+)\s*→\s*(.+)\s*→\s*(.+)$")

View File

@ -1,7 +1,16 @@
import yaml
import streamlit as st
def get_seuil(seuils_dict, key):
def get_seuil(seuils_dict: dict, key: str) -> float|None:
"""Récupère un seuil pour une clé donnée dans le dictionnaire.
Args:
seuils_dict (dict): Dictionnaire contenant les seuils.
key (str): Clé du seuil à récupérer.
Returns:
float|None: Le seuil si existant, sinon None.
"""
try:
if key in seuils_dict:
data = seuils_dict[key]
@ -16,7 +25,19 @@ def get_seuil(seuils_dict, key):
pass
return None
def set_vulnerability(v1, v2, t1, t2, seuils):
def set_vulnerability(v1: int, v2: int, t1: str, t2: str, seuils: dict) -> tuple[int,str,str,str]:
"""Calcule la vulnérabilité en fonction des seuils.
Args:
v1 (int): Valeur de vulnérabilité 1.
v2 (int): Valeur de vulnérabilité 2.
t1 (str): Type 1.
t2 (str): Type 2.
seuils (dict): Dictionnaire des seuils.
Returns:
tuple[int, str, str, str]: Poids et couleurs pour les deux types.
"""
v1_poids = 1
v1_couleur = "Vert"
if v1 > seuils[t1]["rouge"]["min"]:
@ -44,7 +65,15 @@ def set_vulnerability(v1, v2, t1, t2, seuils):
return poids, couleur, v1_couleur, v2_couleur
def colorer_couleurs(la_couleur):
def colorer_couleurs(la_couleur: str) -> str:
"""Convertit une couleur en badge Markdown.
Args:
la_couleur (str): Couleur à convertir (rouge/difficile, orange/modérée, vert/facile).
Returns:
str: Badge Markdown correspondant.
"""
t = la_couleur.lower()
if t == "rouge" or t == "difficile":
return f":red-badge[{la_couleur}]"
@ -54,7 +83,15 @@ def colorer_couleurs(la_couleur):
return f":green-badge[{la_couleur}]"
return la_couleur
def initialiser_seuils(config_path):
def initialiser_seuils(config_path: str) -> dict:
"""Charge les seuils depuis un fichier YAML de configuration.
Args:
config_path (str): Chemin vers le fichier de configuration YAML.
Returns:
dict: Dictionnaire des seuils chargés.
"""
seuils = {}
try:

View File

@ -1,7 +1,11 @@
import streamlit as st
def afficher_bloc_ihh_isg(titre, ihh, isg, details_content=""):
st.markdown(f"### {titre}")
def afficher_bloc_ihh_isg(titre, ihh, isg, details_content="", ui = True) -> str|None:
contenu_bloc = ""
if ui:
st.markdown(f"### {titre}")
else:
contenu_bloc = f"### {titre}\n"
if not details_content:
st.markdown("Données non disponibles")
@ -11,49 +15,74 @@ def afficher_bloc_ihh_isg(titre, ihh, isg, details_content=""):
# 1. Afficher vulnérabilité combinée en premier
if "#### Vulnérabilité combinée IHH-ISG" in details_content:
conteneur, = st.columns([1], gap="small", border=True)
with conteneur:
st.markdown("#### Vulnérabilité combinée IHH-ISG")
contenu = afficher_section_texte(lines, "#### Vulnérabilité combinée IHH-ISG", "###")
st.markdown(contenu)
contenu_md = "#### Vulnérabilité combinée IHH-ISG\n"
contenu_md += afficher_section_texte(lines, "#### Vulnérabilité combinée IHH-ISG", "###")
contenu_md += "\n"
if ui:
conteneur, = st.columns([1], gap="small", border=True)
with conteneur:
st.markdown(contenu_md)
else:
contenu_bloc += contenu_md
# 2. Afficher ISG des pays impliqués
if "##### ISG des pays impliqués" in details_content:
st.markdown("#### ISG des pays impliqués")
contenu = afficher_section_avec_tableau(lines, "##### ISG des pays impliqués")
st.markdown(contenu)
# Afficher le résumé ISG combiné
for line in lines:
if "**ISG combiné:" in line:
st.markdown(line)
break
contenu_md = "#### ISG des pays impliqués\n"
contenu_md += afficher_section_avec_tableau(lines, "##### ISG des pays impliqués")
contenu_md += "\n"
if ui:
st.markdown(contenu_md)
else:
contenu_bloc += contenu_md
# 3. Afficher la section IHH complète
if "#### Indice de Herfindahl-Hirschmann" in details_content:
st.markdown("#### Indice de Herfindahl-Hirschmann")
contenu_md = "#### Indice de Herfindahl-Hirschmann\n"
# Tableau de résumé IHH
contenu = afficher_section_avec_tableau(lines, "#### Indice de Herfindahl-Hirschmann")
st.markdown(contenu)
contenu_md += afficher_section_avec_tableau(lines, "#### Indice de Herfindahl-Hirschmann")
contenu_md += "\n"
if ui:
st.markdown(contenu_md)
else:
contenu_bloc += contenu_md
# IHH par entreprise
if "##### IHH par entreprise (acteurs)" in details_content:
st.markdown("##### IHH par entreprise (acteurs)")
contenu = afficher_section_texte(lines, "##### IHH par entreprise (acteurs)", "##### IHH par pays")
st.markdown(contenu)
contenu_md = "##### IHH par entreprise (acteurs)\n"
contenu_md += afficher_section_texte(lines, "##### IHH par entreprise (acteurs)", "##### IHH par pays")
st.markdown(contenu_md)
# IHH par pays
if "##### IHH par pays" in details_content:
st.markdown("##### IHH par pays")
contenu = afficher_section_texte(lines, "##### IHH par pays", "##### En résumé")
st.markdown(contenu)
contenu_md = "##### IHH par pays\n"
contenu_md += afficher_section_texte(lines, "##### IHH par pays", "##### En résumé")
contenu_md += "\n"
if ui:
st.markdown(contenu_md)
else:
contenu_bloc += contenu_md
# En résumé
if "##### En résumé" in details_content:
st.markdown("##### En résumé")
contenu = afficher_section_texte(lines, "##### En résumé", "####")
st.markdown(contenu)
contenu_md = "##### En résumé\n"
contenu_md += afficher_section_texte(lines, "##### En résumé", "####")
contenu_md += "\n"
if ui:
st.markdown(contenu_md)
else:
contenu_bloc += contenu_md
if not ui:
return contenu_bloc
else:
return None
def afficher_section_avec_tableau(lines, section_start, section_end=None):
"""Affiche une section contenant un tableau"""
@ -98,79 +127,117 @@ def afficher_section_texte(lines, section_start, section_end_marker=None):
contenu = '\n'.join(contenu_md)
return contenu
def afficher_description(titre, description):
st.markdown(f"## {titre}")
conteneur, = st.columns([1], gap="small", border=True)
with conteneur:
if description:
lines = description.split('\n')
description_lines = []
def afficher_description(titre, description, ui = True) -> str|None:
contenu_bloc = ""
if ui:
st.markdown(f"### {titre}")
else:
contenu_bloc = f"### {titre}\n"
# Extraire le premier paragraphe descriptif
for line in lines:
line = line.strip()
if not line:
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é')):
if description:
lines = description.split('\n')
description_lines = []
# Extraire le premier paragraphe descriptif
for line in lines:
line = line.strip()
if not line:
if description_lines: # Si on a déjà du contenu, une ligne vide termine le paragraphe
break
description_lines.append(line)
continue
# 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:
# Rejoindre les lignes en un seul paragraphe
full_description = ' '.join(description_lines)
st.markdown(full_description)
else:
st.markdown("Description non disponible")
if description_lines:
# Rejoindre les lignes en un seul paragraphe
contenu_md = ' '.join(description_lines)
else:
st.markdown("Description non disponible")
contenu_md = "Description non disponible"
else:
contenu_md = "Description non disponible"
def afficher_caracteristiques_minerai(minerai, mineraux_data, details_content=""):
st.markdown("### Caractéristiques générales")
if ui:
conteneur, = st.columns([1], gap="small", border=True)
with conteneur:
st.markdown(contenu_md)
return None
else:
contenu_bloc += contenu_md
return contenu_bloc
def afficher_caracteristiques_minerai(minerai, mineraux_data, details_content="", ui = True) -> str|None:
contenu_bloc = ""
if ui:
st.markdown("### Caractéristiques générales")
else:
contenu_bloc = "### Caractéristiques générales\n"
if not details_content:
st.markdown("Données non disponibles")
if ui:
st.markdown("Données non disponibles")
else:
contenu_bloc += "Données non disponibles\n"
return
lines = details_content.split('\n')
# 3. Afficher la vulnérabilité combinée ICS-IVC en dernier
if "#### Vulnérabilité combinée ICS-IVC" in details_content:
conteneur, = st.columns([1], gap="small", border=True)
with conteneur:
st.markdown("#### Vulnérabilité combinée ICS-IVC")
contenu = afficher_section_texte(lines, "#### Vulnérabilité combinée ICS-IVC", "####")
st.markdown(contenu)
contenu_md = "#### Vulnérabilité combinée ICS-IVC\n"
contenu_md += afficher_section_texte(lines, "#### Vulnérabilité combinée ICS-IVC", "####")
contenu_md += "\n"
if ui:
conteneur, = st.columns([1], gap="small", border=True)
with conteneur:
st.markdown(contenu_md)
else:
contenu_bloc += contenu_md
# 1. Afficher la section ICS complète
if "#### ICS" in details_content:
st.markdown("#### ICS")
contenu_md = "#### ICS\n"
# Afficher le premier tableau ICS (avec toutes les colonnes)
contenu = afficher_section_avec_tableau(lines, "#### ICS", "##### Valeurs d'ICS par composant")
st.markdown(contenu)
contenu_md += afficher_section_avec_tableau(lines, "#### ICS", "##### Valeurs d'ICS par composant concerné")
contenu_md += "\n"
if ui:
st.markdown(contenu_md)
else:
contenu_bloc += contenu_md
# Afficher la sous-section "Valeurs d'ICS par composant"
if "##### Valeurs d'ICS par composant" in details_content:
st.markdown("##### Valeurs d'ICS par composant")
contenu = afficher_section_avec_tableau(lines, "##### Valeurs d'ICS par composant", "**ICS moyen")
if "##### Valeurs d'ICS par composant concerné" in details_content:
contenu_md = "##### Valeurs d'ICS par composant concerné\n"
# Afficher le résumé ICS moyen
for line in lines:
if "**ICS moyen" in line:
contenu = contenu + line
contenu_md += line
break
st.markdown(contenu)
contenu_md += "\n"
contenu_md += afficher_section_avec_tableau(lines, "##### Valeurs d'ICS par composant concerné", "**ICS moyen")
contenu_md += "\n"
if ui:
st.markdown(contenu_md)
else:
contenu_bloc += contenu_md
# 2. Afficher la section IVC complète
if "#### IVC" in details_content:
st.markdown("#### IVC")
contenu_md = "#### IVC\n"
# Afficher tous les détails de la section IVC
contenu = afficher_section_texte(lines, "#### IVC", "#### Vulnérabilité combinée ICS-IVC")
st.markdown(contenu)
contenu_md += afficher_section_texte(lines, "#### IVC", "#### Vulnérabilité combinée ICS-IVC")
contenu_md += "\n"
if ui:
st.markdown(contenu_md)
return None
else:
contenu_bloc += contenu_md
return contenu_bloc

View File

@ -14,7 +14,7 @@ from app.plan_d_action.utils.data import (
initialiser_seuils
)
def calcul_poids_chaine(poids_A, poids_F, poids_T, poids_E, poids_M):
def calcul_poids_chaine(poids_A: int, poids_F: int, poids_T: int, poids_E: int, poids_M: int) -> tuple[str,dict,int]:
poids_total = (\
poids_A * poids_operation["Assemblage"] + \
poids_F * poids_operation["Fabrication"] + \
@ -35,7 +35,7 @@ def calcul_poids_chaine(poids_A, poids_F, poids_T, poids_E, poids_M):
return criticite_chaine, niveau_criticite, poids_total
def analyser_chaines(chaines, produits, composants, mineraux, seuils, top_n=None):
def analyser_chaines(chaines: list[dict], produits: dict, composants: dict, mineraux: dict, seuils: dict, top_n: int = 0) -> list[tuple[str, str, int]]:
resultats = []
for chaine in chaines:
@ -64,7 +64,7 @@ def analyser_chaines(chaines, produits, composants, mineraux, seuils, top_n=None
resultats.sort(key=lambda x: x["poids_total"], reverse=True)
# Si top_n n'est pas spécifié, tout est retourné
if top_n is None or top_n >= len(resultats):
if top_n == 0 or top_n >= len(resultats):
return resultats
# Déterminer le seuil de coupure
@ -75,7 +75,7 @@ def analyser_chaines(chaines, produits, composants, mineraux, seuils, top_n=None
return top_resultats
def tableau_de_bord(chains, produits, composants, mineraux, seuils):
def tableau_de_bord(chains: list[dict], produits: dict, composants: dict, mineraux: dict, seuils: dict):
col_left, col_right = st.columns([2, 3], gap="small", border=True)
with col_left:
st.markdown("**<u>Panneau de sélection</u>**", unsafe_allow_html=True)
@ -139,7 +139,7 @@ def tableau_de_bord(chains, produits, composants, mineraux, seuils):
couleur_A_ihh, couleur_A_isg, couleur_F_ihh, couleur_F_isg, couleur_T_ihh, couleur_T_isg,couleur_E_ihh, couleur_E_isg, couleur_M_ics, couleur_M_ivc
)
def afficher_criticites(produits, composants, mineraux, sel_prod, sel_comp, sel_miner, seuils):
def afficher_criticites(produits: dict, composants: dict, mineraux: dict, sel_prod: str, sel_comp: str, sel_miner: str, seuils: dict) -> None:
with st.expander("Vue densemble des criticités", expanded=True):
st.markdown("## Vue densemble des criticités", unsafe_allow_html=True)
@ -200,7 +200,7 @@ def afficher_criticites(produits, composants, mineraux, sel_prod, sel_comp, sel_
def afficher_explications_et_details(
couleur_A, poids_A, couleur_F, poids_F, couleur_T, poids_T, couleur_E, poids_E, couleur_M, poids_M,
produits, composants, mineraux, sel_prod, sel_comp, sel_miner,
couleur_A_ihh, couleur_A_isg, couleur_F_ihh, couleur_F_isg, couleur_T_ihh, couleur_T_isg,couleur_E_ihh, couleur_E_isg, couleur_M_ics, couleur_M_ivc):
couleur_A_ihh, couleur_A_isg, couleur_F_ihh, couleur_F_isg, couleur_T_ihh, couleur_T_isg,couleur_E_ihh, couleur_E_isg, couleur_M_ics, couleur_M_ivc, ui = True) -> str|None:
with st.expander("Explications et détails", expanded = True):
from collections import Counter
couleurs = [couleur_A, couleur_F, couleur_T, couleur_E, couleur_M]
@ -209,7 +209,7 @@ def afficher_explications_et_details(
nb_orange = compte["Orange"]
nb_vert = compte["Vert"]
st.markdown(f"""
contenu_md = f"""
Pour cette chaîne :blue-background[**{sel_prod} <-> {sel_comp} <-> {sel_miner}**], avec {nb_rouge} criticité(s) de niveau {colorer_couleurs("Rouge")}, {nb_orange} {colorer_couleurs("Orange")} et {nb_vert} {colorer_couleurs("Vert")}, les indices individuels par opération sont :
* **{sel_prod} - Assemblage** : {colorer_couleurs(couleur_A)} ({poids_A})
@ -230,31 +230,65 @@ def afficher_explications_et_details(
* **{sel_miner} - Minerai** : {colorer_couleurs(couleur_M)} ({poids_M})
* ICS = {mineraux[sel_miner]["ICS"]} ({colorer_couleurs(couleur_M_ics)}) <-> IVC = {mineraux[sel_miner]["IVC"]} ({colorer_couleurs(couleur_M_ivc)})
* pondération de la Substitution dans le calcul de la criticité globale : 2
""")
"""
contenu_md += "\n"
if ui:
st.markdown(contenu_md)
return None
else:
return contenu_md
def afficher_preconisations_et_indicateurs_generiques(niveau_criticite, poids_A, poids_F, poids_T, poids_E, poids_M):
with st.expander("Préconisations et indicateurs génériques"):
col_left, col_right = st.columns([1, 1], gap="small", border=True)
with col_left:
st.markdown("### Préconisations :\n\n")
st.markdown("Mise en œuvre : \n")
for niveau, contenu in PRECONISATIONS.items():
if niveau in niveau_criticite:
contenu_md = f"* {colorer_couleurs(niveau)}\n"
for p in PRECONISATIONS[niveau]:
contenu_md += f" - {p}\n"
st.markdown(contenu_md)
with col_right:
st.markdown("### Indicateurs :\n\n")
st.markdown("Mise en œuvre : \n")
for niveau, contenu in INDICATEURS.items():
if niveau in niveau_criticite:
contenu_md = f"* {colorer_couleurs(niveau)}\n"
for p in INDICATEURS[niveau]:
contenu_md += f" - {p}\n"
st.markdown(contenu_md)
def afficher_preconisations_et_indicateurs_generiques(niveau_criticite: dict, poids_A: int, poids_F: int, poids_T: int, poids_E: int, poids_M: int, ui: bool = True) -> tuple[str|None,str|None]:
contenu_md_left = "### Préconisations :\n\n"
contenu_md_left += "Mise en œuvre : \n"
def afficher_preconisations_et_indicateurs_specifiques(sel_prod, sel_comp, sel_miner, niveau_criticite_operation):
for niveau, contenu in PRECONISATIONS.items():
if niveau in niveau_criticite:
contenu_md_left = f"* {colorer_couleurs(niveau)}\n"
for p in PRECONISATIONS[niveau]:
contenu_md_left += f" - {p}\n"
contenu_md_right = "### Indicateurs :\n\n"
contenu_md_right += "Mise en œuvre : \n"
for niveau, contenu in INDICATEURS.items():
if niveau in niveau_criticite:
contenu_md_right = f"* {colorer_couleurs(niveau)}\n"
for p in INDICATEURS[niveau]:
contenu_md_right += f" - {p}\n"
if ui:
with st.expander("Préconisations et indicateurs génériques"):
col_left, col_right = st.columns([1, 1], gap="small", border=True)
with col_left:
st.markdown(contenu_md_left)
with col_right:
st.markdown(contenu_md_right)
return None, None
else:
return contenu_md_left, contenu_md_right
def afficher_preconisations_specifiques(operation: str, niveau_criticite_operation: dict) -> str:
contenu_md = "#### Préconisations :\n\n"
contenu_md += "Mise en œuvre : \n"
for niveau, contenu in PRECONISATIONS[operation].items():
if niveau in niveau_criticite_operation[operation]:
contenu_md += f"* {colorer_couleurs(niveau)}\n"
for p in PRECONISATIONS[operation][niveau]:
contenu_md += f" - {p}\n"
return(contenu_md)
def afficher_indicateurs_specifiques(operation: str, niveau_criticite_operation: dict) -> str:
contenu_md = "#### Indicateurs :\n\n"
contenu_md += "Mise en œuvre : \n"
for niveau, contenu in INDICATEURS[operation].items():
if niveau in niveau_criticite_operation[operation]:
contenu_md += f"* {colorer_couleurs(niveau)}\n"
for p in INDICATEURS[operation][niveau]:
contenu_md += f" - {p}\n"
return(contenu_md)
def afficher_preconisations_et_indicateurs_specifiques(sel_prod: str, sel_comp: str, sel_miner: str, niveau_criticite_operation: dict) -> None:
for operation in ["Assemblage", "Fabrication", "Traitement", "Extraction"]:
if operation == "Assemblage":
item = sel_prod
@ -266,25 +300,11 @@ def afficher_preconisations_et_indicateurs_specifiques(sel_prod, sel_comp, sel_m
st.markdown(f"### {operation} -> :blue-background[{item}]")
col_left, col_right = st.columns([1, 1], gap="small", border=True)
with col_left:
st.markdown("#### Préconisations :\n\n")
st.markdown("Mise en œuvre : \n")
for niveau, contenu in PRECONISATIONS[operation].items():
if niveau in niveau_criticite_operation[operation]:
contenu_md = f"* {colorer_couleurs(niveau)}\n"
for p in PRECONISATIONS[operation][niveau]:
contenu_md += f" - {p}\n"
st.markdown(contenu_md)
st.markdown(afficher_preconisations_specifiques(operation, niveau_criticite_operation))
with col_right:
st.markdown("#### Indicateurs :\n\n")
st.markdown("Mise en œuvre : \n")
for niveau, contenu in INDICATEURS[operation].items():
if niveau in niveau_criticite_operation[operation]:
contenu_md = f"* {colorer_couleurs(niveau)}\n"
for p in INDICATEURS[operation][niveau]:
contenu_md += f" - {p}\n"
st.markdown(contenu_md)
st.markdown(afficher_indicateurs_specifiques(operation, niveau_criticite_operation))
def afficher_preconisations_et_indicateurs(niveau_criticite, sel_prod, sel_comp, sel_miner, poids_A, poids_F, poids_T, poids_E, poids_M):
def afficher_preconisations_et_indicateurs(niveau_criticite: dict, sel_prod: str, sel_comp: str, sel_miner: str, poids_A: int, poids_F: int, poids_T: int, poids_E: int, poids_M: int) -> None:
st.markdown("## Préconisations et indicateurs")
afficher_preconisations_et_indicateurs_generiques(niveau_criticite, poids_A, poids_F, poids_T, poids_E, poids_M)
@ -306,7 +326,7 @@ def afficher_preconisations_et_indicateurs(niveau_criticite, sel_prod, sel_comp,
afficher_preconisations_et_indicateurs_specifiques(sel_prod, sel_comp, sel_miner, niveau_criticite_operation)
def afficher_details_operations(produits, composants, mineraux, sel_prod, sel_comp, sel_miner, details_sections):
def afficher_details_operations(produits, composants, mineraux, sel_prod, sel_comp, sel_miner, details_sections) -> None:
st.markdown("## Détails des opérations")
with st.expander(f"{sel_prod} et Assemblage"):
@ -332,7 +352,7 @@ def afficher_details_operations(produits, composants, mineraux, sel_prod, sel_co
afficher_caracteristiques_minerai(sel_miner, mineraux[sel_miner], minerai_general)
def initialiser_interface(filepath: str, config_path: str = "assets/config.yaml"):
def initialiser_interface(filepath: str, config_path: str = "assets/config.yaml") -> None:
produits, composants, mineraux, chains, descriptions, details_sections = parse_chains_md(filepath)

View File

@ -1,7 +1,21 @@
from typing import Dict, Tuple, Union, List, Set
import networkx as nx
def exporter_graphe_filtre(G, liens_chemins):
"""Gère l'export du graphe filtré au format DOT"""
def exporter_graphe_filtre(
G: nx.Graph,
liens_chemins: List[Tuple[Union[str, int], Union[str, int]]]
) -> nx.Graph:
"""Gère l'export du graphe filtré au format DOT.
Args:
G (nx.Graph): Le graphe d'origine à exporter.
liens_chemins (list): Liste des tuples contenant les paires de nœuds reliées
par un chemin dans le graphe, avec leurs attributs associés.
Returns:
tuple: Un tuple contenant le graphe exporté sous forme de DiGraph
et le dictionnaire des attributs du graphe exporté.
"""
G_export = nx.DiGraph()
for u, v in liens_chemins:
@ -17,8 +31,26 @@ def exporter_graphe_filtre(G, liens_chemins):
return(G_export)
def extraire_liens_filtres(chemins, niveaux, niveau_depart, niveau_arrivee, niveaux_speciaux):
"""Extrait les liens des chemins en respectant les niveaux"""
def extraire_liens_filtres(
chemins: List[List[Union[str, int]]],
niveaux: Dict[str | int, int],
niveau_depart: int,
niveau_arrivee: int,
niveaux_speciaux: list[int]
) -> List[Tuple[Union[str, int], Union[str, int]]]:
"""Extrait les liens des chemins en respectant les niveaux.
Args:
chemins (list): Liste des chemins dans le graphe.
niveaux (dict): Dictionnaire associant chaque nœud au niveau correspondant.
niveau_depart (int): Niveau de départ pour la sélection des liens.
niveau_arrivee (int): Niveau d'arrivée pour la sélection des liens.
niveaux_speciaux (set): Ensemble des niveaux spéciaux à considérer dans le filtrage.
Returns:
set: Ensemble des paires de nœuds constituant les liens du graphe filtré
en respectant les niveaux et les niveaux spéciaux demandés.
"""
liens = set()
for chemin in chemins:
for i in range(len(chemin) - 1):

View File

@ -1,5 +1,16 @@
def extraire_niveaux(G):
"""Extrait les niveaux des nœuds du graphe"""
from typing import Dict
import networkx as nx
def extraire_niveaux(G: nx.Graph) -> Dict[str | int, int]:
"""Extrait les niveaux des nœuds du graphe.
Args:
G (nx.Graph): Le graphe d'origine à analyser.
Returns:
dict: Un dictionnaire associant chaque nœud au niveau correspondant.
Les valeurs sont des entiers représentant les niveaux.
"""
niveaux = {}
for node, attrs in G.nodes(data=True):
niveau_str = attrs.get("niveau")

View File

@ -1,5 +1,17 @@
def preparer_graphe(G):
"""Nettoie et prépare le graphe pour l'analyse."""
from typing import Dict, Tuple, Union
import networkx as nx
def preparer_graphe(G: nx.Graph) -> Tuple[nx.Graph, Dict[Union[str, int], int]]:
"""Nettoie et prépare le graphe pour l'analyse.
Args:
G (nx.Graph): Le graphe d'origine à nettoyer.
Returns:
tuple: Un tuple contenant le graphe nettoyé et les niveaux temporels associés
aux nœuds du graphe. Le graphe nettoyé a eu ses nœuds qui ne respectaient
pas les critères d'admissibilité enlevés.
"""
niveaux_temp = {
node: int(str(attrs.get("niveau")).strip('"'))
for node, attrs in G.nodes(data=True)

View File

@ -1,3 +1,4 @@
from typing import Any, Dict, Tuple, List, Union, Optional
import streamlit as st
import networkx as nx
from utils.translations import _
@ -7,8 +8,16 @@ from utils.graph_utils import (
extraire_chemins_vers
)
def selectionner_minerais(G, noeuds_depart):
"""Interface pour sélectionner les minerais si nécessaire."""
def selectionner_minerais(G: nx.Graph, noeuds_depart: List[Any]) -> List[Union[str, int]]:
"""Interface pour sélectionner les minerais si nécessaire.
Args:
G (nx.Graph): Le graphe des relations entre les nœuds.
noeuds_depart (list): Les nœuds de départ qui doivent être considérés.
Returns:
list: La liste des nœuds sélectionnés comme minerais.
"""
minerais_selection = None
st.markdown(f"## {str(_('pages.plan_d_action.select_minerals'))}")
@ -32,9 +41,21 @@ def selectionner_minerais(G, noeuds_depart):
return minerais_selection
def selectionner_noeuds(
G: nx.Graph,
niveaux_temp: Dict[Union[str, int], int],
niveau_depart: int
) -> Tuple[Optional[List[Union[str, int]]], List[Union[str, int]]]:
"""Interface pour sélectionner les nœuds spécifiques de départ et d'arrivée.
def selectionner_noeuds(G, niveaux_temp, niveau_depart):
"""Interface pour sélectionner les nœuds spécifiques de départ et d'arrivée."""
Args:
G (nx.Graph): Le graphe des relations entre les nœuds.
niveaux_temp (dict): Dictionnaire contenant les niveaux des nœuds.
niveau_depart (int): Niveau à partir duquel commencer la sélection.
Returns:
tuple: La paire de départ et d'arrivée des nœuds sélectionnés.
"""
st.markdown("---")
st.markdown(f"## {str(_('pages.plan_d_action.fine_selection'))}")
@ -49,8 +70,27 @@ def selectionner_noeuds(G, niveaux_temp, niveau_depart):
return noeuds_depart, noeuds_arrivee
def extraire_chemins_selon_criteres(G, niveaux, niveau_depart, noeuds_depart, noeuds_arrivee, minerais):
"""Extrait les chemins selon les critères spécifiés"""
def extraire_chemins_selon_criteres(
G: nx.Graph,
niveaux: Dict[str | int, int],
niveau_depart: int,
noeuds_depart: Optional[List[Union[str, int]]],
noeuds_arrivee: List[Union[str, int]],
minerais: Optional[List[Union[str, int]]]
) -> List[List[str | int]]:
"""Extrait les chemins selon les critères spécifiés.
Args:
G (nx.Graph): Le graphe des relations entre les nœuds.
niveaux (dict): Dictionnaire contenant les niveaux des nœuds.
niveau_depart (int): Niveau à partir duquel commencer la sélection.
noeuds_depart (list, optional): Les nœuds de départ qui doivent être considérés.
noeuds_arrivee (list): Les nœuds d'arrivée qui doivent être inclus dans les chemins.
minerais (list, optional): La liste des nœuds sélectionnés comme minerais.
Returns:
list: Liste des chemins trouvés selon les critères spécifiés.
"""
chemins = []
if noeuds_depart and noeuds_arrivee:
for nd in noeuds_depart:

View File

@ -1,7 +1,22 @@
from typing import Dict, Optional
import re
from app.plan_d_action.utils.interface import CORRESPONDANCE_COULEURS
def remplacer_par_badge(markdown_text, correspondance=CORRESPONDANCE_COULEURS):
def remplacer_par_badge(
markdown_text: str,
correspondance: Optional[Dict[str, str]] = CORRESPONDANCE_COULEURS
) -> str:
"""Remplace certains mots par des badges colorés dans un texte Markdown.
Args:
markdown_text (str): Le texte Markdown à modifier.
correspondance (dict, optional): Dictionnaire qui mappe les mots
à remplacer vers les couleurs de leurs badges. Si None, utilise
CORRESPONDANCE_COULEURS par défaut.
Returns:
str: Le texte Markdown modifié avec des badges ajoutés.
"""
# É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

View File

@ -3366,7 +3366,7 @@ Le hafnium est un métal de transition rare, gris-argenté, ductile et lustré,
| SSDM2 | 0.80 | 0.80 | 0.80 | 0.80 |
| StockageEMMC | 0.80 | 0.80 | 0.80 | 0.80 |
##### Valeurs d'ICS par composant
##### Valeurs d'ICS par composant concerné
| Composant | ICS | Criticité |
| :-- | :-- | :-- |
@ -3550,7 +3550,7 @@ Le cuivre est un métal de transition rouge-brun, malléable et ductile, connu p
| CarteMere | 0.81 | 0.90 | 0.80 | 0.70 |
| Connecteurs | 0.81 | 0.90 | 0.80 | 0.70 |
##### Valeurs d'ICS par composant
##### Valeurs d'ICS par composant concerné
| Composant | ICS | Criticité |
| :-- | :-- | :-- |
@ -3770,7 +3770,7 @@ Le germanium est un métalloïde gris-blanc, élément numéro 32 du tableau pé
| ProcesseurASIC | 0.64 | 0.70 | 0.60 | 0.60 |
| ProcesseurX86 | 0.64 | 0.70 | 0.60 | 0.60 |
##### Valeurs d'ICS par composant
##### Valeurs d'ICS par composant concerné
| Composant | ICS | Criticité |
| :-- | :-- | :-- |
@ -3978,7 +3978,7 @@ Le silicium constitue un matériau stratégique pour de nombreux secteurs indust
| SSDM2 | 0.90 | 0.90 | 0.90 | 0.90 |
| StockageEMMC | 0.90 | 0.90 | 0.90 | 0.90 |
##### Valeurs d'ICS par composant
##### Valeurs d'ICS par composant concerné
| Composant | ICS | Criticité |
| :-- | :-- | :-- |
@ -4184,7 +4184,7 @@ Le palladium n'existe pas à l'état natif dans la nature mais se trouve princip
| ProcesseurARM | 0.50 | 0.50 | 0.40 | 0.60 |
| ProcesseurX86 | 0.50 | 0.50 | 0.40 | 0.60 |
##### Valeurs d'ICS par composant
##### Valeurs d'ICS par composant concerné
| Composant | ICS | Criticité |
| :-- | :-- | :-- |
@ -4385,7 +4385,7 @@ Le phosphore est un élément chimique non métallique, essentiel à toute forme
| ProcesseurASIC | 0.50 | 0.50 | 0.40 | 0.60 |
| ProcesseurX86 | 0.50 | 0.50 | 0.40 | 0.60 |
##### Valeurs d'ICS par composant
##### Valeurs d'ICS par composant concerné
| Composant | ICS | Criticité |
| :-- | :-- | :-- |
@ -4597,7 +4597,7 @@ L'antimoine est un métalloïde blanc-argenté, cristallin et cassant, qui prés
| ProcesseurASIC | 0.60 | 0.60 | 0.50 | 0.70 |
| ProcesseurX86 | 0.60 | 0.60 | 0.50 | 0.70 |
##### Valeurs d'ICS par composant
##### Valeurs d'ICS par composant concerné
| Composant | ICS | Criticité |
| :-- | :-- | :-- |
@ -4800,7 +4800,7 @@ Le tantale est un métal de transition rare, gris-bleu, dense et réfractaire, d
| SSDM2 | 0.70 | 0.70 | 0.70 | 0.70 |
| StockageEMMC | 0.64 | 0.70 | 0.60 | 0.60 |
##### Valeurs d'ICS par composant
##### Valeurs d'ICS par composant concerné
| Composant | ICS | Criticité |
| :-- | :-- | :-- |
@ -4988,7 +4988,7 @@ L'argent est un métal précieux qui joue un rôle essentiel mais discret dans l
| CarteMere | 0.61 | 0.70 | 0.50 | 0.60 |
| Connecteurs | 0.61 | 0.70 | 0.50 | 0.60 |
##### Valeurs d'ICS par composant
##### Valeurs d'ICS par composant concerné
| Composant | ICS | Criticité |
| :-- | :-- | :-- |
@ -5186,7 +5186,7 @@ L'étain est un métal gris-argent, malléable, moyennement ductile à températ
| CarteMere | 0.60 | 0.60 | 0.60 | 0.60 |
| Connecteurs | 0.60 | 0.60 | 0.60 | 0.60 |
##### Valeurs d'ICS par composant
##### Valeurs d'ICS par composant concerné
| Composant | ICS | Criticité |
| :-- | :-- | :-- |
@ -5382,7 +5382,7 @@ Le lithium est un métal alcalin léger, blanc-argenté, qui se caractérise par
| :-- | :--: | :--: | :--: | :--: |
| Batterie | 0.51 | 0.60 | 0.50 | 0.40 |
##### Valeurs d'ICS par composant
##### Valeurs d'ICS par composant concerné
| Composant | ICS | Criticité |
| :-- | :-- | :-- |
@ -5589,7 +5589,7 @@ Le nickel est un métal de transition gris-argenté, ferromagnétique, prisé po
| Connecteurs | 0.50 | 0.50 | 0.40 | 0.60 |
| Batterie | 0.44 | 0.50 | 0.40 | 0.40 |
##### Valeurs d'ICS par composant
##### Valeurs d'ICS par composant concerné
| Composant | ICS | Criticité |
| :-- | :-- | :-- |
@ -5810,7 +5810,7 @@ Le gallium est un métal rare aux propriétés physico-chimiques remarquables, d
| EcranSpecifique | 0.41 | 0.50 | 0.40 | 0.30 |
| CreusetGraphite | 0.37 | 0.40 | 0.30 | 0.40 |
##### Valeurs d'ICS par composant
##### Valeurs d'ICS par composant concerné
| Composant | ICS | Criticité |
| :-- | :-- | :-- |
@ -6005,7 +6005,7 @@ Le lanthane est un métal de transition appartenant à la famille des terres rar
| Camera | 0.64 | 0.70 | 0.60 | 0.60 |
| Batterie | 0.54 | 0.60 | 0.50 | 0.50 |
##### Valeurs d'ICS par composant
##### Valeurs d'ICS par composant concerné
| Composant | ICS | Criticité |
| :-- | :-- | :-- |
@ -6196,7 +6196,7 @@ Le graphite existe sous deux formes principales : naturel (extrait de gisements
| Batterie | 0.51 | 0.60 | 0.50 | 0.40 |
| CreusetGraphite | 0.44 | 0.50 | 0.30 | 0.50 |
##### Valeurs d'ICS par composant
##### Valeurs d'ICS par composant concerné
| Composant | ICS | Criticité |
| :-- | :-- | :-- |
@ -6396,7 +6396,7 @@ La demande mondiale continue d'être soutenue par le secteur de la galvanisation
| Batterie | 0.30 | 0.30 | 0.20 | 0.40 |
| Boitier | 0.30 | 0.30 | 0.20 | 0.40 |
##### Valeurs d'ICS par composant
##### Valeurs d'ICS par composant concerné
| Composant | ICS | Criticité |
| :-- | :-- | :-- |
@ -6599,7 +6599,7 @@ Le cobalt est un métal de transition gris, brillant et ferromagnétique, décou
| :-- | :--: | :--: | :--: | :--: |
| Batterie | 0.57 | 0.60 | 0.60 | 0.50 |
##### Valeurs d'ICS par composant
##### Valeurs d'ICS par composant concerné
| Composant | ICS | Criticité |
| :-- | :-- | :-- |
@ -6797,7 +6797,7 @@ Le manganèse est un métal de transition gris-argenté, dur et cassant, caract
| Batterie | 0.40 | 0.40 | 0.30 | 0.50 |
| Boitier | 0.40 | 0.40 | 0.30 | 0.50 |
##### Valeurs d'ICS par composant
##### Valeurs d'ICS par composant concerné
| Composant | ICS | Criticité |
| :-- | :-- | :-- |
@ -7004,7 +7004,7 @@ Malgré sa rareté (production mondiale de quelques centaines de tonnes par an),
| Capteurs | 0.70 | 0.70 | 0.70 | 0.70 |
| DisqueDur | 0.64 | 0.70 | 0.60 | 0.60 |
##### Valeurs d'ICS par composant
##### Valeurs d'ICS par composant concerné
| Composant | ICS | Criticité |
| :-- | :-- | :-- |
@ -7193,7 +7193,7 @@ Le titane est un métal de transition léger, résistant et de couleur gris arge
| :-- | :--: | :--: | :--: | :--: |
| Boitier | 0.67 | 0.70 | 0.60 | 0.70 |
##### Valeurs d'ICS par composant
##### Valeurs d'ICS par composant concerné
| Composant | ICS | Criticité |
| :-- | :-- | :-- |
@ -7386,7 +7386,7 @@ Le scandium est un métal de transition léger appartenant au groupe IIIB du tab
| ProcesseurASIC | 0.70 | 0.70 | 0.70 | 0.70 |
| ProcesseurX86 | 0.70 | 0.70 | 0.70 | 0.70 |
##### Valeurs d'ICS par composant
##### Valeurs d'ICS par composant concerné
| Composant | ICS | Criticité |
| :-- | :-- | :-- |
@ -7569,7 +7569,7 @@ Le chrome est un métal de transition de numéro atomique 24, symbole Cr, caract
| :-- | :--: | :--: | :--: | :--: |
| Boitier | 0.39 | 0.30 | 0.40 | 0.50 |
##### Valeurs d'ICS par composant
##### Valeurs d'ICS par composant concerné
| Composant | ICS | Criticité |
| :-- | :-- | :-- |
@ -7759,7 +7759,7 @@ Le magnésium est un métal alcalino-terreux léger, blanc argenté, qui présen
| :-- | :--: | :--: | :--: | :--: |
| Boitier | 0.50 | 0.50 | 0.40 | 0.60 |
##### Valeurs d'ICS par composant
##### Valeurs d'ICS par composant concerné
| Composant | ICS | Criticité |
| :-- | :-- | :-- |
@ -7966,7 +7966,7 @@ Le cérium est un métal lanthanide gris-argenté, malléable et ductile, décou
| EcranLCD | 0.70 | 0.70 | 0.70 | 0.70 |
| EcranOLED | 0.64 | 0.70 | 0.60 | 0.60 |
##### Valeurs d'ICS par composant
##### Valeurs d'ICS par composant concerné
| Composant | ICS | Criticité |
| :-- | :-- | :-- |
@ -8148,7 +8148,7 @@ L'holmium est un métal de terre rare appartenant à la famille des lanthanides,
| Camera | 0.84 | 0.90 | 0.80 | 0.80 |
| Capteurs | 0.84 | 0.90 | 0.80 | 0.80 |
##### Valeurs d'ICS par composant
##### Valeurs d'ICS par composant concerné
| Composant | ICS | Criticité |
| :-- | :-- | :-- |
@ -8333,7 +8333,7 @@ L'europium est un métal de la série des lanthanides, découvert en 1901 par Eu
| EcranLCD | 0.81 | 0.90 | 0.80 | 0.70 |
| EcranMiniLED | 0.81 | 0.90 | 0.80 | 0.70 |
##### Valeurs d'ICS par composant
##### Valeurs d'ICS par composant concerné
| Composant | ICS | Criticité |
| :-- | :-- | :-- |
@ -8515,7 +8515,7 @@ Le terbium est un élément métallique du groupe des lanthanides, découvert en
| EcranLCD | 0.81 | 0.90 | 0.80 | 0.70 |
| EcranMiniLED | 0.81 | 0.90 | 0.80 | 0.70 |
##### Valeurs d'ICS par composant
##### Valeurs d'ICS par composant concerné
| Composant | ICS | Criticité |
| :-- | :-- | :-- |
@ -8703,7 +8703,7 @@ L'yttrium est un métal de transition du groupe 3, souvent classé parmi les ter
| EcranMiniLED | 0.74 | 0.80 | 0.70 | 0.70 |
| EcranOLED | 0.70 | 0.70 | 0.70 | 0.70 |
##### Valeurs d'ICS par composant
##### Valeurs d'ICS par composant concerné
| Composant | ICS | Criticité |
| :-- | :-- | :-- |
@ -8888,7 +8888,7 @@ Le béryllium est un métal alcalino-terreux léger, dur et fragile, découvert
| Connecteurs | 0.64 | 0.70 | 0.60 | 0.60 |
| Connectivite | 0.64 | 0.70 | 0.60 | 0.60 |
##### Valeurs d'ICS par composant
##### Valeurs d'ICS par composant concerné
| Composant | ICS | Criticité |
| :-- | :-- | :-- |
@ -9069,7 +9069,7 @@ Le secteur technologique émerge comme nouveau pilier de croissance (+7% en 2024
| ProcesseurASIC | 0.60 | 0.60 | 0.60 | 0.60 |
| ProcesseurX86 | 0.60 | 0.60 | 0.60 | 0.60 |
##### Valeurs d'ICS par composant
##### Valeurs d'ICS par composant concerné
| Composant | ICS | Criticité |
| :-- | :-- | :-- |
@ -9258,7 +9258,7 @@ Le quartz ultra-pur 5N représente l'une des matières premières les plus criti
| :-- | :--: | :--: | :--: | :--: |
| CreusetQuartz | 0.74 | 0.80 | 0.70 | 0.70 |
##### Valeurs d'ICS par composant
##### Valeurs d'ICS par composant concerné
| Composant | ICS | Criticité |
| :-- | :-- | :-- |
@ -9452,7 +9452,7 @@ Principalement utilisé dans la fabrication de carbures cémentés (50% des usag
| ProcesseurASIC | 0.60 | 0.60 | 0.50 | 0.70 |
| ProcesseurX86 | 0.60 | 0.60 | 0.50 | 0.70 |
##### Valeurs d'ICS par composant
##### Valeurs d'ICS par composant concerné
| Composant | ICS | Criticité |
| :-- | :-- | :-- |
@ -9652,7 +9652,7 @@ Le samarium est un métal des terres rares du groupe des lanthanides, caractéri
| Capteurs | 0.74 | 0.80 | 0.70 | 0.70 |
| Connectivite | 0.64 | 0.70 | 0.60 | 0.60 |
##### Valeurs d'ICS par composant
##### Valeurs d'ICS par composant concerné
| Composant | ICS | Criticité |
| :-- | :-- | :-- |
@ -9840,7 +9840,7 @@ Le gadolinium est un métal rare, blanc-argenté, appartenant à la famille des
| :-- | :--: | :--: | :--: | :--: |
| Capteurs | 0.74 | 0.80 | 0.70 | 0.70 |
##### Valeurs d'ICS par composant
##### Valeurs d'ICS par composant concerné
| Composant | ICS | Criticité |
| :-- | :-- | :-- |
@ -10025,7 +10025,7 @@ L'erbium est un métal de transition appartenant au groupe des terres rares, dé
| :-- | :--: | :--: | :--: | :--: |
| Connectivite | 0.74 | 0.80 | 0.70 | 0.70 |
##### Valeurs d'ICS par composant
##### Valeurs d'ICS par composant concerné
| Composant | ICS | Criticité |
| :-- | :-- | :-- |
@ -10212,7 +10212,7 @@ Le dysprosium est un métal lanthanide rare de couleur blanc-argenté, découver
| :-- | :--: | :--: | :--: | :--: |
| Audio | 0.70 | 0.70 | 0.70 | 0.70 |
##### Valeurs d'ICS par composant
##### Valeurs d'ICS par composant concerné
| Composant | ICS | Criticité |
| :-- | :-- | :-- |
@ -10391,7 +10391,7 @@ Le néodyme est un métal de transition appartenant à la famille des lanthanide
| :-- | :--: | :--: | :--: | :--: |
| Audio | 0.47 | 0.50 | 0.50 | 0.40 |
##### Valeurs d'ICS par composant
##### Valeurs d'ICS par composant concerné
| Composant | ICS | Criticité |
| :-- | :-- | :-- |
@ -10585,7 +10585,7 @@ Le praséodyme est un métal de la famille des lanthanides (terres rares), déco
| :-- | :--: | :--: | :--: | :--: |
| Audio | 0.41 | 0.50 | 0.40 | 0.30 |
##### Valeurs d'ICS par composant
##### Valeurs d'ICS par composant concerné
| Composant | ICS | Criticité |
| :-- | :-- | :-- |

View File

@ -400,7 +400,7 @@ def generate_minerals_section(data, results, config):
ics_average = sum(ics_values) / len(ics_values)
color, suffix = determine_threshold_color(ics_average, "ICS", config.get('thresholds'))
template.append("##### Valeurs d'ICS par composant\n")
template.append("##### Valeurs d'ICS par composant concerné\n")
template.append("| Composant | ICS | Criticité |")
template.append("| :-- | :-- | :-- |")