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

feat: Nutrient levels knowledge panels with facts and recommendations #6980

Merged
merged 6 commits into from
Jul 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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