File size: 6,102 Bytes
e297a6f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
"""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 "<p>No products to display</p>"
    
    # 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 = ["<div style='font-family: system-ui, sans-serif; background: #1a1a1a; padding: 1rem; border-radius: 0.5rem;'>"]
    
    # 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("<h3 style='color: #ffffff; margin-bottom: 1rem;'>Products ({})</h3>".format(len(all_products)))
        html_parts.append("<div style='display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 1rem; margin-bottom: 2rem;'>")
        for _, product in all_products.iterrows():
            html_parts.append(_build_card(product, "match", has_requirements))
        html_parts.append("</div>")
    
    html_parts.append("</div>")
    
    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 = "<div style='margin-top: 0.5rem; font-size: 0.85rem;'>"
            for req_item in confirmed_features:
                req_text = req_item.get("req", "")
                req_html += f"<div style='color: #4ade80;'>✓ {req_text}</div>"  # Light green checkmark
            req_html += "</div>"
    
    # Clickable thumbnail
    thumbnail_html = ""
    if thumbnail and link:
        thumbnail_html = f'<a href="{link}" target="_blank"><img src="{thumbnail}" style="width: 100%; height: 200px; object-fit: contain; margin-bottom: 0.75rem; cursor: pointer; transition: opacity 0.2s;" onmouseover="this.style.opacity=\'0.8\'" onmouseout="this.style.opacity=\'1\'" /></a>'
    elif thumbnail:
        thumbnail_html = f'<img src="{thumbnail}" style="width: 100%; height: 200px; object-fit: contain; margin-bottom: 0.75rem;" />'
    
    card_html = f"""
    <div style='border: 2px solid {colors["border"]}; border-radius: 0.5rem; padding: 1rem; background: {colors["bg"]};'>
        {thumbnail_html}
        <h4 style='margin: 0 0 0.5rem 0; font-size: 0.95rem; line-height: 1.3; color: {colors["text"]};'>{title}</h4>
        <div style='display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.5rem;'>
            <span style='font-weight: bold; font-size: 1.25rem; color: {colors["price"]};'>${price:.2f}</span>
            <span style='font-size: 0.85rem; color: #a0a0a0;'>{source}</span>
        </div>
        {f'<div style="margin-bottom: 0.5rem; font-size: 0.85rem; color: #d0d0d0;">⭐ {rating} ({reviews} reviews)</div>' if rating else ''}
        {req_html}
    </div>
    """
    
    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)