Skip to content

Commit

Permalink
feat: Nutrient levels knowledge panels with facts and recommendations (
Browse files Browse the repository at this point in the history
…#6980)

* feat: knowledge panels for nutrient levels #6947

* add quantity in nutrient panel title

* facts + recommendations for salt

* fixed conflict

* add info and recommendations for sugars, fat and saturated fat
  • Loading branch information
stephanegigandet authored and LandonPattison committed Jul 25, 2022
1 parent 84db162 commit 40b06c3
Show file tree
Hide file tree
Showing 7 changed files with 407 additions and 61 deletions.
140 changes: 83 additions & 57 deletions lib/ProductOpener/Display.pm
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@ BEGIN
&get_world_subdomain
&data_to_display_nutriscore_and_nutrient_levels
&data_to_display_nutriscore
&data_to_display_nutrient_levels
&data_to_display_ingredients_analysis
&data_to_display_ingredients_analysis_details
Expand Down Expand Up @@ -7858,15 +7859,16 @@ HTML

# Display Nutri-Score and nutrient levels

my $template_data_nutriscore_and_nutrient_levels_ref = data_to_display_nutriscore_and_nutrient_levels($product_ref);
my $template_data_nutriscore_ref = data_to_display_nutriscore($product_ref);
my $template_data_nutrient_levels_ref = data_to_display_nutrient_levels($product_ref);

my $nutriscore_html = '';
my $nutrient_levels_html = '';

if (not $template_data_nutriscore_and_nutrient_levels_ref->{do_not_display}) {
if (not $template_data_nutrient_levels_ref->{do_not_display}) {

process_template('web/pages/product/includes/nutriscore.tt.html', $template_data_nutriscore_and_nutrient_levels_ref, \$nutriscore_html) || return "template error: " . $tt->error();
process_template('web/pages/product/includes/nutrient_levels.tt.html', $template_data_nutriscore_and_nutrient_levels_ref, \$nutrient_levels_html) || return "template error: " . $tt->error();
process_template('web/pages/product/includes/nutriscore.tt.html', $template_data_nutriscore_ref, \$nutriscore_html) || return "template error: " . $tt->error();
process_template('web/pages/product/includes/nutrient_levels.tt.html', $template_data_nutrient_levels_ref, \$nutrient_levels_html) || return "template error: " . $tt->error();
}

$template_data_ref->{display_nutriscore} = $nutriscore_html;
Expand Down Expand Up @@ -8611,9 +8613,9 @@ sub display_nutriscore_calculation_details($nutriscore_data_ref) {
}


=head2 data_to_display_nutriscore_and_nutrient_levels ( $product_ref )
=head2 data_to_display_nutrient_levels ( $product_ref )
Generates a data structure to display the Nutri-Score and the nutrient levels (food trafic lights).
Generates a data structure to display the nutrient levels (food trafic lights).
The resulting data structure can be passed to a template to generate HTML or the JSON data for a knowledge panel.
Expand All @@ -8627,11 +8629,81 @@ Reference to a data structure with needed data to display.
=cut

sub data_to_display_nutriscore_and_nutrient_levels($product_ref) {
sub data_to_display_nutrient_levels($product_ref) {

my $result_data_ref = {};

# Populate the data templates needed to display the Nutri-Score and nutrient levels
# Do not display traffic lights for baby foods
if (has_tag($product_ref, "categories", "en:baby-foods")) {

$result_data_ref->{do_not_display} = 1;
}

# do not compute a score for dehydrated products to be rehydrated (e.g. dried soups, coffee, tea)
# unless we have nutrition data for the prepared product

my $prepared = "";

foreach my $category_tag ("en:dried-products-to-be-rehydrated", "en:chocolate-powders", "en:dessert-mixes", "en:flavoured-syrups") {

if (has_tag($product_ref, "categories", $category_tag)) {

if ((defined $product_ref->{nutriments}{"energy_prepared_100g"})) {
$prepared = '_prepared';
last;
}
else {
$result_data_ref->{do_not_display} = 1;
}
}
}

if (not $result_data_ref->{do_not_display}) {

$result_data_ref->{nutrient_levels} = [];

foreach my $nutrient_level_ref (@nutrient_levels) {
my ($nid, $low, $high) = @{$nutrient_level_ref};

if ((defined $product_ref->{nutrient_levels}) and (defined $product_ref->{nutrient_levels}{$nid})) {

push @{$result_data_ref->{nutrient_levels}}, {
nid => $nid,
nutrient_level => $product_ref->{nutrient_levels}{$nid},
nutrient_quantity_in_grams => sprintf("%.2e", $product_ref->{nutriments}{$nid . $prepared . "_100g"}) + 0.0,
nutrient_in_quantity => sprintf(lang("nutrient_in_quantity"), display_taxonomy_tag($lc, "nutrients", "zz:$nid") , lang($product_ref->{nutrient_levels}{$nid} . "_quantity")),
# Needed for the current display on product page, can be removed once transitioned fully to knowledge panels
nutrient_bold_in_quantity => sprintf(lang("nutrient_in_quantity"), "<b>" . display_taxonomy_tag($lc, "nutrients", "zz:$nid") . "</b>", lang($product_ref->{nutrient_levels}{$nid} . "_quantity")),
};
}
}
}

return $result_data_ref;
}


=head2 data_to_display_nutriscore ( $product_ref )
Generates a data structure to display the Nutri-Score.
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 data_to_display_nutriscore($) {

my $product_ref = shift;

my $result_data_ref = {};

# Nutri-Score data

Expand Down Expand Up @@ -8735,60 +8807,14 @@ sub data_to_display_nutriscore_and_nutrient_levels($product_ref) {
$result_data_ref->{nutriscore_details} = display_nutriscore_calculation_details($product_ref->{nutriscore_data});
}


# Nutrient levels data

# Do not display traffic lights for baby foods
if (has_tag($product_ref, "categories", "en:baby-foods")) {

$result_data_ref->{do_not_display} = 1;
}

# do not compute a score for dehydrated products to be rehydrated (e.g. dried soups, coffee, tea)
# unless we have nutrition data for the prepared product

my $prepared = "";

foreach my $category_tag ("en:dried-products-to-be-rehydrated", "en:chocolate-powders", "en:dessert-mixes", "en:flavoured-syrups") {

if (has_tag($product_ref, "categories", $category_tag)) {

if ((defined $product_ref->{nutriments}{"energy_prepared_100g"})) {
$prepared = '_prepared';
last;
}
else {
$result_data_ref->{do_not_display} = 1;
}
}
}

if (not $result_data_ref->{do_not_display}) {

$result_data_ref->{nutrient_levels} = [];

foreach my $nutrient_level_ref (@nutrient_levels) {
my ($nid, $low, $high) = @{$nutrient_level_ref};

if ((defined $product_ref->{nutrient_levels}) and (defined $product_ref->{nutrient_levels}{$nid})) {

push @{$result_data_ref->{nutrient_levels}}, {
nutrient_level => $product_ref->{nutrient_levels}{$nid},
nutriment_prepared => sprintf("%.2e", $product_ref->{nutriments}{$nid . $prepared . "_100g"}) + 0.0,
nutriment_quantity => sprintf(lang("nutrient_in_quantity"), "<b>" . display_taxonomy_tag($lc, "nutrients", "zz:$nid") . "</b>", lang($product_ref->{nutrient_levels}{$nid} . "_quantity")),
};
}
}
}


return $result_data_ref;
}


sub add_product_nutriment_to_stats($nutriments_ref, $nid, $value) {

if ($value ne '') {

if ((defined $value) and ($value ne '')) {

if (not defined $nutriments_ref->{"${nid}_n"}) {
$nutriments_ref->{"${nid}_n"} = 0;
Expand Down
46 changes: 45 additions & 1 deletion lib/ProductOpener/KnowledgePanels.pm
Original file line number Diff line number Diff line change
Expand Up @@ -761,6 +761,8 @@ sub create_health_card_panel($$$$) {

create_nutriscore_panel($product_ref, $target_lc, $target_cc);

create_nutrient_levels_panels($product_ref, $target_lc, $target_cc);

create_nutrition_facts_table_panel($product_ref, $target_lc, $target_cc);

if ($options_ref->{activate_knowledge_panel_physical_activities}) {
Expand Down Expand Up @@ -809,7 +811,9 @@ sub create_nutriscore_panel($$$) {

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

my $panel_data_ref = data_to_display_nutriscore_and_nutrient_levels($product_ref);
my $panel_data_ref = data_to_display_nutriscore($product_ref);

# Nutri-Score panel

if ($panel_data_ref->{nutriscore_grade} eq "not-applicable") {
$panel_data_ref->{title} = lang_in_other_lc($target_lc, "attribute_nutriscore_not_applicable_title");
Expand All @@ -824,6 +828,46 @@ sub create_nutriscore_panel($$$) {
}


=head2 create_nutrient_levels_panels ( $product_ref, $target_lc, $target_cc )
Creates knowledge panels for nutrient levels for fat, saturated fat, sugars and salt.
=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_nutrient_levels_panels($$$) {

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

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

my $nutrient_levels_ref = data_to_display_nutrient_levels($product_ref);

# Nutrient levels panels
if (not $nutrient_levels_ref->{do_not_display}) {
foreach my $nutrient_level_ref (@{$nutrient_levels_ref->{nutrient_levels}}) {
my $nid = $nutrient_level_ref->{nid};
create_panel_from_json_template("nutrient_level_" . $nid, "api/knowledge-panels/health/nutrition/nutrient_level.tt.json",
$nutrient_level_ref, $product_ref, $target_lc, $target_cc);
}
}
}


=head2 create_nutrition_facts_table_panel ( $product_ref, $target_lc, $target_cc )
Creates a knowledge panel with the nutrition facts table.
Expand Down
61 changes: 60 additions & 1 deletion po/common/common.pot
Original file line number Diff line number Diff line change
Expand Up @@ -6196,4 +6196,63 @@ msgctxt "action_add_nutrition_facts"
msgid "Add nutrition facts"
msgstr "Add nutrition facts"


# Used as a header for key facts
msgctxt "knowledge_panels_facts"
msgid "What you need to know"
msgstr "What you need to know"

msgctxt "knowledge_panels_recommendation"
msgid "Recommendation"
msgstr "Recommendation"

msgctxt "nutrient_info_salt_risk"
msgid "A high consumption of salt (or sodium) can cause raised blood pressure, which can increase the risk of heart disease and stroke."
msgstr "A high consumption of salt (or sodium) can cause raised blood pressure, which can increase the risk of heart disease and stroke."

msgctxt "nutrient_info_salt_high_blood_pressure"
msgid "Many people who have high blood pressure do not know it, as there are often no symptoms."
msgstr "Many people who have high blood pressure do not know it, as there are often no symptoms."

msgctxt "nutrient_info_salt_high_consumption"
msgid "Most people consume too much salt (on average 9 to 12 grams per day), around twice the recommended maximum level of intake."
msgstr "Most people consume too much salt (on average 9 to 12 grams per day), around twice the recommended maximum level of intake."

msgctxt "nutrient_recommendation_salt_title"
msgid "Limit the consumption of salt and salted food"
msgstr "Limit the consumption of salt and salted food"

msgctxt "nutrient_recommendation_salt_cooking_and_table"
msgid "Reduce the quantity of salt used when cooking, and don't salt again at the table."
msgstr "Reduce the quantity of salt used when cooking, and don't salt again at the table."

msgctxt "nutrient_recommendation_salt_limit_salty_snacks"
msgid "Limit the consumption of salty snacks and choose products with lower salt content."
msgstr "Limit the consumption of salty snacks and choose products with lower salt content."

msgctxt "nutrient_info_sugars_risk"
msgid "A high consumption of sugar can cause weight gain and tooth decay. It also augments the risk of type 2 diabetes and cardio-vascular diseases."
msgstr "A high consumption of sugar can cause weight gain and tooth decay. It also augments the risk of type 2 diabetes and cardio-vascular diseases."

msgctxt "nutrient_recommendation_sugars_title"
msgid "Limit the consumption of sugar and sugary drinks"
msgstr "Limit the consumption of sugar and sugary drinks"

msgctxt "nutrient_recommendation_sugars_drinks"
msgid "Sugary drinks (such as sodas, fruit beverages, and fruit juices and nectars) should be limited as much as possible (no more than 1 glass a day)."
msgstr "Sugary drinks (such as sodas, fruit beverages, and fruit juices and nectars) should be limited as much as possible (no more than 1 glass a day)."

msgctxt "nutrient_recommendation_sugars_food"
msgid "Choose products with lower sugar content and reduce the consumption of products with added sugars."
msgstr "Choose products with lower sugar content and reduce the consumption of products with added sugars."

msgctxt "nutrient_info_fat_and_saturated_fat_risk"
msgid "A high consumption of fat, especially saturated fats, can raise cholesterol, which increases the risk of heart diseases."
msgstr "A high consumption of fat, especially saturated fats, can raise cholesterol, which increases the risk of heart diseases."

msgctxt "nutrient_recommendation_fat_and_saturated_fat_title"
msgid "Reduce the consumption of fat and saturated fat"
msgstr "Limit the consumption of fat and saturated fat"

msgctxt "nutrient_recommendation_fat_and_saturated_fat"
msgid "Choose products with lower fat and saturated fat content."
msgstr "Choose products with lower fat and saturated fat content."
63 changes: 63 additions & 0 deletions po/common/en.po
Original file line number Diff line number Diff line change
Expand Up @@ -6218,3 +6218,66 @@ msgctxt "action_add_nutrition_facts"
msgid "Add nutrition facts"
msgstr "Add nutrition facts"

# Used as a header for key facts
msgctxt "knowledge_panels_facts"
msgid "What you need to know"
msgstr "What you need to know"

msgctxt "knowledge_panels_recommendation"
msgid "Recommendation"
msgstr "Recommendation"

msgctxt "nutrient_info_salt_risk"
msgid "A high consumption of salt (or sodium) can cause raised blood pressure, which can increase the risk of heart disease and stroke."
msgstr "A high consumption of salt (or sodium) can cause raised blood pressure, which can increase the risk of heart disease and stroke."

msgctxt "nutrient_info_salt_high_blood_pressure"
msgid "Many people who have high blood pressure do not know it, as there are often no symptoms."
msgstr "Many people who have high blood pressure do not know it, as there are often no symptoms."

msgctxt "nutrient_info_salt_high_consumption"
msgid "Most people consume too much salt (on average 9 to 12 grams per day), around twice the recommended maximum level of intake."
msgstr "Most people consume too much salt (on average 9 to 12 grams per day), around twice the recommended maximum level of intake."

msgctxt "nutrient_recommendation_salt_title"
msgid "Limit the consumption of salt and salted food"
msgstr "Limit the consumption of salt and salted food"

msgctxt "nutrient_recommendation_salt_cooking_and_table"
msgid "Reduce the quantity of salt used when cooking, and don't salt again at the table."
msgstr "Reduce the quantity of salt used when cooking, and don't salt again at the table."

msgctxt "nutrient_recommendation_salt_limit_salty_snacks"
msgid "Limit the consumption of salty snacks and choose products with lower salt content."
msgstr "Limit the consumption of salty snacks and choose products with lower salt content."

msgctxt "nutrient_info_sugars_risk"
msgid "A high consumption of sugar can cause weight gain and tooth decay. It also augments the risk of type 2 diabetes and cardio-vascular diseases."
msgstr "A high consumption of sugar can cause weight gain and tooth decay. It also augments the risk of type 2 diabetes and cardio-vascular diseases."

msgctxt "nutrient_recommendation_sugars_title"
msgid "Limit the consumption of sugar and sugary drinks"
msgstr "Limit the consumption of sugar and sugary drinks"

msgctxt "nutrient_recommendation_sugars_drinks"
msgid "Sugary drinks (such as sodas, fruit beverages, and fruit juices and nectars) should be limited as much as possible (no more than 1 glass a day)."
msgstr "Sugary drinks (such as sodas, fruit beverages, and fruit juices and nectars) should be limited as much as possible (no more than 1 glass a day)."

msgctxt "nutrient_recommendation_sugars_food"
msgid "Choose products with lower sugar content and reduce the consumption of products with added sugars."
msgstr "Choose products with lower sugar content and reduce the consumption of products with added sugars."

msgctxt "nutrient_info_fat_and_saturated_fat_risk"
msgid "A high consumption of fat, especially saturated fats, can raise cholesterol, which increases the risk of heart diseases."
msgstr "A high consumption of fat, especially saturated fats, can raise cholesterol, which increases the risk of heart diseases."

msgctxt "nutrient_recommendation_fat_and_saturated_fat_title"
msgid "Reduce the consumption of fat and saturated fat"
msgstr "Limit the consumption of fat and saturated fat"

msgctxt "nutrient_recommendation_fat_and_saturated_fat"
msgid "Choose products with lower fat and saturated fat content."
msgstr "Choose products with lower fat and saturated fat content."



Loading

0 comments on commit 40b06c3

Please sign in to comment.