Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

taxonomy: adding a new feature in the API to compute the Ecobalyse score #11196

Merged
merged 138 commits into from
Feb 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
138 commits
Select commit Hold shift + click to select a range
44cf545
taxonomy: a new function assign_property_to_ingredients has been adde…
very-smartin Oct 9, 2024
41f3fd1
Merge branch 'main' into ecobalyse
very-smartin Oct 10, 2024
b5ab63e
updated tests
stephanegigandet Oct 11, 2024
49c07ef
lint
stephanegigandet Oct 11, 2024
e4d6e54
Merge branch 'main' into ecobalyse
very-smartin Oct 11, 2024
9b29b75
Merge branch 'main' into ecobalyse
very-smartin Oct 11, 2024
a606d32
Merge branch 'main' into ecobalyse
very-smartin Oct 14, 2024
98560d5
taxonomy: a new key has been added in country.txt in order to know if…
very-smartin Oct 21, 2024
ebb3add
Erratum in MakeFile
very-smartin Oct 21, 2024
9b2741b
ecobalyse: a boolean has been added in the country taxonomy for europ…
very-smartin Oct 24, 2024
2458c0c
ecobalyse: a boolean has been added in the country taxonomy for europ…
very-smartin Oct 24, 2024
8d449e7
Merge branch 'main' into ecobalyse
very-smartin Oct 24, 2024
fed86f1
test: Update tests results
Oct 24, 2024
150348f
chore: Linting changes
Oct 25, 2024
34ad737
Merge branch 'main' into ecobalyse
very-smartin Oct 25, 2024
f1803f6
taxonomy: changing the function assign_property_to_ingredient
very-smartin Oct 29, 2024
1273fd3
taxonomy: resolving conflicts
very-smartin Oct 29, 2024
43448e0
taxonomy: changing the function assign_property_to_ingredient
very-smartin Oct 29, 2024
7302c37
Merge branch 'main' into ecobalyse
very-smartin Oct 29, 2024
2206fea
taxonomy; new version of the get_missing_ecobalyse_ids function
very-smartin Oct 30, 2024
678a2a7
Merge branch 'main' into ecobalyse
very-smartin Oct 30, 2024
28d0a36
Merge branch 'main' into ecobalyse
very-smartin Oct 31, 2024
7034337
taxonomy: adressing bugsin Ingredients.pm
very-smartin Oct 31, 2024
ca5d35f
Merge branch 'main' into ecobalyse
very-smartin Oct 31, 2024
96b0cfd
tackling (again) Perl errors
very-smartin Nov 4, 2024
d5ae6fa
Merge branch 'main' into ecobalyse
very-smartin Nov 4, 2024
995ade1
tackling (again) Perl errors
very-smartin Nov 4, 2024
97695e3
Merge branch 'ecobalyse' of https://github.com/openfoodfacts/openfood…
very-smartin Nov 4, 2024
0828916
tackling (again) Perl errors
very-smartin Nov 4, 2024
5e5a8e2
chore: Linting changes
Nov 4, 2024
be2e361
Merge branch 'main' into ecobalyse
very-smartin Nov 12, 2024
1b69d54
Correcting tests/unit for ecobalyse
very-smartin Nov 12, 2024
bea6622
Merge branch 'main' into ecobalyse
very-smartin Nov 12, 2024
d9e75a1
Merge branch 'main' into ecobalyse
very-smartin Nov 18, 2024
ab65eff
Changing Ingredients.pm
very-smartin Nov 18, 2024
00dd1db
Squashing modifications : ecobalyse codes extraction + tacking issues on
very-smartin Nov 18, 2024
cf501fc
Updating ecobalyse branch
very-smartin Dec 9, 2024
1733845
taxonomy: taking into account the ingredient origin for ecobalyse codes
very-smartin Dec 9, 2024
2b4257b
taxonomy : new function created to retrieve the geographical area
very-smartin Dec 10, 2024
fa5865b
Merge branch 'main' into ecobalyse
very-smartin Dec 10, 2024
ced253b
taxonomy: corrections on retrieving the corresponding ecobalyse code …
very-smartin Dec 10, 2024
d9fc132
taxonomy: minor correction
very-smartin Dec 10, 2024
0a52271
Merge branch 'main' into ecobalyse
very-smartin Dec 10, 2024
1559266
Merge branch 'main' into ecobalyse
very-smartin Dec 10, 2024
04a3586
Tackling linting issue
very-smartin Dec 10, 2024
56f9f76
Merge branch 'main' into ecobalyse
very-smartin Dec 10, 2024
8167a74
Tackling linting issue
very-smartin Dec 10, 2024
7b6417c
Merge branch 'main' into ecobalyse
very-smartin Dec 10, 2024
6c9a322
chore: Linting changes
Dec 11, 2024
755451e
Merge branch 'main' into ecobalyse
very-smartin Dec 11, 2024
eb085fa
Tackling unit test issues
very-smartin Dec 11, 2024
46e5369
Merge branch 'ecobalyse' of https://github.com/openfoodfacts/openfood…
very-smartin Dec 11, 2024
28fd034
Tackling unit test issues : suite
very-smartin Dec 11, 2024
1c5d7af
Adding a new function in the API to compute the Ecobalyse score
very-smartin Jan 6, 2025
303549f
Tackling merging issues
very-smartin Jan 6, 2025
c3de8cd
Adding new steps in the new function
very-smartin Jan 6, 2025
fa20ff0
Changing the structure for the futur code
very-smartin Jan 7, 2025
c0af057
Merge branch 'main' into ecobalyse
very-smartin Jan 7, 2025
c35d5df
Adding new tests
very-smartin Jan 7, 2025
cecc8da
Tackling test issues
very-smartin Jan 7, 2025
fabb72f
Merge branch 'main' into ecobalyse
very-smartin Jan 7, 2025
0ccc2f3
Tackling test issues again
very-smartin Jan 7, 2025
1644f1e
Merge branch 'main' into ecobalyse
very-smartin Jan 8, 2025
45e93ef
Tackling minor errors
very-smartin Jan 8, 2025
6f677c6
New tests added + addressing linting issues
very-smartin Jan 8, 2025
c6c6217
Making API requests !
very-smartin Jan 8, 2025
c79b5d5
Merge branch 'main' into ecobalyse
very-smartin Jan 8, 2025
9adece1
Merge branch 'main' into ecobalyse
very-smartin Jan 8, 2025
b6eed1a
Tackling test issues
very-smartin Jan 8, 2025
fcaffe9
Tackling small issues
very-smartin Jan 8, 2025
b5f7a81
Merge branch 'main' into ecobalyse
very-smartin Jan 9, 2025
a5f4f1c
Tackling comments issues + tests
very-smartin Jan 9, 2025
fba5f73
Tackling tests issues
very-smartin Jan 9, 2025
e415a5a
Tackling tests issues
very-smartin Jan 9, 2025
e49d3c9
Minor changes
very-smartin Jan 9, 2025
761395f
Merge branch 'main' into ecobalyse
very-smartin Jan 9, 2025
e117282
Minor changes
very-smartin Jan 9, 2025
571adee
Tackling int tests issues
very-smartin Jan 13, 2025
21e017b
Merge branch 'main' into ecobalyse
very-smartin Jan 13, 2025
416712d
Merge branch 'main' into ecobalyse
very-smartin Jan 15, 2025
01de6a5
Merge branch 'main' into ecobalyse
very-smartin Jan 16, 2025
4ecc600
Merge branch 'main' into ecobalyse
very-smartin Jan 20, 2025
c273be2
Merge branch 'main' into ecobalyse
very-smartin Jan 20, 2025
81f4a9f
Tackling linting issues
very-smartin Jan 20, 2025
387931e
Merge branch 'ecobalyse' of https://github.com/openfoodfacts/openfood…
very-smartin Jan 20, 2025
6ffc01c
Tackling linting issues
very-smartin Jan 20, 2025
77a27e9
chore: Linting changes
Jan 20, 2025
df27823
Tackling PerlCritic issues
very-smartin Jan 20, 2025
2a87d9e
Merge branch 'ecobalyse' of https://github.com/openfoodfacts/openfood…
very-smartin Jan 20, 2025
3d46e5c
Tackling PerlCritic issues
very-smartin Jan 20, 2025
d1552fe
Tackling lint issues
very-smartin Jan 20, 2025
cdefe8d
Merge branch 'main' into ecobalyse
very-smartin Jan 20, 2025
3681cee
chore: Linting changes
Jan 20, 2025
85ee330
Tackling perl issues
very-smartin Jan 20, 2025
2205876
Tackling perl issues
very-smartin Jan 20, 2025
fc0294f
chore: Linting changes
Jan 20, 2025
dd8125e
Merge branch 'main' into ecobalyse
very-smartin Jan 21, 2025
cc189aa
lint
very-smartin Jan 21, 2025
a81f3fe
New test
very-smartin Jan 21, 2025
cda1c8f
chore: Linting changes
Jan 21, 2025
47ce36b
Check perl issues
very-smartin Jan 21, 2025
7757f1b
Merge branch 'ecobalyse' of https://github.com/openfoodfacts/openfood…
very-smartin Jan 21, 2025
4bd73f7
Perl issues
very-smartin Jan 21, 2025
e6b1ded
chore: Linting changes
Jan 21, 2025
3926495
Merge branch 'main' into ecobalyse
very-smartin Jan 27, 2025
e7bc079
linting
very-smartin Jan 27, 2025
072f867
Setting up correctly environmental_score_ecobalyse.t
very-smartin Jan 27, 2025
5b7318f
Merge branch 'main' into ecobalyse
very-smartin Jan 27, 2025
995a78e
chore: Linting changes
Jan 27, 2025
43033a8
Merge branch 'main' into ecobalyse
very-smartin Jan 28, 2025
839a67e
Tackling import issues
very-smartin Feb 3, 2025
d69aa2e
call ecobalyse
stephanegigandet Feb 3, 2025
913dec6
update tests
stephanegigandet Feb 3, 2025
6e902c3
Merge branch 'main' into ecobalyse
very-smartin Feb 4, 2025
d8baf96
Merge branch 'main' into ecobalyse
very-smartin Feb 6, 2025
d7d816e
Tackling test issues
very-smartin Feb 6, 2025
e0baa9b
Changing test
very-smartin Feb 10, 2025
515586c
Merge branch 'main' into ecobalyse
very-smartin Feb 10, 2025
3e86626
Trying new tests
very-smartin Feb 10, 2025
9a0b091
Merge branch 'main' into ecobalyse
very-smartin Feb 10, 2025
66b0a29
update tests
stephanegigandet Feb 10, 2025
6075f81
fix: ecobalyse service and tests (#11352)
stephanegigandet Feb 10, 2025
6e98ac5
fix: ecobalyse call (#11353)
stephanegigandet Feb 11, 2025
577135c
chore: Linting changes
Feb 11, 2025
a2ea5d9
fix: ecobalyse call and tests (#11359)
stephanegigandet Feb 12, 2025
ee36db3
Merge branch 'main' into ecobalyse
stephanegigandet Feb 12, 2025
0fbe341
remove old tests
stephanegigandet Feb 12, 2025
78615a6
Merge branch 'main' into ecobalyse
very-smartin Feb 12, 2025
3260a77
taxonomy: fix taxonomy build error: unexisting whole-bananas parent
stephanegigandet Feb 12, 2025
3defb59
Merge branch 'bananas-fix2' into ecobalyse
stephanegigandet Feb 12, 2025
471c052
fix ingredients
stephanegigandet Feb 12, 2025
c206d6a
taxonomy: updating ecobalyse codes
very-smartin Feb 12, 2025
902b5a9
More updates
very-smartin Feb 12, 2025
60c4941
call ecobalyse in test_ingredients_analysis.pl
stephanegigandet Feb 12, 2025
4257071
Merge branch 'ecobalyse_update' into ecobalyse
stephanegigandet Feb 12, 2025
c39df46
update tests
stephanegigandet Feb 12, 2025
6065dcc
merged main
stephanegigandet Feb 14, 2025
423e320
test: Update tests results
Feb 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions cgi/test_ingredients_analysis.pl
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
use ProductOpener::Ingredients
qw/clean_ingredients_text extract_additives_from_text extract_ingredients_from_text preparse_ingredients_text/;
use ProductOpener::Text qw/remove_tags_and_quote/;
use ProductOpener::EnvironmentalImpact qw/estimate_environmental_impact_service/;

use CGI qw/:cgi :form escapeHTML charset/;
use URI::Escape::XS;
Expand Down Expand Up @@ -85,6 +86,16 @@

my $json = JSON::MaybeXS->new->pretty->encode($product_ref->{ingredients});
$template_data_ref->{json} = $json;

# Environmental impact
my $errors_ref = [];
estimate_environmental_impact_service($product_ref, {}, $errors_ref);

$template_data_ref->{ecobalyse_request_json}
= JSON::MaybeXS->new->pretty->encode($product_ref->{environmental_impact}{ecobalyse_request} || {});
# If there was an error, we have ecobalyse_response, otherwise we have ecobalyse_response_data
$template_data_ref->{ecobalyse_response_json}
= JSON::MaybeXS->new->pretty->encode($product_ref->{environmental_impact} || {});
}

process_template('web/pages/test_ingredients/test_ingredients_analysis.tt.html', $template_data_ref, \$html)
Expand Down
3 changes: 3 additions & 0 deletions lib/ProductOpener/APIProductServices.pm
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ Currently implemented services:
- extend_ingredients : extend the ingredients object with additional information
- estimate_ingredients_percent : compute percent_min, percent_max, percent_estimate for each ingredient in the ingredients object
- analyze_ingredients : analyze the ingredients object and return a summary object
- estimate_environmental_cost_ingredients : estimate the environmental cost of a given product (see Ecobalyse)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the service should be estimate_environmental_impact, without speciffying ingredients: at first we will look only at ingredients, but maybe in the next iteration, we will also add the packaging data, and maybe some processing implied by the category (e.g. frozen vegetables: freezing).

cost -> I think it may be more generic to use "impact" instead of "cost"

So we could create a separate EnvironmentalImpact.pm module.


=head4 product

Expand Down Expand Up @@ -90,6 +91,7 @@ use ProductOpener::Users qw/:all/;
use ProductOpener::Lang qw/:all/;
use ProductOpener::Products qw/:all/;
use ProductOpener::API qw/add_error customize_response_for_product/;
use ProductOpener::EnvironmentalImpact;

use Encode;

Expand All @@ -116,6 +118,7 @@ my %service_functions = (
extend_ingredients => \&ProductOpener::Ingredients::extend_ingredients_service,
estimate_ingredients_percent => \&ProductOpener::Ingredients::estimate_ingredients_percent_service,
analyze_ingredients => \&ProductOpener::Ingredients::analyze_ingredients_service,
estimate_environmental_impact => \&ProductOpener::EnvironmentalImpact::estimate_environmental_impact_service,
determine_food_contact_of_packaging_components =>
\&ProductOpener::PackagingFoodContact::determine_food_contact_of_packaging_components_service,
);
Expand Down
4 changes: 4 additions & 0 deletions lib/ProductOpener/Attributes.pm
Original file line number Diff line number Diff line change
Expand Up @@ -1206,6 +1206,7 @@ sub compute_attribute_nutrient_level ($product_ref, $target_lc, $level, $nid) {
lang_in_other_lc($target_lc, "unknown_quantity")
);
$attribute_ref->{missing} = lang_in_other_lc($target_lc, "missing_nutrition_facts");
$attribute_ref->{panel_id} = "nutrition_facts_table";
}
}
else {
Expand Down Expand Up @@ -1262,6 +1263,9 @@ sub compute_attribute_nutrient_level ($product_ref, $target_lc, $level, $nid) {
$attribute_ref->{description_short}
= sprintf(lang_in_other_lc($target_lc, 'g_per_100g'), (sprintf('%.2e', $value) + 0.0));
}

$attribute_ref->{panel_id} = "nutrient_level_" . $nid;
$attribute_ref->{panel_id} =~ s/-/_/g;
}
}
}
Expand Down
222 changes: 222 additions & 0 deletions lib/ProductOpener/EnvironmentalImpact.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
# This file is part of Product Opener.
#
# Product Opener
# Copyright (C) 2011-2023 Association Open Food Facts
# Contact: [email protected]
# Address: 21 rue des Iles, 94100 Saint-Maur des Fossés, France
#
# Product Opener is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

