Skip to content

Commit

Permalink
feat: compute stats for the main material of the packaging (#8662)
Browse files Browse the repository at this point in the history
  • Loading branch information
stephanegigandet authored Aug 1, 2023
1 parent 3e92f7e commit be14720
Show file tree
Hide file tree
Showing 49 changed files with 756 additions and 129 deletions.
60 changes: 60 additions & 0 deletions docs/api/ref/api-v3.yml
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,66 @@ paths:
in: query
name: term
description: Alias for the "string" parameter provided for backward compatibility. "string" takes precedence.
'/api/v3/tag/{tagtype}/{tag_or_tagid}':
parameters:
- schema:
type: string
example: categories
name: tagtype
in: path
required: true
description: Type of the tag
- schema:
type: string
name: tag_or_tagid
in: path
required: true
description: 'Tag name (e.g. yogurts) or tag id (e.g. en:yogurts)'
get:
summary: Get knowledge panels for a tag
tags: []
responses:
'200':
description: OK
content:
application/json:
schema:
allOf:
- $ref: ./responses/response-status/response_status.yaml
- type: object
properties:
tagtype:
type: string
description: |
Input tagtype
tagid:
type: string
description: |
Input tagid
tag:
type: object
properties:
tagid:
type: string
description: Canonicalized tagid corresponding to the input tag_or_tagid
tagtype:
type: string
description: Canonicalized tagtype
knowledge_panels:
$ref: ./schemas/knowledge_panels/panels.yaml
description: Knowledge panels for the tag
application/xml:
schema:
type: object
properties: {}
operationId: get-api-v3-tag-tagtype-tag_or_tagid
description: |-
Return knowledge panels for a tag.
Currently the knowledge panels returned are:
Categories:
- Packaging stats for a category
tags:
- name: Read Requests
- name: Write Requests
2 changes: 1 addition & 1 deletion docs/api/ref/schemas/taxonomies/tagtype.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ enum:
- preservation
- states
- test
- allergens
- traces
- vitamins
description: 'Identifier of a taxonomy. See https://wiki.openfoodfacts.org/Global_taxonomies and https://github.com/openfoodfacts/openfoodfacts-server/tree/main/taxonomies'
examples: []
11 changes: 11 additions & 0 deletions lib/ProductOpener/API.pm
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ use ProductOpener::Packaging qw/:all/;

use ProductOpener::APIProductRead qw/:all/;
use ProductOpener::APIProductWrite qw/:all/;
use ProductOpener::APITagRead qw/:all/;
use ProductOpener::APITaxonomySuggestions qw/:all/;

use CGI qw(header);
Expand Down Expand Up @@ -397,6 +398,16 @@ sub process_api_request ($request_ref) {
add_invalid_method_error($response_ref, $request_ref);
}
}
# Tag read
elsif ($request_ref->{api_action} eq "tag") {

if ($request_ref->{api_method} =~ /^(GET|HEAD|OPTIONS)$/) {
read_tag_api($request_ref);
}
else {
add_invalid_method_error($response_ref, $request_ref);
}
}
# Unknown action
else {
$log->warn("process_api_request - unknown action", {request => $request_ref}) if $log->is_warn();
Expand Down
145 changes: 145 additions & 0 deletions lib/ProductOpener/APITagRead.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
# This file is part of Product Opener.
#
# Product Opener
# Copyright (C) 2011-2023 Association Open Food Facts
# Contact: contact@openfoodfacts.org
# 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/>.

=head1 NAME
ProductOpener::APIProductRead - implementation of READ API for accessing product data
=head1 DESCRIPTION
=cut

package ProductOpener::APITagRead;

use ProductOpener::PerlStandards;
use Exporter qw< import >;

use Log::Any qw($log);

BEGIN {
use vars qw(@ISA @EXPORT_OK %EXPORT_TAGS);
@EXPORT_OK = qw(
&read_tag_api
); # symbols to export on request
%EXPORT_TAGS = (all => [@EXPORT_OK]);
}

use vars @EXPORT_OK;

use ProductOpener::Config qw/:all/;
use ProductOpener::Display qw/:all/;
use ProductOpener::Users qw/:all/;
use ProductOpener::Lang qw/:all/;
use ProductOpener::API qw/:all/;
use ProductOpener::KnowledgePanels qw/:all/;
use ProductOpener::KnowledgePanelsTags qw/:all/;
use ProductOpener::Tags qw/:all/;

=head2 read_tag_api ( $request_ref )
Process API V3 READ tag requests.
Currently only return the knowledge_panels field for the tag, if any.
=head3 Parameters
=head4 $request_ref (input)
Reference to the request object.
=cut

sub read_tag_api ($request_ref) {

$log->debug("read_tag_api - start", {request => $request_ref}) if $log->is_debug();

my $response_ref = $request_ref->{api_response};

# we add the inputs to the response
my $tagtype = $request_ref->{tagtype};
my $tagid = $request_ref->{tagid};

$response_ref->{tagtype} = $tagtype;
$response_ref->{tagid} = $tagid;

if (not defined $tagtype) {

add_error(
$response_ref,
{
message => {id => "missing_tagtype"},
field => {id => "tagtype", value => $tagtype},
impact => {id => "failure"},
}
);
$response_ref->{result} = {id => "tag_not_found"};
}

if (not defined $tagid) {

add_error(
$response_ref,
{
message => {id => "missing_tagid"},
field => {id => "tagid", value => $tagtype},
impact => {id => "failure"},
}
);
$response_ref->{result} = {id => "tag_not_found"};
}

# TODO: add check for valid tagtype? (we currently do not have a definitive list though)

if ((defined $tagtype) and (defined $tagid)) {
$response_ref->{result} = {id => "tag_found"};

# Canonicalize the tagid
my $canon_tagid;
if (defined $taxonomy_fields{$tagtype}) {
$canon_tagid = canonicalize_taxonomy_tag($lc, $tagtype, $tagid);

}
else {
my $display_tag = canonicalize_tag2($tagtype, $tagid);
$canon_tagid = get_string_id_for_lang("no_language", $display_tag);
}

# add canonical values to tag output
$response_ref->{tag} = {
tagid => $canon_tagid,
tagtype => $tagtype
};

initialize_knowledge_panels_options($knowledge_panels_options_ref, $request_ref);
my $tag_ref = {}; # Object to store the knowledge panels
my $panels_created
= create_tag_knowledge_panels($tag_ref, $lc, $cc, $knowledge_panels_options_ref, $tagtype, $canon_tagid);

if ($panels_created) {
$response_ref->{tag}{knowledge_panels} = $tag_ref->{"knowledge_panels" . "_" . $lc};
}
}

$log->debug("read_tag_api - stop", {request => $request_ref}) if $log->is_debug();

return;
}

1;
6 changes: 4 additions & 2 deletions lib/ProductOpener/Ecoscore.pm
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ BEGIN {
%ecoscore_countries_enabled
@ecoscore_countries_enabled_sorted
%agribalyse
); # symbols to export on request
%EXPORT_TAGS = (all => [@EXPORT_OK]);
}
Expand All @@ -78,7 +80,7 @@ use Text::CSV();
use Math::Round;
use Data::DeepAccess qw(deep_get deep_exists);

