Levimichael4 commited on
Commit
2e4b33e
·
verified ·
1 Parent(s): 76f7626

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +28 -23
app.py CHANGED
@@ -26,14 +26,12 @@ NUM = [
26
  def ensure_emb():
27
  if not (os.path.exists('emb_text.npy') and os.path.exists('emb_num.npy')):
28
  from sentence_transformers import SentenceTransformer
29
- # text
30
  m = SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2')
31
  te = m.encode(DF['text_record'].astype(str).tolist(),
32
  batch_size=256, show_progress_bar=True, normalize_embeddings=True)
33
  np.save('emb_text.npy', np.asarray(te, dtype='float32'))
34
- # numeric (invert 0-100 time)
35
  X = DF[NUM].copy()
36
- X['zero_to_100_kmh_s'] = -X['zero_to_100_kmh_s']
37
  Xs = StandardScaler().fit_transform(X.values.astype('float32'))
38
  np.save('emb_num.npy', Xs.astype('float32'))
39
  return np.load('emb_text.npy'), np.load('emb_num.npy')
@@ -49,17 +47,15 @@ def _map():
49
  'years': sorted(g2['year'].astype(int).unique().tolist())
50
  }
51
  return m
52
-
53
  MAP = _map()
54
 
55
- def models_for(mk):
56
- return sorted(MAP.get(mk, {}).keys()) if mk else []
57
 
58
  def trim_year(mk, md):
59
  d = MAP.get(mk, {}).get(md, {})
60
  return d.get('trims', []), d.get('years', [])
61
 
62
- # ---------- helpers ----------
63
  def anchor_row(mk, md, tr, yr):
64
  sub = DF.copy()
65
  if mk: sub = sub[sub['make'] == mk]
@@ -69,13 +65,12 @@ def anchor_row(mk, md, tr, yr):
69
  if sub.empty: return None
70
  return sub.sort_values('popularity_score', ascending=False).iloc[0]
71
 
72
- def apply_filters(df, body, fuel, yr_rng, price, safety, rel):
73
  out = df.copy()
74
  if body != 'Any': out = out[out['body_type'] == body]
75
  if fuel != 'Any': out = out[out['fuel'] == fuel]
76
- y0, y1 = yr_rng; p0, p1 = price
77
- out = out[(out['year'] >= y0) & (out['year'] <= y1)]
78
- out = out[(out['price_usd'] >= p0) & (out['price_usd'] <= p1)]
79
  out = out[(out['safety_rating'] >= safety) & (out['reliability_score'] >= rel)]
80
  return out
81
 
@@ -91,11 +86,12 @@ def fmt_card(r):
91
  f"Reliability {int(r['reliability_score'])}/100 • Safety {int(r['safety_rating'])}★"
92
  )
93
 
94
- def recommend(mk, md, tr, yr, topk, alpha, body, fuel, yr_rng, price, safety, rel):
 
95
  a = anchor_row(mk, md, tr, yr)
96
  if a is None:
97
  return "No match for that combo.", None, None
98
- sub = apply_filters(DF, body, fuel, yr_rng, price, safety, rel)
99
  if sub.empty:
100
  return "No cars after filters.", None, None
101
 
@@ -121,7 +117,7 @@ def recommend(mk, md, tr, yr, topk, alpha, body, fuel, yr_rng, price, safety, re
121
  'ownership_cost_score','safety_rating','similarity_%']
122
  return fmt_card(a), sel[cols], f"α = {alpha:.2f} (text ↔ numeric)"
123
 
124
- # ---------- UI ----------
125
  with gr.Blocks() as demo:
126
  gr.Markdown("# RideSearch — pick a car, get similar across brands")
127
 
@@ -136,18 +132,25 @@ with gr.Blocks() as demo:
136
  t, y = trim_year(a,b); return t, y
137
  md.change(_up, [mk, md], [tr, yr])
138
 
 
 
 
139
  with gr.Row():
140
  body = gr.Dropdown(['Any']+sorted(DF['body_type'].unique().tolist()), value='Any', label='Body')
141
  fuel = gr.Dropdown(['Any']+sorted(DF['fuel'].unique().tolist()), value='Any', label='Fuel')
142
- yr_rng = gr.RangeSlider(int(DF['year'].min()), int(DF['year'].max()),
143
- value=[int(DF['year'].min()), int(DF['year'].max())],
144
- step=1, label='Year range')
 
 
 
 
 
 
145
  with gr.Row():
146
- price = gr.RangeSlider(int(DF['price_usd'].min()), int(DF['price_usd'].max()),
147
- value=[int(DF['price_usd'].min()), min(int(DF['price_usd'].max()), 60000)],
148
- step=500, label='Price (USD)')
149
  safety = gr.Slider(3,5,value=4,step=1,label='Min Safety ★')
150
  rel = gr.Slider(55,99,value=70,step=1,label='Min Reliability')
 
151
  with gr.Row():
152
  topk = gr.Slider(1,10,value=5,step=1,label='Recommendations')
153
  alpha = gr.Slider(0,1,value=0.7,step=0.05,label='α — Text vs Numeric')
@@ -157,9 +160,11 @@ with gr.Blocks() as demo:
157
  table = gr.Dataframe(interactive=False)
158
  note = gr.Markdown()
159
 
160
- go.click(recommend, [mk,md,tr,yr,topk,alpha,body,fuel,yr_rng,price,safety,rel],
161
- [anchor_md, table, note])
 
 
 
