Skip to content

Commit

Permalink
feat: knowledge panel to display the ingredients that make a product …
Browse files Browse the repository at this point in the history
…not vegan / vegetarian / palm oil free (#6420)

* small improvements to display ingredients analysis

* ingredients analysis knowledge panels

* display list of non vegan ingredients

* trigger API when fields parameter is added to product url

* ingredients analysis details in knowledge panels

* ingredients analysis details in knowledge panels

* new vegetarian icon

* new vegetarian icon

* extra field for debugging ingredients analysis

* Update lib/ProductOpener/Display.pm

Co-authored-by: Alex Garel <[email protected]>

* Update lib/ProductOpener/KnowledgePanels.pm

Co-authored-by: Alex Garel <[email protected]>

* suggestions from code review

* update tests

Co-authored-by: Alex Garel <[email protected]>
  • Loading branch information
stephanegigandet and alexgarel authored Feb 18, 2022
1 parent 1462f72 commit 27b7137
Show file tree
Hide file tree
Showing 35 changed files with 478 additions and 39 deletions.
9 changes: 8 additions & 1 deletion cgi/display.pl
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,14 @@
display_mission(\%request);
}
elsif (defined $request{product}) {
display_product(\%request);
# if we are passed the field parameter, make the request an API request
# this is so that we can easily add ?fields=something at the end of a product url
if (defined param("fields")) {
display_product_api(\%request);
}
else {
display_product(\%request);
}
}
elsif (defined $request{points}) {
display_points(\%request);
Expand Down
70 changes: 70 additions & 0 deletions icons/vegetarian.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
73 changes: 63 additions & 10 deletions lib/ProductOpener/Display.pm
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ BEGIN
&display_properties
&data_to_display_nutriscore_and_nutrient_levels
&data_to_display_ingredients_analysis
&count_products
&add_params_to_query
Expand Down Expand Up @@ -11019,23 +11020,33 @@ CSS
}


=head2 display_ingredients_analysis ( $product_ref )
=head2 data_to_display_ingredients_analysis ( $product_ref )
Generates HTML code with icons that show if the product is vegetarian, vegan and without palm oil.
Generates a data structure to display the results of ingredients analysis.
The resulting data structure can be passed to a template to generate HTML or the JSON data for a knowledge panel.
=head3 Arguments
=head4 Product reference $product_ref
=head3 Return values
Reference to a data structure with needed data to display.
=cut

