Yoel125 commited on
Commit
8d6418d
·
verified ·
1 Parent(s): 6692892

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +37 -65
app.py CHANGED
@@ -13,20 +13,11 @@ import spaces # <--- Import the Hugging Face spaces library for Free GPU
13
  # --- 1. LOAD GENERATIVE AI COMPONENT ---
14
  device = "cuda" if torch.cuda.is_available() else "cpu"
15
  print(f"Loading GenAI Component on {device}...")
 
16
  # Using the smarter base model for high-quality text generation
17
  gen_tokenizer = AutoTokenizer.from_pretrained("google/flan-t5-base")
18
  gen_model = AutoModelForSeq2SeqLM.from_pretrained("google/flan-t5-base").to(device)
19
 
20
- # THE FIX for "the pitch changes every time I search":
21
- # from_pretrained() does NOT put the model in inference mode by default, so its
22
- # dropout layers stay active and randomly perturb every forward pass -- meaning
23
- # the model can genuinely produce a different sentence for the exact same company
24
- # and query, even with do_sample=False. Calling .eval() turns dropout off, which
25
- # combined with do_sample=False/num_beams below makes generation fully deterministic:
26
- # same company + same query -> same pitch, every single time.
27
- gen_model.eval()
28
-
29
-
30
  def generate_sales_pitch(user_query, company_name, sector, theme, description):
31
  # Feeding the company's description to the AI so it knows exactly what it's selling
32
  prompt = (
@@ -34,29 +25,26 @@ def generate_sales_pitch(user_query, company_name, sector, theme, description):
34
  f"Write one single, highly persuasive sentence explaining why investing in {company_name} "
35
  f"is the perfect choice for someone looking for '{user_query}'."
36
  )
 
37
  try:
38
  inputs = gen_tokenizer(prompt, return_tensors="pt", max_length=256, truncation=True).to(device)
39
- # Extra safety net: pin the RNG state right before generation too, in case any
40
- # part of the model still touches it. With eval() already set this is now
41
- # belt-and-suspenders, not the primary fix -- but it costs nothing to keep.
42
- torch.manual_seed(42)
43
- # do_sample=False and num_beams=4 make the AI mathematically find the single
44
- # "best" response and lock it in every time, instead of rolling dice on each call.
45
- with torch.no_grad():
46
- outputs = gen_model.generate(
47
- **inputs,
48
- max_new_tokens=60,
49
- do_sample=False,
50
- num_beams=4,
51
- repetition_penalty=2.0,
52
- early_stopping=True
53
- )
54
- pitch = gen_tokenizer.decode(outputs[0], skip_special_tokens=True)
55
 
 
 
 
 
 
 
 
 
 
 
 
 
56
  # Clean up any leftover prompt artifacts
57
  pitch = pitch.replace("Based on this company description:", "").strip()
58
  return pitch
59
-
60
  except Exception:
61
  return f"{company_name} is an exceptional strategic match for '{user_query}' within the {sector} space."
62
 
@@ -78,15 +66,15 @@ if 'faiss_index' not in globals():
78
  faiss_index = faiss.IndexFlatL2(embeddings.shape[1])
79
  faiss_index.add(np.array(embeddings).astype('float32'))
80
  except FileNotFoundError:
81
- print("Saved embeddings not found, encoding from scratch...")
82
  embeddings = embedding_model.encode(df['full_text'].tolist(), show_progress_bar=False)
83
  faiss_index = faiss.IndexFlatL2(embeddings.shape[1])
84
  faiss_index.add(np.array(embeddings).astype('float32'))
85
 
 
86
  # --- 3. RECOMMENDATION ENGINE LOGIC ---
87
  all_sectors = ["All Sectors"] + sorted(list(df['sector'].unique()))
88
 
89
-
90
  @spaces.GPU # <--- Hugging Face ZeroGPU Decorator!
91
  def recommend_investment(user_query, selected_sector, top_k=3):
