Spaces:
Sleeping
Sleeping
Upload app.py
Browse files
app.py
CHANGED
|
@@ -7,7 +7,7 @@ df = pd.read_csv("offers_with_prices.csv")
|
|
| 7 |
df.columns = [c.strip().lower() for c in df.columns]
|
| 8 |
|
| 9 |
# normalize key fields if necessary
|
| 10 |
-
for col in ["country","dealer","brand","model","trim_or_variant","starting_price","heading","offer_description","vehicle_offer_url"]:
|
| 11 |
if col not in df.columns:
|
| 12 |
df[col] = ""
|
| 13 |
|
|
@@ -44,22 +44,23 @@ def generate_cards_html(df_filtered):
|
|
| 44 |
return f"""
|
| 45 |
<html><head>
|
| 46 |
<style>
|
| 47 |
-
|
|
|
|
| 48 |
.cards{{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:18px;}}
|
| 49 |
-
.card{{background:
|
| 50 |
overflow:hidden;box-shadow:0 4px 12px rgba(0,0,0,.06);
|
| 51 |
cursor:pointer;transition:transform .08s ease,box-shadow .2s ease;}}
|
| 52 |
.card:hover{{transform:translateY(-2px);box-shadow:0 8px 20px rgba(0,0,0,.12);}}
|
| 53 |
.thumb{{height:160px;overflow:hidden;background:#000;}}
|
| 54 |
.thumb img{{width:100%;height:100%;object-fit:cover;}}
|
| 55 |
.body{{padding:12px;display:flex;flex-direction:column;gap:6px;}}
|
| 56 |
-
.sp{{font-size:13px;color:
|
| 57 |
-
.sp strong{{display:block;font-size:20px;color:
|
| 58 |
-
.heading{{font-weight:700;color:
|
| 59 |
-
.offer{{color:
|
| 60 |
display:-webkit-box;-webkit-line-clamp:4;-webkit-box-orient:vertical;overflow:hidden;}}
|
| 61 |
.meta{{display:flex;gap:6px;flex-wrap:wrap;padding:0 12px 12px;}}
|
| 62 |
-
.chip{{font-size:11px;color:#374151;background:
|
| 63 |
</style></head>
|
| 64 |
<body><div class="cards">{cards}</div></body></html>
|
| 65 |
"""
|
|
@@ -83,7 +84,17 @@ def app():
|
|
| 83 |
brands = ["All"] + sorted(df["brand"].dropna().astype(str).unique().tolist())
|
| 84 |
dealers = ["All"] + sorted(df["dealer"].dropna().astype(str).unique().tolist())
|
| 85 |
|
| 86 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 87 |
gr.Markdown("## 🚗 Vehicle Offers Explorer")
|
| 88 |
|
| 89 |
with gr.Row():
|
|
@@ -92,10 +103,12 @@ def app():
|
|
| 92 |
dealer = gr.Dropdown(choices=dealers, label="Dealer", value="All")
|
| 93 |
limit = gr.Slider(6, 200, value=30, step=6, label="Max Offers")
|
| 94 |
|
| 95 |
-
|
|
|
|
|
|
|
| 96 |
btn = gr.Button("Show Offers", variant="primary")
|
| 97 |
btn.click(fn=filter_offers, inputs=[country, brand, dealer, limit], outputs=output)
|
| 98 |
-
|
| 99 |
return demo
|
| 100 |
|
| 101 |
if __name__ == "__main__":
|
|
|
|
| 7 |
df.columns = [c.strip().lower() for c in df.columns]
|
| 8 |
|
| 9 |
# normalize key fields if necessary
|
| 10 |
+
for col in ["country","dealer","brand","model","trim_or_variant","starting_price","heading","offer_description","vehicle_offer_url","images"]:
|
| 11 |
if col not in df.columns:
|
| 12 |
df[col] = ""
|
| 13 |
|
|
|
|
| 44 |
return f"""
|
| 45 |
<html><head>
|
| 46 |
<style>
|
| 47 |
+
:root{{ --bg:#f6f7fb; --card:#ffffff; --ink:#111827; --muted:#6b7280; --line:#e5e7eb; --chip:#e5e7eb; }}
|
| 48 |
+
body{{background:var(--bg);font-family:Inter, Segoe UI, Roboto, Helvetica, Arial, sans-serif; margin:0;}}
|
| 49 |
.cards{{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:18px;}}
|
| 50 |
+
.card{{background:var(--card);border:1px solid var(--line);border-radius:16px;
|
| 51 |
overflow:hidden;box-shadow:0 4px 12px rgba(0,0,0,.06);
|
| 52 |
cursor:pointer;transition:transform .08s ease,box-shadow .2s ease;}}
|
| 53 |
.card:hover{{transform:translateY(-2px);box-shadow:0 8px 20px rgba(0,0,0,.12);}}
|
| 54 |
.thumb{{height:160px;overflow:hidden;background:#000;}}
|
| 55 |
.thumb img{{width:100%;height:100%;object-fit:cover;}}
|
| 56 |
.body{{padding:12px;display:flex;flex-direction:column;gap:6px;}}
|
| 57 |
+
.sp{{font-size:13px;color:var(--muted);}}
|
| 58 |
+
.sp strong{{display:block;font-size:20px;color:var(--ink);margin-top:2px;}}
|
| 59 |
+
.heading{{font-weight:700;color:var(--ink);font-size:15px;line-height:1.25;}}
|
| 60 |
+
.offer{{color:var(--ink);font-size:13px;line-height:1.4;opacity:.9;
|
| 61 |
display:-webkit-box;-webkit-line-clamp:4;-webkit-box-orient:vertical;overflow:hidden;}}
|
| 62 |
.meta{{display:flex;gap:6px;flex-wrap:wrap;padding:0 12px 12px;}}
|
| 63 |
+
.chip{{font-size:11px;color:#374151;background:var(--chip);border-radius:999px;padding:4px 8px;}}
|
| 64 |
</style></head>
|
| 65 |
<body><div class="cards">{cards}</div></body></html>
|
| 66 |
"""
|
|
|
|
| 84 |
brands = ["All"] + sorted(df["brand"].dropna().astype(str).unique().tolist())
|
| 85 |
dealers = ["All"] + sorted(df["dealer"].dropna().astype(str).unique().tolist())
|
| 86 |
|
| 87 |
+
custom_css = """
|
| 88 |
+
/* Force consistent font across the whole Space */
|
| 89 |
+
body, .gradio-container, .gr-block, .gr-button, .gr-input, .gr-dropdown,
|
| 90 |
+
.gradio-container * {
|
| 91 |
+
font-family: Inter, Segoe UI, Roboto, Helvetica, Arial, sans-serif !important;
|
| 92 |
+
}
|
| 93 |
+
/* Give the HTML output a fixed viewport height with scrolling */
|
| 94 |
+
#cards-pane { height: 800px; overflow: auto; border-radius: 10px; }
|
| 95 |
+
"""
|
| 96 |
+
|
| 97 |
+
with gr.Blocks(title="Vehicle Offers", css=custom_css) as demo:
|
| 98 |
gr.Markdown("## 🚗 Vehicle Offers Explorer")
|
| 99 |
|
| 100 |
with gr.Row():
|
|
|
|
| 103 |
dealer = gr.Dropdown(choices=dealers, label="Dealer", value="All")
|
| 104 |
limit = gr.Slider(6, 200, value=30, step=6, label="Max Offers")
|
| 105 |
|
| 106 |
+
# NOTE: use elem_id + Blocks(css=...) instead of HTML.style(...)
|
| 107 |
+
output = gr.HTML(elem_id="cards-pane")
|
| 108 |
+
|
| 109 |
btn = gr.Button("Show Offers", variant="primary")
|
| 110 |
btn.click(fn=filter_offers, inputs=[country, brand, dealer, limit], outputs=output)
|
| 111 |
+
|
| 112 |
return demo
|
| 113 |
|
| 114 |
if __name__ == "__main__":
|