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: Adding Knowledge Panel for Last-edits #13

Closed
wants to merge 18 commits into from
Closed
52 changes: 49 additions & 3 deletions app/knowledge_panels.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
from typing import Union

from urllib.parse import urlencode

from .models import HungerGameFilter
from .models import HungerGameFilter, country_to_ISO_code, facet_plural
from .off import lastEdit


def hunger_game_kp(
Expand Down Expand Up @@ -39,3 +38,50 @@ def hunger_game_kp(
],
},
}


def last_edits_kp(
facet: str,
value: Union[str, None] = None,
country: Union[str, None] = None,
):
"""
Return knowledge panel for last-edits corresponding to different facet
"""
query = {
"fields": "product_name,code,last_editor,last_edit_dates_tags",
"sort_by": "last_modified_t",
}
description = ""
if facet == "country":
country = value
country_code = country_to_ISO_code(value=value)
url = f"https://{country_code}-en.openfoodfacts.org"
facet = value = None
if country is not None:
country_code = country_to_ISO_code(value=country)
url = f"https://{country_code}-en.openfoodfacts.org"
description += country
if country is None:
url = "https://world.openfoodfacts.org"
sumit-158 marked this conversation as resolved.
Show resolved Hide resolved
if facet is not None:
description += f" {facet}"
if value is not None:
query[f"{facet_plural(facet=facet)}_tags_en"] = value
description += f" {value}"
description = f"last-edits issues related to {description}"
expected_html = lastEdit(url=url, query=query)

return {
"LastEdits": {
"title": "Last-edites",
"subtitle": f"{description}",
"source_url": f"{url}/{facet}/{value}?sort_by=last_modified_t",
"elements": [
{
"element_type": "text",
"text_element": expected_html,
},
],
},
}
29 changes: 20 additions & 9 deletions app/main.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from typing import Union

from fastapi import FastAPI
from fastapi import FastAPI, HTTPException

from .knowledge_panels import hunger_game_kp
from .knowledge_panels import hunger_game_kp, last_edits_kp
from .models import FacetName, HungerGameFilter

app = FastAPI()
Expand All @@ -23,12 +23,23 @@ def knowledge_panel(
):
# FacetName is the model that have list of values
# facet_value are the list of values connecting to FacetName eg:- category/beer, here beer is the value
panels = []
if facet_name in HungerGameFilter.list():
panels.append(
hunger_game_kp(
hunger_game_filter=facet_name, value=facet_value, country=country
try:
panels = []
if facet_name in HungerGameFilter.list():
panels.append(
hunger_game_kp(
hunger_game_filter=facet_name, value=facet_value, country=country
)
)
)
"""Appending hunger-game-knowledge-panel
"""

return {"knowledge_panels": panels}
if facet_value is not None:
panels.append(
last_edits_kp(facet=facet_name, value=facet_value, country=country)
)
"""Appending last-edits-knowledge-panel"""

return {"knowledge_panels": panels}
except:
raise HTTPException(status_code=404, detail="Item not found")
24 changes: 24 additions & 0 deletions app/models.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
from enum import Enum
import inflect
sumit-158 marked this conversation as resolved.
Show resolved Hide resolved

"""Library to correctly generate plurals, singular nouns, ordinals, indefinite articles convert numbers to words.
https://pypi.org/project/inflect/ """

import pycountry
from pydantic import BaseModel


Expand Down Expand Up @@ -38,3 +43,22 @@ class HungerGameFilter(str, Enum):
@staticmethod
def list():
return [c.value for c in HungerGameFilter]


def facet_plural(facet: str):
"""
Return plural of facet
"""
p = inflect.engine()
plural = p.plural(facet)
facet_plural = plural
if facet == "packaging":
facet_plural = facet

return facet_plural


def country_to_ISO_code(value: str):
country_data = pycountry.countries.get(name=value)
country_iso_code = country_data.alpha_2
return country_iso_code.lower()
22 changes: 22 additions & 0 deletions app/off.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import requests


def lastEdit(url, query):
"""
Helper function to return data for last-edits
"""
search_url = f"{url}/api/v2/search"
response_API = requests.get(search_url, params=query)
data = response_API.json()
counts = data["count"]
tags = data["products"]

html = "\n".join(
f'<li>{tag["product_name"]} ({tag["code"]}) edited by {tag["last_editor"]} on {tag["last_edit_dates_tags"][0]}</li>'
for tag in tags[0:10]
if "product_name" in tag
)
sumit-158 marked this conversation as resolved.
Show resolved Hide resolved

html = f"<ul><p>Total number of edits {counts} </p>\n {html}</ul>"
teolemon marked this conversation as resolved.
Show resolved Hide resolved

return html
Binary file modified requirements.txt
Binary file not shown.
56 changes: 55 additions & 1 deletion tests/test_knowledge_panels.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
from app.main import hunger_game_kp
from ast import Param
from app.main import hunger_game_kp, last_edits_kp
import requests
import app.main
from .test_utils import mock_get_factory


def test_hunger_game_kp_with_filter_value_and_country():
Expand Down Expand Up @@ -91,3 +95,53 @@ def test_hunger_game_kp_label_with_value():
]
}
}