92
  # 1. Check if completely empty
@@ -98,7 +86,7 @@ def recommend_investment(user_query, selected_sector, top_k=3):
98
  if user_query and str(user_query).strip():
99
  non_english_chars = sum(1 for char in str(user_query) if ord(char) > 127)
100
  if non_english_chars > 2:
101
- yield "⚠️ *Language Not Supported:* SectorSync AI is currently optimized exclusively for English data. Please write your investment thesis in English and try again."
102
  return
103
 
104
  # 3. Auto-fill sector if text box is empty
@@ -134,9 +122,9 @@ def recommend_investment(user_query, selected_sector, top_k=3):
134
  sim_score = 1 / (1 + distances[0][i])
135
  matches.append((df.iloc[idx], sim_score))
136
 
137
- output_markdown = f"### Top {len(matches)} AI-Recommended Matches for: '{user_query}'\n\n"
138
  if selected_sector != "All Sectors":
139
- output_markdown += f"*Filtered by Sector:* ⁠ {selected_sector} ⁠\n\n---\n\n"
140
  else:
141
  output_markdown += "---\n\n"
142
 
@@ -157,18 +145,18 @@ def recommend_investment(user_query, selected_sector, top_k=3):
157
  tier_label = match_labels[rank - 1] if rank <= len(match_labels) else "Match"
158
 
159
  # The Fix: No bullet points, reads like a clean, professional report!
160
- output_markdown += f"#### #{rank}. {c_name} (⁠ {ticker} ⁠) — {sector}\n\n"
161
- output_markdown += f"*{tier_label}* (Similarity Score: ⁠ {score*100:.1f}% ⁠)\n\n"
162
- output_markdown += f"*Industry:* {theme}\n\n"
163
- output_markdown += f"*GenAI Investment Pitch:* '{pitch}'\n\n"
164
- output_markdown += f"*Company Overview:* {desc[:200]}...\n\n---\n\n"
165
 
166
  # Streams the results instantly!
167
  yield output_markdown
168
 
169
 
170
  # --- 4. GRADIO USER INTERFACE ---