sub display_ingredients_analysis($) {
sub data_to_display_ingredients_analysis($) {

my $product_ref = shift;

# Ingredient analysis
my $result_data_ref;

my $html = "";
# Populate the data templates needed to display the Nutri-Score and nutrient levels

if (defined $product_ref->{ingredients_analysis_tags}) {

my $template_data_ref = {
$result_data_ref = {
ingredients_analysis_tags => [],
};

Expand All @@ -11046,8 +11057,10 @@ sub display_ingredients_analysis($) {

if ($ingredients_analysis_tag =~ /palm/) {

# Icon
$icon = "palm-oil";

# Evaluation
if ($ingredients_analysis_tag =~ /-free$/) {
$evaluation = 'good';
}
Expand All @@ -11063,13 +11076,15 @@ sub display_ingredients_analysis($) {
}
else {

# Icon
if ($ingredients_analysis_tag =~ /vegan/) {
$icon = "leaf";
}
elsif ($ingredients_analysis_tag =~ /vegetarian/) {
$icon = "egg";
$icon = "vegetarian";
}

# Evaluation
if ($ingredients_analysis_tag =~ /^en:non-/) {
$evaluation = 'bad';
}
Expand All @@ -11084,19 +11099,57 @@ sub display_ingredients_analysis($) {
}
}

push @{$template_data_ref->{ingredients_analysis_tags}}, {
# Generate the translation string id for the list of ingredients we will display
my $ingredients_title_id;
if ($evaluation eq "unknown") {
$ingredients_title_id = "unrecognized_ingredients";
}
else {
# convert analysis tag to a translation string id
# eg. en:non-vegetarian property to non_vegetarian_ingredients translation string id
$ingredients_title_id = lc($ingredients_analysis_tag) . "_ingredients";
$ingredients_title_id =~ s/^en://;
$ingredients_title_id =~ s/-/_/g;
}

push @{$result_data_ref->{ingredients_analysis_tags}}, {
property => $ingredients_analysis_tag,
evaluation => $evaluation,
icon => $icon,
text => display_taxonomy_tag($lc, "ingredients_analysis", $ingredients_analysis_tag),
title => display_taxonomy_tag($lc, "ingredients_analysis", $ingredients_analysis_tag),
ingredients_title_id => $ingredients_title_id,
};
}
}

return $result_data_ref;
}


=head2 display_ingredients_analysis ( $product_ref )
Generates HTML code with icons that show if the product is vegetarian, vegan and without palm oil.
=cut

sub display_ingredients_analysis($) {

my $product_ref = shift;

# Ingredient analysis

my $html = "";

my $template_data_ref = data_to_display_ingredients_analysis($product_ref);

if (defined $template_data_ref) {
process_template('web/pages/product/includes/ingredients_analysis.tt.html', $template_data_ref, \$html) || return "template error: " . $tt->error();
}

return $html;
}


sub _format_comment {
my ($comment) = @_;

Expand All @@ -11107,7 +11160,7 @@ sub _format_comment {
$comment = q{};
}

$comment =~ s/\new image \d+( -)?//;
$comment =~ s/new image \d+( -)?//;

return $comment;
}
Expand Down
13 changes: 9 additions & 4 deletions lib/ProductOpener/Ingredients.pm
Original file line number Diff line number Diff line change
Expand Up @@ -2735,6 +2735,8 @@ sub analyze_ingredients($) {
if ($property =~ /^from_/) {

my $from_what = $';
my $from_what_with_dashes = $from_what;
$from_what_with_dashes =~ s/_/-/g;

# For properties like from_palm, one positive ingredient triggers a positive result for the whole product
# We assume that all the positive ingredients have been marked as yes or maybe in the taxonomy
Expand All @@ -2744,22 +2746,22 @@ sub analyze_ingredients($) {

if (defined $values{yes}) {
# One yes ingredient -> yes for the whole product
$property_value = "en:" . $from_what ; # en:palm-oil
$property_value = "en:" . $from_what_with_dashes ; # en:palm-oil
$ingredients_analysis_ref->{$property_value} = $values{yes};
}
elsif (defined $values{maybe}) {
# One maybe ingredient -> maybe for the whole product
$property_value = "en:may-contain-" . $from_what ; # en:may-contain-palm-oil
$property_value = "en:may-contain-" . $from_what_with_dashes ; # en:may-contain-palm-oil
$ingredients_analysis_ref->{$property_value} = $values{maybe};
}
elsif (defined $values{unknown_ingredients}) {
# Some ingredients were not recognized
$property_value = "en:" . $from_what . "-content-unknown"; # en:palm-oil-content-unknown
$property_value = "en:" . $from_what_with_dashes . "-content-unknown"; # en:palm-oil-content-unknown
$ingredients_analysis_ref->{$property_value} = $values{unknown_ingredients};
}
else {
# no yes, maybe or unknown ingredients
$property_value = "en:" . $from_what . "-free"; # en:palm-oil-free
$property_value = "en:" . $from_what_with_dashes . "-free"; # en:palm-oil-free
}
}
else {
Expand Down Expand Up @@ -2837,6 +2839,9 @@ sub analyze_ingredients($) {
}
}
}

# Uncomment the following line to add an extra field with more data for debugging purposes
#$product_ref->{ingredients_analysis_debug} = $ingredients_analysis_ref;
}


Expand Down
57 changes: 49 additions & 8 deletions lib/ProductOpener/KnowledgePanels.pm
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ sub create_panel_from_json_template ($$$$$$) {
# As it is a trailing comma inside a string, it's not a terrible issue, the string will be valid,
# but it will have an unneeded trailing comma.
# The group (\W) at the end is to avoid removing commas before an opening quote (e.g. for "field": true, "other_field": ..)
$panel_json =~ s/(?<!("|'|\]|\}|\d))\s*,\s*"(\W)/"$2/g;
$panel_json =~ s/(?<!("|'|\]|\}|\d))\s*,\s*"(\W)/"$2/sg;

# Remove trailing commas after the last element of a array or hash, as they will make the JSON invalid
# It makes things much simpler in templates if they can output a trailing comma though
Expand Down Expand Up @@ -736,22 +736,18 @@ sub create_health_card_panel($$$) {

my $panel_data_ref = {};

# Create Nutri-Score panel
create_nutriscore_panel($product_ref, $target_lc, $target_cc);

# Create the nutrition facts table panel
create_nutrition_facts_table_panel($product_ref, $target_lc, $target_cc);

# Create the physical activities panel
create_physical_activities_panel($product_ref, $target_lc, $target_cc);

# Create the ingredients panel
create_ingredients_panel($product_ref, $target_lc, $target_cc);

# Create the additives panel
create_additives_panel($product_ref, $target_lc, $target_cc);

# Create the health_card panel
create_ingredients_analysis_panel($product_ref, $target_lc, $target_cc);

create_panel_from_json_template("health_card", "api/knowledge-panels/health/health_card.tt.json",
$panel_data_ref, $product_ref, $target_lc, $target_cc);
}
Expand Down Expand Up @@ -1054,7 +1050,7 @@ sub create_additives_panel($$$) {
add_taxonomy_properties_in_target_languages_to_object($additive_panel_data_ref, "additives", $additive,
["wikipedia_url", "wikipedia_title", "wikipedia_abstract"], $target_lcs_ref);

create_panel_from_json_template("additive_" . $additive, "api/knowledge-panels/health/ingredients/additive.tt.json",
create_panel_from_json_template($additive_panel_id, "api/knowledge-panels/health/ingredients/additive.tt.json",
$additive_panel_data_ref, $product_ref, $target_lc, $target_cc);
}

Expand All @@ -1065,6 +1061,51 @@ sub create_additives_panel($$$) {
}


=head2 create_ingredients_analysis_panel ( $product_ref, $target_lc, $target_cc )
Creates a knowledge panel with the results of ingredients analysis.
=head3 Arguments
=head4 product reference $product_ref
Loaded from the MongoDB database, Storable files, or the OFF API.
=head4 language code $target_lc
Returned attributes contain both data and strings intended to be displayed to users.
This parameter sets the desired language for the user facing strings.
=head4 country code $target_cc
=cut

sub create_ingredients_analysis_panel($$$) {

my $product_ref = shift;
my $target_lc = shift;
my $target_cc = shift;

$log->debug("create ingredients analysis panel", { code => $product_ref->{code} }) if $log->is_debug();

my $ingredients_analysis_data_ref = data_to_display_ingredients_analysis($product_ref);

if (defined $ingredients_analysis_data_ref) {

foreach my $property_panel_data_ref (@{$ingredients_analysis_data_ref->{ingredients_analysis_tags}}) {

my $property_panel_id = "ingredients_analysis_" . $property_panel_data_ref->{property};

create_panel_from_json_template($property_panel_id, "api/knowledge-panels/health/ingredients/ingredients_analysis_property.tt.json",
$property_panel_data_ref, $product_ref, $target_lc, $target_cc);
}

create_panel_from_json_template("ingredients_analysis", "api/knowledge-panels/health/ingredients/ingredients_analysis.tt.json",
{}, $product_ref, $target_lc, $target_cc);
}
}


=head2 add_taxonomy_properties_in_target_languages_to_object ( $object_ref, $tagtype, $tagid, $properties_ref, $target_lcs_ref )
This function adds to the hash ref $object_ref (for instance a data structure passed to a template) the values
Expand Down
Loading

0 comments on commit 27b7137

Please sign in to comment.