162
 
163
  # IMPORTANT for Hugging Face Spaces: do NOT call demo.launch()
164
- # Returning `demo` is enough:
165
  demo
 
26
  def ensure_emb():
27
  if not (os.path.exists('emb_text.npy') and os.path.exists('emb_num.npy')):
28
  from sentence_transformers import SentenceTransformer
 
29
  m = SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2')
30
  te = m.encode(DF['text_record'].astype(str).tolist(),
31
  batch_size=256, show_progress_bar=True, normalize_embeddings=True)
32
  np.save('emb_text.npy', np.asarray(te, dtype='float32'))
 
33
  X = DF[NUM].copy()
34
+ X['zero_to_100_kmh_s'] = -X['zero_to_100_kmh_s'] # smaller time = better
35
  Xs = StandardScaler().fit_transform(X.values.astype('float32'))
36
  np.save('emb_num.npy', Xs.astype('float32'))
37
  return np.load('emb_text.npy'), np.load('emb_num.npy')
 
47
  'years': sorted(g2['year'].astype(int).unique().tolist())
48
  }
49
  return m
 
50
  MAP = _map()
51
 
52
+ def models_for(mk): return sorted(MAP.get(mk, {}).keys()) if mk else []
 
53
 
54
  def trim_year(mk, md):
55
  d = MAP.get(mk, {}).get(md, {})
56
  return d.get('trims', []), d.get('years', [])
57
 
58
+ # ---------- filtering & rec ----------
59
  def anchor_row(mk, md, tr, yr):
60
  sub = DF.copy()
61
  if mk: sub = sub[sub['make'] == mk]
 
65
  if sub.empty: return None
66
  return sub.sort_values('popularity_score', ascending=False).iloc[0]
67
 
68
+ def apply_filters(df, body, fuel, y_min, y_max, p_min, p_max, safety, rel):
69
  out = df.copy()
70
  if body != 'Any': out = out[out['body_type'] == body]
71
  if fuel != 'Any': out = out[out['fuel'] == fuel]
72
+ out = out[(out['year'] >= y_min) & (out['year'] <= y_max)]
73
+ out = out[(out['price_usd'] >= p_min) & (out['price_usd'] <= p_max)]
 
74
  out = out[(out['safety_rating'] >= safety) & (out['reliability_score'] >= rel)]
75
  return out
76
 
 
86
  f"Reliability {int(r['reliability_score'])}/100 • Safety {int(r['safety_rating'])}★"
87
  )
88
 
89
+ def recommend(mk, md, tr, yr, topk, alpha,
90
+ body, fuel, y_min, y_max, p_min, p_max, safety, rel):
91
  a = anchor_row(mk, md, tr, yr)
92
  if a is None:
93
  return "No match for that combo.", None, None
94
+ sub = apply_filters(DF, body, fuel, int(y_min), int(y_max), int(p_min), int(p_max), int(safety), int(rel))
95
  if sub.empty:
96
  return "No cars after filters.", None, None
97
 
 
117
  'ownership_cost_score','safety_rating','similarity_%']
118
  return fmt_card(a), sel[cols], f"α = {alpha:.2f} (text ↔ numeric)"
119
 
120
+ # ---------- UI (no RangeSlider; use min/max sliders) ----------
121
  with gr.Blocks() as demo:
122
  gr.Markdown("# RideSearch — pick a car, get similar across brands")
123
 
 
132
  t, y = trim_year(a,b); return t, y
133
  md.change(_up, [mk, md], [tr, yr])
134
 
135
+ ylo, yhi = int(DF['year'].min()), int(DF['year'].max())
136
+ plo, phi = int(DF['price_usd'].min()), int(DF['price_usd'].max())
137
+
138
  with gr.Row():
139
  body = gr.Dropdown(['Any']+sorted(DF['body_type'].unique().tolist()), value='Any', label='Body')
140
  fuel = gr.Dropdown(['Any']+sorted(DF['fuel'].unique().tolist()), value='Any', label='Fuel')
141
+
142
+ with gr.Row():
143
+ y_min = gr.Slider(ylo, yhi, value=ylo, step=1, label='Year min')
144
+ y_max = gr.Slider(ylo, yhi, value=yhi, step=1, label='Year max')
145
+
146
+ with gr.Row():
147
+ p_min = gr.Slider(plo, phi, value=plo, step=500, label='Price min (USD)')
148
+ p_max = gr.Slider(plo, phi, value=min(phi, 60000), step=500, label='Price max (USD)')
149
+
150
  with gr.Row():
 
 
 
151
  safety = gr.Slider(3,5,value=4,step=1,label='Min Safety ★')
152
  rel = gr.Slider(55,99,value=70,step=1,label='Min Reliability')
153
+
154
  with gr.Row():
155
  topk = gr.Slider(1,10,value=5,step=1,label='Recommendations')
156
  alpha = gr.Slider(0,1,value=0.7,step=0.05,label='α — Text vs Numeric')
 
160
  table = gr.Dataframe(interactive=False)
161
  note = gr.Markdown()
162
 
163
+ go.click(
164
+ recommend,
165
+ [mk,md,tr,yr,topk,alpha,body,fuel,y_min,y_max,p_min,p_max,safety,rel],
166
+ [anchor_md, table, note]
167
+ )
168
 
169
  # IMPORTANT for Hugging Face Spaces: do NOT call demo.launch()
 
170
  demo