Lavender825 commited on
Commit
26dd6cb
·
1 Parent(s): 822f6b9

Show product images in consumer interface

Browse files
Files changed (1) hide show
  1. app.py +38 -2
app.py CHANGED
@@ -9,6 +9,7 @@ import traceback
9
  from functools import lru_cache
10
  from pathlib import Path
11
  from typing import Any, Dict, List, Tuple
 
12
 
13
  try:
14
  import huggingface_hub as _hf_hub
@@ -164,6 +165,9 @@ def _coerce_product(item, idx=0):
164
  "category": category,
165
  "features": features,
166
  "categories": categories,
 
 
 
167
  "price": _safe_float(item.get("price")),
168
  "average_rating": _safe_float(item.get("average_rating")),
169
  "rating_number": _safe_float(item.get("rating_number")),
@@ -252,6 +256,18 @@ def _get_product(name: str) -> Dict[str, Any]:
252
  return next((p for p in PRODUCTS if p["name"] == name), PRODUCTS[0])
253
 
254
 
 
 
 
 
 
 
 
 
 
 
 
 
255
  def _meta(product_or_meta: Dict[str, Any]) -> Dict[str, Any]:
256
  return {
257
  "features_text": product_or_meta.get("features", product_or_meta.get("features_text", "")),
@@ -404,7 +420,25 @@ def consumer_product_view(product_name: str, selected_aspect: str) -> Tuple[str,
404
  result = _predict_product(product_name)
405
  except Exception:
406
  return _error_html(traceback.format_exc(limit=5)), "", "", []
407
- detail = f'<div class="product-card"><h3>{_esc(product["name"])}</h3><p class="muted">{_esc(product["categories"])}</p><div class="meta-pills"><span>Source: {_esc(product.get("source", "demo"))}</span><span>Price: ${_safe_float(product["price"]):.2f}</span><span>Rating: {_safe_float(product["average_rating"]):.1f}</span><span>Reviews: {int(_safe_float(product["rating_number"]))}</span></div><p><b>Metadata:</b> {_esc(product["features"])}</p>{_recommendation_html(result, product["name"])}{_overall_html(result)}</div>'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
408
  evidence = f'<h4>Key review evidence</h4>{_highlight_review(product["review"], selected_aspect)}'
409
  return detail, _aspect_cards(result, product["review"], selected_aspect), evidence, _aspect_rows(result, product["review"])
410
 
@@ -622,6 +656,8 @@ button.primary, .gradio-button.primary { background:var(--accent) !important; bo
622
  .status.ok { background:#ecfdf5; border-color:#86efac; color:#065f46; }
623
  .status.bad { background:#fff1f2; border-color:#fda4af; color:#991b1b; }
624
  .product-card, .overall-card, .note-card { border:1px solid var(--line); border-radius:8px; padding:16px; background:white; }
 
 
625
  .recommendation-card { border:1px solid #fed7aa; border-left:5px solid var(--accent); background:#fff7ed; border-radius:8px; padding:13px 14px; margin:12px 0; }
626
  .recommendation-card p { margin:7px 0 0; }
627
  .muted { color:var(--muted); }
@@ -654,7 +690,7 @@ mark { background:#fde68a; color:#111827; border-radius:4px; padding:1px 3px; }
654
  .kv-table td { border-bottom:1px solid #e2e8f0; padding:9px 12px; }
655
  .kv-table td:first-child { width:220px; color:#334155; font-weight:700; background:#f8fafc; }
656
  .compact-note { color:#475569; font-size:13px; margin:4px 0 10px; }
657
- @media (max-width:860px) { .aspect-grid, .metric-grid { grid-template-columns:1fr; } }
658
  """
659
 
660
 
 
9
  from functools import lru_cache
10
  from pathlib import Path
11
  from typing import Any, Dict, List, Tuple
12
+ from urllib.parse import quote_plus
13
 
14
  try:
15
  import huggingface_hub as _hf_hub
 
165
  "category": category,
166
  "features": features,
167
  "categories": categories,
168
+ "image_url": str(item.get("image_url") or item.get("image") or item.get("main_image") or ""),
169
+ "store": str(item.get("store") or item.get("brand") or "Amazon"),
170
+ "parent_asin": str(item.get("parent_asin") or item.get("asin") or "-"),
171
  "price": _safe_float(item.get("price")),
172
  "average_rating": _safe_float(item.get("average_rating")),
173
  "rating_number": _safe_float(item.get("rating_number")),
 
256
  return next((p for p in PRODUCTS if p["name"] == name), PRODUCTS[0])
257
 
258
 
259
+ def _product_image_url(product: Dict[str, Any]) -> str:
260
+ image_url = str(product.get("image_url") or "").strip()
261
+ if image_url:
262
+ return image_url
263
+ query = quote_plus(" ".join([
264
+ str(product.get("category") or "clothing"),
265
+ str(product.get("tags", ["fashion"])[0] if product.get("tags") else "fashion"),
266
+ "product"
267
+ ]))
268
+ return f"https://source.unsplash.com/320x420/?{query}"
269
+
270
+
271
  def _meta(product_or_meta: Dict[str, Any]) -> Dict[str, Any]:
272
  return {
273
  "features_text": product_or_meta.get("features", product_or_meta.get("features_text", "")),
 
420
  result = _predict_product(product_name)
421
  except Exception:
422
  return _error_html(traceback.format_exc(limit=5)), "", "", []
423
+ image_html = (
424
+ f'<img class="product-img" src="{_esc(_product_image_url(product))}" '
425
+ f'alt="{_esc(product["name"])} product image" loading="lazy">'
426
+ )
427
+ store = product.get("store") or "Amazon"
428
+ asin = product.get("parent_asin") or "-"
429
+ detail = (
430
+ f'<div class="product-card product-layout">{image_html}<div>'
431
+ f'<h3>{_esc(product["name"])}</h3>'
432
+ f'<p class="muted">{_esc(product["categories"])}</p>'
433
+ f'<div class="meta-pills"><span>Store: {_esc(store)}</span>'
434
+ f'<span>ASIN: {_esc(asin)}</span>'
435
+ f'<span>Source: {_esc(product.get("source", "demo"))}</span>'
436
+ f'<span>Price: ${_safe_float(product["price"]):.2f}</span>'
437
+ f'<span>Rating: {_safe_float(product["average_rating"]):.1f}</span>'
438
+ f'<span>Reviews: {int(_safe_float(product["rating_number"]))}</span></div>'
439
+ f'<p><b>Metadata:</b> {_esc(product["features"])}</p>'
440
+ f'{_recommendation_html(result, product["name"])}{_overall_html(result)}</div></div>'
441
+ )
442
  evidence = f'<h4>Key review evidence</h4>{_highlight_review(product["review"], selected_aspect)}'
443
  return detail, _aspect_cards(result, product["review"], selected_aspect), evidence, _aspect_rows(result, product["review"])
444
 
 
656
  .status.ok { background:#ecfdf5; border-color:#86efac; color:#065f46; }
657
  .status.bad { background:#fff1f2; border-color:#fda4af; color:#991b1b; }
658
  .product-card, .overall-card, .note-card { border:1px solid var(--line); border-radius:8px; padding:16px; background:white; }
659
+ .product-layout { display:grid; grid-template-columns:132px 1fr; gap:16px; align-items:start; }
660
+ .product-img { width:132px; height:166px; object-fit:cover; border-radius:8px; border:1px solid var(--line); background:#f8fafc; }
661
  .recommendation-card { border:1px solid #fed7aa; border-left:5px solid var(--accent); background:#fff7ed; border-radius:8px; padding:13px 14px; margin:12px 0; }
662
  .recommendation-card p { margin:7px 0 0; }
663
  .muted { color:var(--muted); }
 
690
  .kv-table td { border-bottom:1px solid #e2e8f0; padding:9px 12px; }
691
  .kv-table td:first-child { width:220px; color:#334155; font-weight:700; background:#f8fafc; }
692
  .compact-note { color:#475569; font-size:13px; margin:4px 0 10px; }
693
+ @media (max-width:860px) { .aspect-grid, .metric-grid, .product-layout { grid-template-columns:1fr; } .product-img { width:100%; height:220px; } }
694
  """
695
 
696