=encoding UTF-8

=head1 NAME

ProductOpener::EnvironmentalImpact - process and analyze products

=head1 SYNOPSIS

C<ProductOpener::EnvironmentalImpact> processes products to compute
their environmental impact (see french environmental labeling Ecobalyse).

use ProductOpener::EnvironmentalImpact qw/:all/;

[..]

estimate_environmental_impact($product_ref);

=head1 DESCRIPTION

[..]

=cut

package ProductOpener::EnvironmentalImpact;

use ProductOpener::PerlStandards;
use Exporter qw< import >;
use LWP::UserAgent;
use HTTP::Request::Common;
use JSON;
use Encode qw(decode_utf8 encode_utf8);

BEGIN {
use vars qw(@ISA @EXPORT_OK %EXPORT_TAGS);
@EXPORT_OK = qw(

&estimate_environmental_impact_service

); # symbols to export on request
%EXPORT_TAGS = (all => [@EXPORT_OK]);
}

use vars @EXPORT_OK;

use Log::Any '$log', default_adapter => 'Stderr';

=head1 FUNCTIONS

=head2 estimate_environmental_impact_service ( $product_ref, $updated_product_fields_ref, $errors_ref )

Compute the environmental impact of a given product (see the french environmental environmental labeling Ecobalyse).

