Gap Filling Modules (GFM)
Les Gap Filling Modules sont les éléments constitutifs du moteur de calcul EOS. Chaque module est une unité spécialisée et autonome qui gère un aspect spécifique du calcul d'incidence environnementale.
Que sont les Gap Filling Modules ?
Dans le monde réel, les données sur les produits alimentaires sont souvent incompletes. Un produit peut avoir :
- Un nom mais pas de liste d'ingrédients
- Des ingrédients mais pas d'informations sur l'origine
- Une origine mais pas de détails sur le transport
- Des données nutritionnelles partielles
Les GFM resolvent ce problème en comblant automatiquement les lacunes dans les données produit à l'aide de modèles scientifiques, de bases de données et de valeurs par défaut intelligentes.
Le concept GFM
Chaque GFM se compose de :
- Logique de planification - Determine si le module est pertinent pour un noeud donné
- Vérification de disponibilité - Vérifie que toutes les dépendances sont satisfaites
- Exécution - La logique de calcul qui comble les lacunes et met à jour le graphe
Modules disponibles
EOS comprend 28 GFM spécialisés organisés par fonction :
Modules de correspondance
Font correspondre les noms de produits et ingrédients aux entrées de la base de données :
| Module | Objectif |
|---|---|
match_product_name_gfm | Fait correspondre les noms de produits aux entrées de la base de données |
attach_food_tags_gfm | Attache les étiquettes de classification alimentaire |
link_term_to_activity_node_gfm | Lie les termes aux activités ACV |
link_food_categories_gfm | Attribue les catégories alimentaires |
Modules de localisation
Gèrent les données géographiques et d'origine :
| Module | Objectif |
|---|---|
origin_gfm | Determine l'origine du produit |
location_gfm | Gestion de la localisation géographique |
transportation_decision_gfm | Determine les modes de transport |
transportation_mode_distance_gfm | Calcule les distances de transport |
Modules de cycle de vie
Modelisent la transformation et la chaîne d'approvisionnement :
| Module | Objectif |
|---|---|
processing_gfm | Incidences de la transformation alimentaire |
greenhouse_gfm | Calculs des gaz à effet de serre |
conservation_gfm | Stockage et conservation |
perishability_gfm | Durée de conservation et facteurs de perte |
Modules d'évaluation de l'incidence
Calculent les métriques environnementales :
| Module | Objectif |
|---|---|
impact_assessment_gfm | Agrege les calculs d'incidence |
water_scarcity_gfm | Calcul de l'empreinte hydrique |
rainforest_gfm | Incidence sur la déforestation |
vitascore_gfm | Score nutritionnel |
Modules d'agrégation
Combinent les résultats entre ingrédients :
| Module | Objectif |
|---|---|
aggregation_gfm | Agrege les incidences des ingrédients |
ingredient_splitter_gfm | Decompose les ingrédients composés |
ingredient_amount_estimator_gfm | Estime les quantités d'ingrédients |
Architecture des modules
Chaque GFM suit le patron Factory/Worker :
# Factory - initialise une fois par service, gere les workers
class ExampleGapFillingFactory(AbstractGapFillingFactory):
def __init__(self, postgres_db, service_provider):
super().__init__(postgres_db, service_provider)
self.cache = {} # Cache persistant entre les calculs
async def init_cache(self):
# Charger les donnees requises en memoire
pass
def spawn_worker(self, node):
return ExampleGapFillingWorker(node)
# Worker - cree par noeud, execute le calcul
class ExampleGapFillingWorker(AbstractGapFillingWorker):
def should_be_scheduled(self) -> bool:
# Ce GFM est-il pertinent pour ce noeud ?
return self.node.needs_processing()
def can_run_now(self) -> GapFillingWorkerStatusEnum:
# Les dependances sont-elles satisfaites ?
if self.node.has_required_data():
return GapFillingWorkerStatusEnum.ready
return GapFillingWorkerStatusEnum.reschedule
async def run(self, calc_graph):
# Executer la logique de comblement des lacunes
result = await self.calculate()
self.node.set_property("result", result)
Pourquoi Factory/Worker ?
| Avantage | Description |
|---|---|
| Isolation | Chaque calcul s'execute dans sa propre instance de worker |
| Mise en cache | Factory maintient les caches entre les calculs |
| Évolutivité | Les workers peuvent être distribues |
| Tests | Les workers peuvent être testes indépendamment |
Orchestration
L'orchestrateur coordonne l'exécution des GFM :
Boucle de planification
- Ajout de noeud - Lorsque des noeuds sont ajoutés au CalcGraph, l'orchestrateur crée des workers
- Vérification de planification - Le
should_be_scheduled()de chaque worker est appele - Vérification de disponibilité -
can_run_now()vérifie les dépendances - Exécution - Les workers prets s'executent de manière asynchrone
- Mises à jour du graphe - Les résultats sont ecrits dans les propriétés du noeud
- Propagation - De nouveaux noeuds peuvent declencher des GFM supplémentaires
Dépendances des modules
Les modules dépendent des sorties d'autres modules :
Les dépendances sont résolues automatiquement via la boucle de planification de l'orchestrateur.
Gestion de l'état
Les GFM suivent leur état d'exécution par noeud :
# Etat par noeud stocke dans GfmStateProp (worker_states)
# Les valeurs proviennent de NodeGfmStateEnum : "S" (planifie), "F" (termine), "C" (annule)
gfm_state = {
"MatchProductNameGapFillingWorker": "F", # termine
"OriginGapFillingWorker": "F", # termine
"GreenhouseGapFillingWorker": "S", # planifie (en cours)
"ImpactAssessmentGapFillingWorker": "S" # planifie (en attente)
}
Valeurs d'état
L'état du GFM est suivi à l'aide de NodeGfmStateEnum :
| État | Code | Description |
|---|---|---|
scheduled | S | Le GFM est planifié pour s'exécuter sur ce noeud |
finished | F | Le GFM s'est terminé avec succes |
canceled | C | Le GFM a été annule (non applicable ou échec) |
Gestion des erreurs
Les GFM implementent une gestion gracieuse des erreurs :
async def run(self, calc_graph):
try:
result = await self.calculate()
self.node.set_property("result", result)
except Exception as e:
# Journaliser l'erreur avec contexte
logger.error("Echec du GFM",
gfm=self.__class__.__name__,
node_uid=self.node.uid,
error=str(e))
# Creer une DataError pour le suivi
error = DataError(
node_uid=self.node.uid,
gfm_name=self.__class__.__name__,
message=str(e),
classification=ErrorClassification.calculation_error
)
self.node.add_error(error)
Stratégie de repli
Lorsqu'un module échoue :
- Journaliser l'erreur - Journalisation structurée avec contexte
- Créer une DataError - Suivi pour le rapport
- Continuer le traitement - Les autres modules peuvent toujours s'exécuter
- Signaler l'incertitude - Marquer le résultat avec une confiance réduite
Prochaines étapes
- Fonctionnement des GFM - Mécanismes detailles
- Catalogue des modules - Tous les modules disponibles
- SDK GFM (bientot disponible) - Construire des modules personnalisés