def test_last_edits_kp_with_all_three_values(monkeypatch):
expected_url = "https://fr-en.openfoodfacts.org/api/v2/search"
expected_json = {
sumit-158 marked this conversation as resolved.
Show resolved Hide resolved
"count": 13552,
"page": 1,
"page_count": 24,
"page_size": 24,
"products": [
{
"code": "7624841856058",
"last_edit_dates_tags": ["2022-07-27", "2022-07", "2022"],
"last_editor": "gluten-scan",
"product_name": "Red thai curry soup",
},
{
"code": "8712566429271",
"last_edit_dates_tags": ["2022-07-27", "2022-07", "2022"],
"last_editor": "org-unilever-france-gms",
"product_name": "Knorr Soupe Liquide Mouliné de Légumes d'Autrefois 1L",
},
{
"code": "4023900542803",
"last_edit_dates_tags": ["2022-07-26", "2022-07", "2022"],
"last_editor": "prepperapp",
"product_name": "Bio Soja Souce",
},
],
}
monkeypatch.setattr(
requests,
"get",
mock_get_factory(expected_url, expected_json),
sumit-158 marked this conversation as resolved.
Show resolved Hide resolved
)
result = app.main.last_edits_kp(facet="label", value="vegan", country="france")

assert result == {
"LastEdits": {
"title": "Last-edites",
"subtitle": "last-edits issues related to france label vegan",
"source_url": "https://fr-en.openfoodfacts.org/label/vegan?sort_by=last_modified_t",
"elements": [
{
"element_type": "text",
"text_element": "<ul><p>Total number of edits 13552 </p>\n <li>Red thai curry soup (7624841856058) edited by gluten-scan on 2022-07-27</li>\n<li>Knorr Soupe Liquide Mouliné de Légumes d'Autrefois 1L (8712566429271) edited by org-unilever-france-gms on 2022-07-27</li>\n<li>Bio Soja Souce (4023900542803) edited by prepperapp on 2022-07-26</li>\n<li>Berry Revolutionary (8711327539303) edited by kiliweb on 2022-07-26</li>\n<li>Gelées con succhi Di frutta (8016042021011) edited by kiliweb on 2022-07-26</li>\n<li>Minifrühlingsrollen mit Gemüse (4316268371421) edited by blaerf on 2022-07-26</li>\n<li>Chicorée 0% Caffeine (5411788047166) edited by kiliweb on 2022-07-26</li>\n<li>Soy sauce (8715035110502) edited by frazerclews on 2022-07-26</li>\n<li>Sables pépites de chocolat (3760154260619) edited by kiliweb on 2022-07-26</li>\n<li>Raw pasta Fettuccine (8718868683878) edited by kiliweb on 2022-07-26</li></ul>",
}
],
}
}
30 changes: 27 additions & 3 deletions tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def test_knowledge_panel_badendpoint():

def test_knowledge_panel_ctegory_with_value_and_country():
sumit-158 marked this conversation as resolved.
Show resolved Hide resolved
assert knowledge_panel(
facet_name="category", facet_value="chocolate", country="belgium"
facet_name="category", facet_value="chocolates", country="belgium"
) == {
"knowledge_panels": [
{
Expand All @@ -39,12 +39,36 @@ def test_knowledge_panel_ctegory_with_value_and_country():
{
"element_type": "text",
"text_element": {
"html": "<p><a href='https://hunger.openfoodfacts.org/questions?country=belgium&type=category&value_tag=chocolate'>Answer robotoff questions about chocolate category</a></p>\n"
"html": "<p><a href='https://hunger.openfoodfacts.org/questions?country=belgium&type=category&value_tag=chocolates'>Answer robotoff questions about chocolates category</a></p>\n"
},
}
]
}
}
},
{
"last-edits": {
"elements": [
{
"element_type": "text",
"total_issues": 17028,
"text_element": [
{"code": "3664346305860", "last_editor": "jul45"},
{
"code": "5201127034724",
"last_editor": "ayyyvocado",
"product_name": "Ион Дарк Шок. 72 % Какао и Цели Бадеми",
},
{
"code": "3560071265564",
"last_editor": "kiliweb",
"product_name": "Chocolat noir noisettes entières",
},
],
"source_url": "https://world.openfoodfacts.org/api/v2/search?categories_tags_en=chocolates&fields=code%2Cproduct_name%2Clast_editor&sort_by=last_modified_t",
}
]
}
},
]
}

Expand Down
21 changes: 21 additions & 0 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
class MockResponse:
def __init__(self, json_content):
self.json_content = json_content

def json(self):
return self.json_content


def mock_get_factory(target_url, json_content):
"""generate a mock to patch request.get with a json response"""

def mock_get(url, **kwargs):
assert url == target_url
assert kwargs == {
"fields": "product_name,code,last_editor,last_edit_dates_tags",
"sort_by": "last_modified_t",
"labels_tags_en": "vegan",
sumit-158 marked this conversation as resolved.
Show resolved Hide resolved
}
sumit-158 marked this conversation as resolved.
Show resolved Hide resolved
return MockResponse(json_content)

return mock_get