171
- # Native Gradio Dark Theme to fix the white boxes.
172
  custom_theme = gr.themes.Base(
173
  primary_hue="emerald",
174
  neutral_hue="slate"
@@ -189,40 +177,25 @@ custom_theme = gr.themes.Base(
189
  block_label_text_color_dark="#f0f4f8",
190
  input_background_fill="#2a2a2a",
191
  input_background_fill_dark="#2a2a2a",
192
- input_border_color="#333333",
193
- input_border_color_dark="#333333",
194
- input_placeholder_color="#9ca3af",
195
- input_placeholder_color_dark="#9ca3af",
196
  button_primary_background_fill="#10b981",
197
  button_primary_background_fill_dark="#10b981",
198
  button_primary_text_color="#121212",
199
  button_primary_text_color_dark="#121212",
200
- # THE FIX for "the table is still white": the Quick Starters examples list
201
- # renders as a table, and the theme's generic background tokens above don't
202
- # touch it -- it has its own dedicated table_* tokens that must be set separately.
203
- table_even_background_fill="#1a1a1a",
204
- table_even_background_fill_dark="#1a1a1a",
205
- table_odd_background_fill="#242424",
206
- table_odd_background_fill_dark="#242424",
207
  table_border_color="#333333",
208
- table_border_color_dark="#333333",
209
  )
210
 
211
- # Belt-and-suspenders CSS in case this Gradio version's Examples table doesn't
212
- # fully respect the table_* theme tokens above -- forces its background/text
213
- # directly regardless of theme token coverage.
214
- table_css = """
215
- table, table.dataset, tbody, thead, tr, td, th {
216
- background-color: #1a1a1a !important;
217
- color: #f0f4f8 !important;
218
- border-color: #333333 !important;
219
- }
220
- """
221
-
222
- with gr.Blocks(theme=custom_theme, css=table_css, title="SectorSync AI") as demo:
223
  gr.Markdown("# SectorSync AI")
224
  gr.Markdown("Cut Through the Market Noise — Find Your Next Winning Stock in Seconds. Discover high-growth companies matching your investment thesis using FAISS Vector Search and Generative AI.")
225
- gr.Markdown("Similarity Score reflects how closely a company profile matches your query in AI-embedding space — a relative ranking signal, not a calibrated financial confidence rating.")
226
 
227
  with gr.Row():
228
  with gr.Column(scale=2):
@@ -255,7 +228,6 @@ with gr.Blocks(theme=custom_theme, css=table_css, title="SectorSync AI") as demo
255
  search_button.click(fn=recommend_investment, inputs=[query_input, sector_dropdown], outputs=results_output)
256
  query_input.submit(fn=recommend_investment, inputs=[query_input, sector_dropdown], outputs=results_output)
257
 
258
- if _name_ == "_main_":
259
  print("Launching SectorSync AI Recommender App...")
260
- # share=False is best for Hugging Face spaces
261
  demo.launch(share=False)
 
13
  # --- 1. LOAD GENERATIVE AI COMPONENT ---
14
  device = "cuda" if torch.cuda.is_available() else "cpu"
15
  print(f"Loading GenAI Component on {device}...")
16
+
17
  # Using the smarter base model for high-quality text generation
18
  gen_tokenizer = AutoTokenizer.from_pretrained("google/flan-t5-base")
19
  gen_model = AutoModelForSeq2SeqLM.from_pretrained("google/flan-t5-base").to(device)
20
 
 
 
 
 
 
 
 
 
 
 
21
  def generate_sales_pitch(user_query, company_name, sector, theme, description):
22
  # Feeding the company's description to the AI so it knows exactly what it's selling
23
  prompt = (
 
25
  f"Write one single, highly persuasive sentence explaining why investing in {company_name} "
26
  f"is the perfect choice for someone looking for '{user_query}'."
27
  )
28
+
29
  try:
30
  inputs = gen_tokenizer(prompt, return_tensors="pt", max_length=256, truncation=True).to(device)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
 
32
+ # THE FIX: do_sample=False and num_beams=4 ensures the AI mathematically finds
33
+ # the single "best" response and locks it in every time without changing.
34
+ outputs = gen_model.generate(
35
+ **inputs,
36
+ max_new_tokens=60,
37
+ do_sample=False,
38
+ num_beams=4,
39
+ repetition_penalty=2.0,
40
+ early_stopping=True
41
+ )
42
+ pitch = gen_tokenizer.decode(outputs[0], skip_special_tokens=True)
43
+
44
  # Clean up any leftover prompt artifacts
45
  pitch = pitch.replace("Based on this company description:", "").strip()
46
  return pitch
47
+
48
  except Exception:
49
  return f"{company_name} is an exceptional strategic match for '{user_query}' within the {sector} space."
50
 
 
66
  faiss_index = faiss.IndexFlatL2(embeddings.shape[1])
67
  faiss_index.add(np.array(embeddings).astype('float32'))
68
  except FileNotFoundError:
69
+ print("Saved embeddings not scratch...")
70
  embeddings = embedding_model.encode(df['full_text'].tolist(), show_progress_bar=False)
71
  faiss_index = faiss.IndexFlatL2(embeddings.shape[1])
72
  faiss_index.add(np.array(embeddings).astype('float32'))
73
 
74
+
75
  # --- 3. RECOMMENDATION ENGINE LOGIC ---
76
  all_sectors = ["All Sectors"] + sorted(list(df['sector'].unique()))
77
 
 
78
  @spaces.GPU # <--- Hugging Face ZeroGPU Decorator!
79
  def recommend_investment(user_query, selected_sector, top_k=3):
80
  # 1. Check if completely empty
 
86
  if user_query and str(user_query).strip():
87
  non_english_chars = sum(1 for char in str(user_query) if ord(char) > 127)
88
  if non_english_chars > 2:
89
+ yield "⚠️ **Language Not Supported:** SectorSync AI is currently optimized exclusively for English data. Please write your investment thesis in English and try again."
90
  return
91
 
92
  # 3. Auto-fill sector if text box is empty
 
122
  sim_score = 1 / (1 + distances[0][i])
123
  matches.append((df.iloc[idx], sim_score))
124
 
125
+ output_markdown = f"### Top {len(matches)} AI-Recommended Matches for: *'{user_query}'*\n\n"
126
  if selected_sector != "All Sectors":
127
+ output_markdown += f"**Filtered by Sector:** `{selected_sector}`\n\n---\n\n"
128
  else:
129
  output_markdown += "---\n\n"
130
 
 
145
  tier_label = match_labels[rank - 1] if rank <= len(match_labels) else "Match"
146
 
147
  # The Fix: No bullet points, reads like a clean, professional report!
148
+ output_markdown += f"#### #{rank}. {c_name} (`{ticker}`) — *{sector}*\n\n"
149
+ output_markdown += f"**{tier_label}** (Similarity Score: `{score*100:.1f}%`)\n\n"
150
+ output_markdown += f"**Industry:** {theme}\n\n"
151
+ output_markdown += f"**GenAI Investment Pitch:** *'{pitch}'*\n\n"
152
+ output_markdown += f"**Company Overview:** {desc[:200]}...\n\n---\n\n"
153
 
154
  # Streams the results instantly!
155
  yield output_markdown
156
 
157
 
158
  # --- 4. GRADIO USER INTERFACE ---
159
+ # Instead of CSS hacks, we build a native Gradio Dark Theme to fix the white boxes!
160
  custom_theme = gr.themes.Base(
161
  primary_hue="emerald",
162
  neutral_hue="slate"
 
177
  block_label_text_color_dark="#f0f4f8",
178
  input_background_fill="#2a2a2a",
179
  input_background_fill_dark="#2a2a2a",
 
 
 
 
180
  button_primary_background_fill="#10b981",
181
  button_primary_background_fill_dark="#10b981",
182
  button_primary_text_color="#121212",
183
  button_primary_text_color_dark="#121212",
184
+ # THE TABLE FIX: Hard-locking the table colors to dark mode grays for everyone
185
+ table_even_background_fill="#1e1e1e",
186
+ table_even_background_fill_dark="#1e1e1e",
187
+ table_odd_background_fill="#121212",
188
+ table_odd_background_fill_dark="#121212",
189
+ table_row_focus_fill="#2a2a2a",
190
+ table_row_focus_fill_dark="#2a2a2a",
191
  table_border_color="#333333",
192
+ table_border_color_dark="#333333"
193
  )
194
 
195
+ with gr.Blocks(theme=custom_theme, title="SectorSync AI") as demo:
 
 
 
 
 
 
 
 
 
 
 
196
  gr.Markdown("# SectorSync AI")
197
  gr.Markdown("Cut Through the Market Noise — Find Your Next Winning Stock in Seconds. Discover high-growth companies matching your investment thesis using FAISS Vector Search and Generative AI.")
198
+ gr.Markdown("*Similarity Score reflects how closely a company profile matches your query in AI-embedding space — a relative ranking signal, not a calibrated financial confidence rating.*")
199
 
200
  with gr.Row():
201
  with gr.Column(scale=2):
 
228
  search_button.click(fn=recommend_investment, inputs=[query_input, sector_dropdown], outputs=results_output)
229
  query_input.submit(fn=recommend_investment, inputs=[query_input, sector_dropdown], outputs=results_output)
230
 
231
+ if __name__ == "__main__":
232
  print("Launching SectorSync AI Recommender App...")
 
233
  demo.launch(share=False)