This function is a product service that can be run through ProductOpener::ApiProductServices

=head3 Arguments

=head4 $product_ref

product object reference

=head4 $updated_product_fields_ref

reference to a hash of product fields that have been created or updated

=head4 $errors_ref

reference to an array of error messages

=cut

sub estimate_environmental_impact_service ($product_ref, $updated_product_fields_ref, $errors_ref) {

# $updated_product_fields_ref, $errors_ref sont des outputs : chaque service
# dit quels champs sont modifiés
# Ici on en ajoute un : "environmental_impact"

# If undefined ingredients, do nothing
return if not defined $product_ref->{ingredients};

# indicate that the service is modifying the "ingredients" structure
$updated_product_fields_ref->{environmental_impact} = 1;
$product_ref->{environmental_impact} = 0;

# Initialisation of the payload structure
my $payload = {
ingredients => [],
transform => {
"id" => "7541cf94-1d4d-4d1c-99e3-a9d5be0e7569",
"mass" => 545
},
packaging => [],
distribution => "ambient",
preparation => ["refrigeration"]
};

# Estimating the environmental impact
foreach my $ingredient_ref (@{$product_ref->{ingredients}}) {
# TODO: when we don't have an ecobalyse_code or ecobalyse_proxy_code,
# we can ignore the ingredient, but we need to record the quantity of unrecognized ingredients
next unless defined $ingredient_ref->{id} && defined $ingredient_ref->{percent_estimate};
push @{$payload->{ingredients}},
{
id => $ingredient_ref->{ecobalyse_code} || $ingredient_ref->{ecobalyse_proxy_code},
mass => $ingredient_ref->{percent_estimate}
};
}

# Adding a transformation
if (defined $product_ref->{transform}) {
$payload->{transform} = {
id => $product_ref->{transform}->{id},
mass => $product_ref->{transform}->{mass}
}
if defined $product_ref->{transform}->{id} && defined $product_ref->{transform}->{mass};
}

# Adding a packaging
if (defined $product_ref->{packaging}) {
foreach my $packaging_ref (@{$product_ref->{packaging}}) {
next unless defined $packaging_ref->{id} && defined $packaging_ref->{mass};
push @{$payload->{packaging}},
{
id => $packaging_ref->{id},
mass => $packaging_ref->{mass}
};
}
}

# API URL
my $url_recipe = "https://staging-ecobalyse.incubateur.net/api/food";

# Create a UserAgent object to make the API request
my $ua = LWP::UserAgent->new();
$ua->timeout(5);

# Prepare the POST request with the payload
my $request = POST $url_recipe, $payload;
$request->header('content-type' => 'application/json');
$request->content(decode_utf8(encode_json($payload)));

# Debug information for the request
$log->debug("send_event request", {endpoint => $url_recipe, payload => $payload}) if $log->is_debug();

$product_ref->{environmental_impact} = {ecobalyse_request => {url => $url_recipe, data => $payload}};

# Send the request and get the response
my $response = $ua->request($request);

# Parse the JSON response
my $response_content = $response->decoded_content;
my $response_data = $response_content;
# if the response is JSON, decode it
eval {$response_data = decode_json($response_content);};

$product_ref->{environmental_impact}{ecobalyse_response} = $response_data;

# Handle the response based on success or failure
if ($response->is_success) {

# Access the specific "ecs" value
if (exists $response_data->{results}{total}{ecs}) {
my $ecs_value = $response_data->{results}{total}{ecs};
# If 'ecs' is defined, store it in the product reference
if (defined $ecs_value) {
$product_ref->{environmental_impact}{ecs} = $ecs_value;
}
}
}
else {
# If the request failed, log the error
$log->error("send_event request failed",
{endpoint => $url_recipe, payload => $payload, response => $response_content})
if $log->is_error();
# Add an error message to the errors array
$product_ref->{environmental_impact}{ecobalyse_response} = $response_data;

push @{$errors_ref},
{
message => {id => "error_response_from_ecobalyse"},
field => {
id => "ecobalyse_response",
value => $response_content,
},
impact => {id => "failure"},
service => {id => "estimate_environmental_impact_service"},
};
}

# If necessary, return error as well
# (number of unattributed ingredients,
# percentage of unattributed mass, etc...)

# add_error
# add_warning

# $product_ref->{environmental_impact} = 5;

return;
}

1;

Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
</form>

[% IF action == 'process' %]
<h3>Ingredients parsing, % estimates and analysis</h3>
<h4>Preparsed ingredients text</h4>
<p>[% preparsed_ingredients_text %]</p>
[% display_ingredients_analysis %]
Expand All @@ -22,6 +23,16 @@ <h4>JSON</h4>
<pre>
[% json %]
</pre>

<h3>Environmental impact</h3>
<h4>Ecobalyse request</h4>
<pre>
[% ecobalyse_request_json %]
</pre>
<h4>Ecobalyse response</h4>
<pre>
[% ecobalyse_response_json %]
</pre>
[% END %]

<!-- end templates/[% template.name %] -->
Loading
Loading