"""UI Components - Build HTML cards and tables with evaluation results.""" import pandas as pd def build_product_cards(df, evaluations): """ Build HTML cards for products grouped by verdict. Args: df: DataFrame with product data evaluations: List of evaluation dicts (same length as df) Returns: str: HTML string with product cards """ if df.empty: return "

No products to display

" # Add evaluation data to dataframe df = df.copy() df["verdict"] = [e.get("verdict", "possible") for e in evaluations] df["notes"] = [e.get("notes", "") for e in evaluations] df["requirements_met"] = [e.get("requirements_met", []) for e in evaluations] # Check if there are actual requirements to display has_requirements = any(e.get("requirements_met") for e in evaluations) # Group by verdict matches = df[df["verdict"] == "match"] possibles = df[df["verdict"] == "possible"] no_matches = df[df["verdict"] == "no_match"] html_parts = ["
"] # Show all products in a single grid - no verdict sections # Just show the products with their confirmed features (green checkmarks) all_products = pd.concat([matches, possibles, no_matches]) if not matches.empty or not possibles.empty or not no_matches.empty else pd.DataFrame() if not all_products.empty: html_parts.append("

Products ({})

".format(len(all_products))) html_parts.append("
") for _, product in all_products.iterrows(): html_parts.append(_build_card(product, "match", has_requirements)) html_parts.append("
") html_parts.append("
") return "\n".join(html_parts) def _build_card(product, verdict, has_requirements=True): """Build a single product card.""" # Dark theme - all cards get dark gray background colors = { "bg": "#2d2d2d", # Dark gray background "border": "#4a4a4a", # Slightly lighter gray border "text": "#ffffff", # White text "price": "#93c5fd" # Light blue for prices } # No verdict icons - checkmarks tell the story icon = "" title = product.get("title", "Unknown") price = product.get("price", 0) source = product.get("source", "") rating = product.get("rating", None) reviews = product.get("reviews", 0) link = product.get("link", "") thumbnail = product.get("thumbnail", "") notes = product.get("notes", "") requirements_met = product.get("requirements_met", []) # Build requirements checklist - ONLY show confirmed features (met) req_html = "" if has_requirements and requirements_met: confirmed_features = [r for r in requirements_met if r.get("status") == "met"] if confirmed_features: req_html = "
" for req_item in confirmed_features: req_text = req_item.get("req", "") req_html += f"
✓ {req_text}
" # Light green checkmark req_html += "
" # Clickable thumbnail thumbnail_html = "" if thumbnail and link: thumbnail_html = f'' elif thumbnail: thumbnail_html = f'' card_html = f"""
{thumbnail_html}

{title}

${price:.2f} {source}
{f'
⭐ {rating} ({reviews} reviews)
' if rating else ''} {req_html}
""" return card_html def build_comparison_table(df, evaluations): """ Build a comparison table with verdict column. Args: df: DataFrame with product data evaluations: List of evaluation dicts Returns: pd.DataFrame: DataFrame ready for gr.Dataframe """ if df.empty: return pd.DataFrame() display_df = df.copy() # Add verdict and notes columns display_df["Verdict"] = [e.get("verdict", "possible") for e in evaluations] display_df["AI Notes"] = [e.get("notes", "") for e in evaluations] # Select and rename columns for display (no URL column) columns_map = { "title": "Title", "price": "Price ($)", "source": "Store", "rating": "Rating", "reviews": "Reviews", "Verdict": "Verdict", "AI Notes": "AI Notes" } display_df = display_df[[c for c in columns_map.keys() if c in display_df.columns]] display_df = display_df.rename(columns=columns_map) # Sort by verdict priority (match, possible, no_match) verdict_order = {"match": 0, "possible": 1, "no_match": 2} display_df["_sort"] = display_df["Verdict"].map(verdict_order) display_df = display_df.sort_values("_sort").drop("_sort", axis=1) return display_df.reset_index(drop=True)