Skip to content

Conversation

@pascalypperciel
Copy link
Contributor

What

  • Creating a GET route that allows users to fetch product info as Knowledge Panels. They can either get all the keys from the product or a selected one.
  • Models to mimic the Knowledge Panels structure.
  • Unit tests to test 4 different test cases for my route.
  • I'd like to note that every whitespace modification happened automatically because of the .editorconfig file.

Screenshot

With an input k

Screenshot from 2025-03-26 01-45-33

Without an input k, so all the keys in the product

Screenshot from 2025-03-26 01-45-48

Fixes bug(s)

  • N/A

Part of

@pascalypperciel
Copy link
Contributor Author

Bonjour @stephanegigandet et @teolemon!

The pytest check failed. After some digging, it seems this could be due to a connection leak in the test code. I think that the database connections aren't being closed correctly:
image

Personally, I think that fixing it would step outside the scope of this issue. I think I should create a new issue to fix the problem (which I'd love to try and fix myself). Then, I'm not sure which way would be preferable here:

  1. I can revert the unit test in this PR so the checks pass for now, and reintroduce it once the connection issue is resolved.
  2. We leave this PR as-is for the moment, fix the test issue, and return to this PR afterward.

Let me know what works best. I’m open to whichever path you think is better, or something else entirely if there's a better solution obviously 😄!

@pascalypperciel
Copy link
Contributor Author

Will reopen when #270 is merged.

Copy link
Member

@alexgarel alexgarel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's the right direction @pascalypperciel but I don't think we want this rendering ! (it's far too verbose and not user oriented, there should be only one panel per property, and inside it, put a sensible html)

@teolemon might be able to provide what we would like to display.

I think there is a "table"

Comment on lines 385 to 403
query = f"""
SELECT product, k, v, owner, version, editor, last_edit, comment
FROM folksonomy
WHERE product = %s
"""
params = [product]
if k:
query+= " AND k = %s"
params.append(k)
query += " ORDER BY k;"

cur, timing = await db.db_exec(query, tuple(params))
rows = await cur.fetchall()

if not rows:
raise HTTPException(
status_code=404,
detail="Could not find product or key",
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer that we reuse existing API functions here (or refactor them to use a common method).

@teolemon
Copy link
Member

teolemon commented Apr 4, 2025

Here's what we currently have in the mobile app:
image
@alexgarel @pascalypperciel I'd very much like to be able to:

  • have the property name link to all instances of that property
  • Have a little (?) icon linking to the property documentation on the wiki next to the property name
  • have the property value link to all instances of that value

@pascalypperciel
Copy link
Contributor Author

Thank you for all the feedback to both of you! I will be bringing changes soon. 😄

@codecov-commenter
Copy link

codecov-commenter commented Apr 5, 2025

Codecov Report

Attention: Patch coverage is 92.63158% with 7 lines in your changes missing coverage. Please review.

Project coverage is 90.21%. Comparing base (b9cda65) to head (04932ef).
Report is 93 commits behind head on main.

Files with missing lines Patch % Lines
folksonomy/knowledge_panels.py 88.00% 6 Missing ⚠️
folksonomy/utils.py 95.45% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #267      +/-   ##
==========================================
- Coverage   95.06%   90.21%   -4.85%     
==========================================
  Files           5        6       +1     
  Lines         324      460     +136     
==========================================
+ Hits          308      415     +107     
- Misses         16       45      +29     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@pascalypperciel
Copy link
Contributor Author

Hello again @alexgarel !

So I switch from using a text element to a table element because that's how I interpreted this comment:

I think there is a "table"

I added every requirement from teolemon, hopefully in a more user-friendly format.

Here is an example of a return in JSON:
image

And here's the same body but in HTML:
image

And for the following comment:

I would prefer that we reuse existing API functions here (or refactor them to use a common method).

I looked for existing helpers to reuse but couldn’t find one that fit. I considered creating a new one, but it ended up requiring changes across multiple routes to make it work cleanly. I held back on that refactor to avoid stepping beyond the scope of this issue or introducing potential merge conflicts. Happy to go through with it if you think I should, or revisit this in a follow-up PR!

Copy link
Member

@alexgarel alexgarel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pascalypperciel first thank you so much for your work, and really sorry for the latency to review.

Overall it's good (although I'm not really convinced that we need a table, but it can be changed later).

I propose some (minor) changes.

panels = data["knowledge_panels"]
assert "color" in panels
assert "size" in panels
assert "x-pg-timing" in response.headers
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to assert that here !

Comment on lines 405 to 470
panels_by_key = {}
for row in rows:

product_value, k, v, _, _, _, _, _ = row

if k not in panels_by_key:
panels_by_key[k] = {
"Barcode": product_value,
"Key": k,
"Value": v
}
else:
data = panels_by_key[k]
if not data.get("Barcode") and product_value:
data["Barcode"] = product_value
if not data.get("Value") and v:
data["Value"] = v

panels = {}
for k, data in panels_by_key.items():
rows_html = ""
for property, value in data.items():
if value is None:
continue

# Links for Key and Value property
if property == "Key":
value_cell = (
f'<a href="world.openfoodfacts.org/property/{value}">{value}</a> '
f'<a href="wiki.openfoodfacts.org/Folksonomy/Property/{value}">&#8505;</a>'
)
elif property == "Value":
value_cell = f'<a href="world.openfoodfacts.org/property/{data["Key"]}/value/{value}">{value}</a>'
else:
value_cell = value

row_html = f"<tr><td>{property}</td><td>{value_cell}</td></tr>"
rows_html += row_html



table_html = f"<table>{rows_html}</table>"

table_element = TableElement(
id=k,
title=f"Folksonomy Data for '{k}'",
rows=table_html,
columns=[
TableColumn(type="text", text="Property"),
TableColumn(type="text", text="Value")
]
)

element = Element(
type="table",
table_element=table_element
)

panel = Panel(
title_element=TitleElement(
title=f"Folksonomy Data for '{k}'",
name=k
),
elements=[element]
)
panels[k] = panel
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like this to be in a separate file. To avoid having a long method. Maybe knowelge_panels.py

Comment on lines 95 to 118
class TitleElement(BaseModel):
name: str
title: str

class TableColumn(BaseModel):
type: str
text: str

class TableElement(BaseModel):
id: str
title: str
rows: str
columns: List[TableColumn]

class Element(BaseModel):
type: str
table_element: TableElement

class Panel(BaseModel):
title_element: TitleElement
elements: List[Element]

class ProductKnowledgePanels(BaseModel):
knowledge_panels: Dict[str, Panel]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add simple docstring to every object you introduce and eventually document fields ? (it will be in the generated documentation).
You might copy information from openfoodfacts-server OpenAPI documentation.

@pascalypperciel
Copy link
Contributor Author

Hello @alexgarel

Thank you for the kind words and for your guidance on this PR!

Apologies for the delay on my side as well! My busy winter semester has just wrapped up, so I finally have more time to contribute. 😄

Please let me know if I can bring any improvements!

@alexgarel
Copy link
Member

Hi @pascalypperciel, really sorry that I missed this PR. You did a great job.
This branch will conflict with #295,
so maybe I will wait for it to fix/merge it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Todo

Development

Successfully merging this pull request may close these issues.

Create a Knowledge Panel compliant route for the Folksonomy Engine list of properties for a given barcode

4 participants