my %agribalyse = ();
%agribalyse = ();

=head1 VARIABLES
Expand All @@ -102,7 +104,7 @@ foreach my $country (@ecoscore_countries_enabled_sorted) {

=head1 FUNCTIONS
=head2 load_agribalyse_data( $product_ref )
=head2 load_agribalyse_data()
Loads the AgriBalyse database.
Expand Down
47 changes: 44 additions & 3 deletions lib/ProductOpener/Packaging.pm
Original file line number Diff line number Diff line change
Expand Up @@ -950,10 +950,37 @@ sub aggregate_packaging_by_parent_materials ($product_ref) {
deep_val($packagings_materials_ref, "all", "weight") += $total_weight;
}
}
}

$product_ref->{packagings_materials} = $packagings_materials_ref;

return;
}

=head2 compute_weight_stats_for_parent_materials($product_ref)
Compute stats for the parent materials of a product:
- % of the weight of a material over the weight of all packaging
- weight of packaging per 100g of product
Also compute the main parent material.
=cut

sub compute_weight_stats_for_parent_materials ($product_ref) {

# We will determine which packaging material has the greatest weight
my $packagings_materials_main;
my $packagings_materials_main_weight = 0;

my $packagings_materials_ref = $product_ref->{packagings_materials};

if (defined $packagings_materials_ref) {

# Iterate over each parent material to compute weight statistics
my $total_weight = deep_get($packagings_materials_ref, "all", "weight");
foreach my $parent_material_ref (values %$packagings_materials_ref) {
foreach my $parent_material_id (sort keys %$packagings_materials_ref) {
my $parent_material_ref = $packagings_materials_ref->{$parent_material_id};
if (defined $parent_material_ref->{weight}) {
if ($total_weight) {
$parent_material_ref->{weight_percent} = $parent_material_ref->{weight} / $total_weight * 100;
Expand All @@ -962,12 +989,23 @@ sub aggregate_packaging_by_parent_materials ($product_ref) {
$parent_material_ref->{weight_100g}
= $parent_material_ref->{weight} / $product_ref->{product_quantity} * 100;
}
if ( ($parent_material_id ne "all")
and ($parent_material_ref->{weight} > $packagings_materials_main_weight))
{
$packagings_materials_main = $parent_material_id;
$packagings_materials_main_weight = $parent_material_ref->{weight};
}
}
}
}

$product_ref->{packagings_materials} = $packagings_materials_ref;

# Record the main packaging material
if (defined $packagings_materials_main) {
$product_ref->{packagings_materials_main} = $packagings_materials_main;
}
else {
delete $product_ref->{packagings_materials_main};
}
return;
}

Expand Down Expand Up @@ -1090,6 +1128,9 @@ sub analyze_and_combine_packaging_data ($product_ref, $response_ref) {
# Aggregate data per parent material
aggregate_packaging_by_parent_materials($product_ref);

# Compute stats for each parent material
compute_weight_stats_for_parent_materials($product_ref);

$log->debug("analyze_and_combine_packaging_data - done",
{packagings => $product_ref->{packagings}, response => $response_ref})
if $log->is_debug();
Expand Down
Loading

0 comments on commit be14720

Please sign in to comment.