Files changed (2) hide show
  1. src/app.py +15 -8
  2. src/flowchart_engine.py +25 -23
src/app.py CHANGED
@@ -605,14 +605,21 @@ with tab_single:
605
  pays_transformation = None
606
 
607
  if provenance_connue == "Oui":
608
- pays_production = st.text_input(
609
- "Pays de production primaire / origine de la graine",
610
- key="input_pays_prod",
611
- placeholder="Ex : France, Brésil, Ukraine…",
612
- help="Pays de production de la MP brute (ou pays d'origine de la graine pour le soja).",
613
- )
614
-
615
- if type_mp_code != "mineral":
 
 
 
 
 
 
 
616
  pays_transformation = st.text_input(
617
  "Pays de transformation (laisser vide si MP brute)",
618
  key="input_pays_transfo",
 
605
  pays_transformation = None
606
 
607
  if provenance_connue == "Oui":
608
+ if type_mp_code == "mineral":
609
+ # Pour les minéraux, on demande uniquement le pays de transformation
610
+ pays_transformation = st.text_input(
611
+ "Pays de transformation",
612
+ key="input_pays_transfo",
613
+ placeholder="Ex : France, Allemagne, Pays-Bas…",
614
+ help="Pays où la transformation du minéral a eu lieu.",
615
+ )
616
+ else:
617
+ pays_production = st.text_input(
618
+ "Pays de production primaire / origine de la graine",
619
+ key="input_pays_prod",
620
+ placeholder="Ex : France, Brésil, Ukraine…",
621
+ help="Pays de production de la MP brute (ou pays d'origine de la graine pour le soja).",
622
+ )
623
  pays_transformation = st.text_input(
624
  "Pays de transformation (laisser vide si MP brute)",
625
  key="input_pays_transfo",
src/flowchart_engine.py CHANGED
@@ -63,21 +63,32 @@ class CarbonResult:
63
  erreur: Optional[str] = None
64
 
65
 
 
 
 
 
 
 
 
 
 
 
66
  def _is_france(pays: Optional[str]) -> bool:
67
  """Vérifie si le pays est la France."""
68
  if not pays:
69
  return False
70
- return pays.lower().strip() in ("france", "fr")
 
71
 
72
 
73
  def _is_european(pays: Optional[str]) -> bool:
74
  """Vérifie si le pays est européen."""
75
  if not pays:
76
  return False
77
- pays_low = pays.lower().strip()
78
- if pays_low in config.EUROPEAN_COUNTRIES_FR:
79
  return True
80
- pays_iso = config.PAYS_FR_TO_ISO.get(pays_low, "").upper()
81
  return pays_iso in config.EUROPEAN_COUNTRIES_ISO
82
 
83
 
@@ -85,7 +96,7 @@ def _get_country_iso(pays: Optional[str]) -> Optional[str]:
85
  """Convertit un nom de pays FR en code ISO."""
86
  if not pays:
87
  return None
88
- return config.PAYS_FR_TO_ISO.get(pays.lower().strip())
89
 
90
 
91
  def _is_name_match(matiere: str, intrant_name: str) -> bool:
@@ -393,8 +404,7 @@ def _resolve_node_9(matiere: str, pays_production: str, result: CarbonResult) ->
393
  if is_eu:
394
  result.actions_appliquees.append("2. Pays européen → Recherche Mix Européen (RER) dans GFLI")
395
  rer = llm_service.smart_search_gfli(matiere, country_iso="RER")
396
- # Bloquer les résultats avec RER/GLO dans le nom (on veut un pays réel, pas l'identifiant)
397
- if rer and ("RER" not in rer["nom_intrant"].upper() and "GLO" not in rer["nom_intrant"].upper()):
398
  val = rer["valeur_kg_co2_eq_par_tonne"]
399
  result.impact_kg_co2_eq = val
400
  result.impact_tonne_co2_eq = val / 1000.0
@@ -408,8 +418,7 @@ def _resolve_node_9(matiere: str, pays_production: str, result: CarbonResult) ->
408
  else:
409
  result.actions_appliquees.append("2. Pays hors Europe → Recherche Mix Monde (GLO) dans GFLI")
410
  glo = llm_service.smart_search_gfli(matiere, country_iso="GLO")
411
- # Bloquer les résultats avec RER/GLO dans le nom
412
- if glo and ("RER" not in glo["nom_intrant"].upper() and "GLO" not in glo["nom_intrant"].upper()):
413
  val = glo["valeur_kg_co2_eq_par_tonne"]
414
  result.impact_kg_co2_eq = val
415
  result.impact_tonne_co2_eq = val / 1000.0
@@ -619,8 +628,7 @@ def _resolve_node_11(matiere: str, result: CarbonResult) -> CarbonResult:
619
  # Étape 2 : RER
620
  result.actions_appliquees.append("2. Impact process non connu → Recherche Mix Européen (RER) dans GFLI")
621
  rer = llm_service.smart_search_gfli(matiere, country_iso="RER")
622
- # Bloquer les résultats avec RER/GLO dans le nom
623
- if rer and ("RER" not in rer["nom_intrant"].upper() and "GLO" not in rer["nom_intrant"].upper()):
624
  val = rer["valeur_kg_co2_eq_par_tonne"]
625
  result.impact_kg_co2_eq = val
626
  result.impact_tonne_co2_eq = val / 1000.0
@@ -749,8 +757,7 @@ def _resolve_node_12(matiere: str, pays_transformation: str, result: CarbonResul
749
  result.actions_appliquees.append("2. Pays hors Europe → Recherche Mix Monde (GLO)")
750
  fallback = llm_service.smart_search_gfli(matiere, country_iso="GLO")
751
 
752
- # Bloquer les résultats avec RER/GLO dans le nom
753
- if fallback and ("RER" not in fallback["nom_intrant"].upper() and "GLO" not in fallback["nom_intrant"].upper()):
754
  val = fallback["valeur_kg_co2_eq_par_tonne"]
755
  result.impact_kg_co2_eq = val
756
  result.impact_tonne_co2_eq = val / 1000.0
@@ -945,8 +952,7 @@ def _resolve_soja_node_4(matiere: str, pays_production: str, result: CarbonResul
945
  result.actions_appliquees.append(f"3. Recherche 'soybeans' dans GFLI mix {mix_label}")
946
  for term in ["soybeans", "soybean"]:
947
  gfli = llm_service.smart_search_gfli(term, country_iso=mix_label)
948
- # Bloquer les résultats avec RER/GLO dans le nom
949
- if gfli and ("RER" not in gfli["nom_intrant"].upper() and "GLO" not in gfli["nom_intrant"].upper()):
950
  result = _apply_gfli_result(gfli, result)
951
  result.actions_appliquees.append(f" → Trouvé dans GFLI ({mix_label}) : {gfli['nom_intrant']}")
952
  return result
@@ -996,8 +1002,7 @@ def _resolve_soja_node_5(matiere: str, pays_production: str, pays_transformation
996
  mix_label = "RER" if is_eu else "GLO"
997
  result.actions_appliquees.append(f"3. Recherche dérivé soja dans GFLI mix {mix_label}")
998
  gfli = llm_service.smart_search_gfli(matiere, country_iso=mix_label)
999
- # Bloquer les résultats avec RER/GLO dans le nom (on veut un pays réel, pas l'identifiant)
1000
- if gfli and ("RER" not in gfli["nom_intrant"].upper() and "GLO" not in gfli["nom_intrant"].upper()):
1001
  result = _apply_gfli_result(gfli, result)
1002
  result.actions_appliquees.append(f" → Trouvé dans GFLI ({mix_label}) : {gfli['nom_intrant']}")
1003
  return result
@@ -1105,8 +1110,7 @@ def _resolve_soja_node_8(matiere: str, pays_transformation: str, result: CarbonR
1105
  mix_label = "RER" if is_eu else "GLO"
1106
  result.actions_appliquees.append(f"3. Recherche dérivé soja dans GFLI mix {mix_label}")
1107
  gfli = llm_service.smart_search_gfli(matiere, country_iso=mix_label)
1108
- # Bloquer les résultats avec RER/GLO dans le nom
1109
- if gfli and ("RER" not in gfli["nom_intrant"].upper() and "GLO" not in gfli["nom_intrant"].upper()):
1110
  result = _apply_gfli_result(gfli, result)
1111
  result.actions_appliquees.append(f" → Trouvé dans GFLI ({mix_label}) : {gfli['nom_intrant']}")
1112
  return result
@@ -1315,8 +1319,7 @@ def _resolve_mineral_node_4(matiere: str, pays_production: str, result: CarbonRe
1315
  mix_label = "RER" if is_eu else "GLO"
1316
  result.actions_appliquees.append(f"3. Recherche dans GFLI mix {mix_label}")
1317
  gfli = llm_service.smart_search_gfli(matiere, country_iso=mix_label)
1318
- # Bloquer les résultats avec RER/GLO dans le nom
1319
- if gfli and ("RER" not in gfli["nom_intrant"].upper() and "GLO" not in gfli["nom_intrant"].upper()):
1320
  result = _apply_gfli_result(gfli, result)
1321
  result.actions_appliquees.append(f" → Trouvé dans GFLI ({mix_label}) : {gfli['nom_intrant']}")
1322
  return result
@@ -1344,8 +1347,7 @@ def _resolve_mineral_node_4(matiere: str, pays_production: str, result: CarbonRe
1344
  if mix_label != "GLO":
1345
  result.actions_appliquees.append("5. Recherche dans GFLI mix GLO")
1346
  gfli = llm_service.smart_search_gfli(matiere, country_iso="GLO")
1347
- # Bloquer les résultats avec RER/GLO dans le nom
1348
- if gfli and ("RER" not in gfli["nom_intrant"].upper() and "GLO" not in gfli["nom_intrant"].upper()):
1349
  result = _apply_gfli_result(gfli, result)
1350
  result.actions_appliquees.append(f" → Trouvé dans GFLI (GLO) : {gfli['nom_intrant']}")
1351
  return result
 
63
  erreur: Optional[str] = None
64
 
65
 
66
+ def _normalize_country_name(pays: Optional[str]) -> str:
67
+ """Normalise un nom de pays : minuscule, strip, espaces → tirets.
68
+
69
+ Ex: 'Pays Bas' → 'pays-bas', 'Etats Unis' → 'etats-unis'
70
+ """
71
+ if not pays:
72
+ return ""
73
+ return pays.lower().strip().replace(" ", "-")
74
+
75
+
76
  def _is_france(pays: Optional[str]) -> bool:
77
  """Vérifie si le pays est la France."""
78
  if not pays:
79
  return False
80
+ n = _normalize_country_name(pays)
81
+ return n in ("france", "fr")
82
 
83
 
84
  def _is_european(pays: Optional[str]) -> bool:
85
  """Vérifie si le pays est européen."""
86
  if not pays:
87
  return False
88
+ n = _normalize_country_name(pays)
89
+ if n in config.EUROPEAN_COUNTRIES_FR:
90
  return True
91
+ pays_iso = config.PAYS_FR_TO_ISO.get(n, "").upper()
92
  return pays_iso in config.EUROPEAN_COUNTRIES_ISO
93
 
94
 
 
96
  """Convertit un nom de pays FR en code ISO."""
97
  if not pays:
98
  return None
99
+ return config.PAYS_FR_TO_ISO.get(_normalize_country_name(pays))
100
 
101
 
102
  def _is_name_match(matiere: str, intrant_name: str) -> bool:
 
404
  if is_eu:
405
  result.actions_appliquees.append("2. Pays européen → Recherche Mix Européen (RER) dans GFLI")
406
  rer = llm_service.smart_search_gfli(matiere, country_iso="RER")
407
+ if rer:
 
408
  val = rer["valeur_kg_co2_eq_par_tonne"]
409
  result.impact_kg_co2_eq = val
410
  result.impact_tonne_co2_eq = val / 1000.0
 
418
  else:
419
  result.actions_appliquees.append("2. Pays hors Europe → Recherche Mix Monde (GLO) dans GFLI")
420
  glo = llm_service.smart_search_gfli(matiere, country_iso="GLO")
421
+ if glo:
 
422
  val = glo["valeur_kg_co2_eq_par_tonne"]
423
  result.impact_kg_co2_eq = val
424
  result.impact_tonne_co2_eq = val / 1000.0
 
628
  # Étape 2 : RER
629
  result.actions_appliquees.append("2. Impact process non connu → Recherche Mix Européen (RER) dans GFLI")
630
  rer = llm_service.smart_search_gfli(matiere, country_iso="RER")
631
+ if rer:
 
632
  val = rer["valeur_kg_co2_eq_par_tonne"]
633
  result.impact_kg_co2_eq = val
634
  result.impact_tonne_co2_eq = val / 1000.0
 
757
  result.actions_appliquees.append("2. Pays hors Europe → Recherche Mix Monde (GLO)")
758
  fallback = llm_service.smart_search_gfli(matiere, country_iso="GLO")
759
 
760
+ if fallback:
 
761
  val = fallback["valeur_kg_co2_eq_par_tonne"]
762
  result.impact_kg_co2_eq = val
763
  result.impact_tonne_co2_eq = val / 1000.0
 
952
  result.actions_appliquees.append(f"3. Recherche 'soybeans' dans GFLI mix {mix_label}")
953
  for term in ["soybeans", "soybean"]:
954
  gfli = llm_service.smart_search_gfli(term, country_iso=mix_label)
955
+ if gfli:
 
956
  result = _apply_gfli_result(gfli, result)
957
  result.actions_appliquees.append(f" → Trouvé dans GFLI ({mix_label}) : {gfli['nom_intrant']}")
958
  return result
 
1002
  mix_label = "RER" if is_eu else "GLO"
1003
  result.actions_appliquees.append(f"3. Recherche dérivé soja dans GFLI mix {mix_label}")
1004
  gfli = llm_service.smart_search_gfli(matiere, country_iso=mix_label)
1005
+ if gfli:
 
1006
  result = _apply_gfli_result(gfli, result)
1007
  result.actions_appliquees.append(f" → Trouvé dans GFLI ({mix_label}) : {gfli['nom_intrant']}")
1008
  return result
 
1110
  mix_label = "RER" if is_eu else "GLO"
1111
  result.actions_appliquees.append(f"3. Recherche dérivé soja dans GFLI mix {mix_label}")
1112
  gfli = llm_service.smart_search_gfli(matiere, country_iso=mix_label)
1113
+ if gfli:
 
1114
  result = _apply_gfli_result(gfli, result)
1115
  result.actions_appliquees.append(f" → Trouvé dans GFLI ({mix_label}) : {gfli['nom_intrant']}")
1116
  return result
 
1319
  mix_label = "RER" if is_eu else "GLO"
1320
  result.actions_appliquees.append(f"3. Recherche dans GFLI mix {mix_label}")
1321
  gfli = llm_service.smart_search_gfli(matiere, country_iso=mix_label)
1322
+ if gfli:
 
1323
  result = _apply_gfli_result(gfli, result)
1324
  result.actions_appliquees.append(f" → Trouvé dans GFLI ({mix_label}) : {gfli['nom_intrant']}")
1325
  return result
 
1347
  if mix_label != "GLO":
1348
  result.actions_appliquees.append("5. Recherche dans GFLI mix GLO")
1349
  gfli = llm_service.smart_search_gfli(matiere, country_iso="GLO")
1350
+ if gfli:
 
1351
  result = _apply_gfli_result(gfli, result)
1352
  result.actions_appliquees.append(f" → Trouvé dans GFLI (GLO) : {gfli['nom_intrant']}")
1353
  return result