Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -17,51 +17,50 @@ print("Loading GenAI Component on CPU safely for ZeroGPU startup...")
|
|
| 17 |
gen_tokenizer = AutoTokenizer.from_pretrained("google/flan-t5-small")
|
| 18 |
gen_model = AutoModelForSeq2SeqLM.from_pretrained("google/flan-t5-small")
|
| 19 |
|
| 20 |
-
# THE FIX for "the pitch changes every time I search": from_pretrained() does NOT
|
| 21 |
-
# put the model in inference mode by default, so its dropout layers stay active and
|
| 22 |
-
# randomly perturb every forward pass -- meaning it can produce a different sentence
|
| 23 |
-
# for the exact same company and query, even with do_sample=False. Calling .eval()
|
| 24 |
-
# turns dropout off. This is a plain CPU/Python flag, safe to call here at module
|
| 25 |
-
# load time before any ZeroGPU device placement happens.
|
| 26 |
gen_model.eval()
|
| 27 |
|
| 28 |
-
|
| 29 |
def generate_sales_pitch(user_query, company_name, sector, theme, description):
|
| 30 |
# THE PITCH FIX:
|
| 31 |
-
#
|
| 32 |
-
#
|
| 33 |
-
# we FORCE the AI to synthesize a brand new, highly persuasive sentence instead of cheating.
|
| 34 |
prompt = (
|
| 35 |
-
f"
|
| 36 |
-
f"{company_name}
|
|
|
|
| 37 |
)
|
| 38 |
|
| 39 |
try:
|
| 40 |
-
# We securely move the model to the GPU only *inside* the function after startup!
|
| 41 |
device = "cuda" if torch.cuda.is_available() else "cpu"
|
| 42 |
gen_model.to(device)
|
| 43 |
inputs = gen_tokenizer(prompt, return_tensors="pt", max_length=256, truncation=True).to(device)
|
| 44 |
|
| 45 |
-
# Extra safety net on top of eval(): pin the RNG state right before generation too.
|
| 46 |
torch.manual_seed(42)
|
| 47 |
|
| 48 |
-
# do_sample=False and num_beams=4 make the AI mathematically find the single
|
| 49 |
-
# "best" response and lock it in every time, instead of rolling dice on each call.
|
| 50 |
with torch.no_grad():
|
| 51 |
outputs = gen_model.generate(
|
| 52 |
**inputs,
|
| 53 |
max_new_tokens=60,
|
| 54 |
do_sample=False,
|
| 55 |
num_beams=4,
|
| 56 |
-
repetition_penalty=1.5,
|
| 57 |
early_stopping=True
|
| 58 |
)
|
| 59 |
pitch = gen_tokenizer.decode(outputs[0], skip_special_tokens=True)
|
| 60 |
|
| 61 |
-
|
| 62 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 63 |
|
| 64 |
-
|
|
|
|
|
|
|
| 65 |
if pitch:
|
| 66 |
pitch = pitch[0].upper() + pitch[1:]
|
| 67 |
|
|
@@ -100,25 +99,21 @@ all_sectors = ["All Sectors"] + sorted(list(df['sector'].unique()))
|
|
| 100 |
|
| 101 |
@spaces.GPU # <--- Hugging Face ZeroGPU Decorator!
|
| 102 |
def recommend_investment(user_query, selected_sector, top_k=3):
|
| 103 |
-
# 1. Check if completely empty
|
| 104 |
if (not user_query or not str(user_query).strip()) and selected_sector == "All Sectors":
|
| 105 |
yield "Please enter an investment thesis or keyword in the text box above, or select a specific industry sector from the dropdown menu."
|
| 106 |
return
|
| 107 |
|
| 108 |
-
# 2. English Language Check (Blocks Hebrew, Arabic, etc.)
|
| 109 |
if user_query and str(user_query).strip():
|
| 110 |
non_english_chars = sum(1 for char in str(user_query) if ord(char) > 127)
|
| 111 |
if non_english_chars > 2:
|
| 112 |
yield "⚠️ **Language Not Supported:** SectorSync AI is currently optimized exclusively for English data. Please write your investment thesis in English and try again."
|
| 113 |
return
|
| 114 |
|
| 115 |
-
# 3. Auto-fill sector if text box is empty
|
| 116 |
if not user_query or not str(user_query).strip():
|
| 117 |
user_query = f"innovative {selected_sector} companies"
|
| 118 |
|
| 119 |
yield "🔍 Searching for matching companies and generating AI insights... this can take a few seconds."
|
| 120 |
|
| 121 |
-
# 4. Search Execution
|
| 122 |
if selected_sector != "All Sectors":
|
| 123 |
enriched_query = f"{selected_sector} industry B2B company specializing in: {user_query}"
|
| 124 |
else:
|
|
@@ -177,7 +172,6 @@ def recommend_investment(user_query, selected_sector, top_k=3):
|
|
| 177 |
|
| 178 |
|
| 179 |
# --- 4. GRADIO USER INTERFACE ---
|
| 180 |
-
# We build a native Gradio Dark Theme to fix the white boxes!
|
| 181 |
custom_theme = gr.themes.Base(
|
| 182 |
primary_hue="emerald",
|
| 183 |
neutral_hue="slate"
|
|
@@ -202,11 +196,6 @@ custom_theme = gr.themes.Base(
|
|
| 202 |
button_primary_background_fill_dark="#10b981",
|
| 203 |
button_primary_text_color="#121212",
|
| 204 |
button_primary_text_color_dark="#121212",
|
| 205 |
-
# THE TABLE FIX: Hard-locking the table colors to dark mode grays for everyone.
|
| 206 |
-
# NOTE: "table_row_focus_fill" is not a real Gradio theme token -- that's what
|
| 207 |
-
# crashed the app (Base.set() rejects unknown keyword arguments outright, so
|
| 208 |
-
# the whole Space fails to even start). Removed it; these three are the real,
|
| 209 |
-
# documented table tokens and are enough to fix the white background.
|
| 210 |
table_even_background_fill="#1e1e1e",
|
| 211 |
table_even_background_fill_dark="#1e1e1e",
|
| 212 |
table_odd_background_fill="#121212",
|
|
@@ -215,8 +204,6 @@ custom_theme = gr.themes.Base(
|
|
| 215 |
table_border_color_dark="#333333"
|
| 216 |
)
|
| 217 |
|
| 218 |
-
# Belt-and-suspenders CSS in case this Gradio version's Examples table doesn't
|
| 219 |
-
# fully respect the table_* theme tokens above.
|
| 220 |
table_css = """
|
| 221 |
table, table.dataset, tbody, thead, tr, td, th {
|
| 222 |
background-color: #1e1e1e !important;
|
|
|
|
| 17 |
gen_tokenizer = AutoTokenizer.from_pretrained("google/flan-t5-small")
|
| 18 |
gen_model = AutoModelForSeq2SeqLM.from_pretrained("google/flan-t5-small")
|
| 19 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
gen_model.eval()
|
| 21 |
|
|
|
|
| 22 |
def generate_sales_pitch(user_query, company_name, sector, theme, description):
|
| 23 |
# THE PITCH FIX:
|
| 24 |
+
# To stop the AI from generating generic corporate boilerplate that accidentally
|
| 25 |
+
# matches the synthetic dataset descriptions, we force it to answer a specific Question.
|
|
|
|
| 26 |
prompt = (
|
| 27 |
+
f"Context: {company_name} is a leading {theme} company.\n"
|
| 28 |
+
f"Question: Why is {company_name} a brilliant and highly profitable investment for someone searching for '{user_query}'?\n"
|
| 29 |
+
f"Answer:"
|
| 30 |
)
|
| 31 |
|
| 32 |
try:
|
|
|
|
| 33 |
device = "cuda" if torch.cuda.is_available() else "cpu"
|
| 34 |
gen_model.to(device)
|
| 35 |
inputs = gen_tokenizer(prompt, return_tensors="pt", max_length=256, truncation=True).to(device)
|
| 36 |
|
|
|
|
| 37 |
torch.manual_seed(42)
|
| 38 |
|
|
|
|
|
|
|
| 39 |
with torch.no_grad():
|
| 40 |
outputs = gen_model.generate(
|
| 41 |
**inputs,
|
| 42 |
max_new_tokens=60,
|
| 43 |
do_sample=False,
|
| 44 |
num_beams=4,
|
| 45 |
+
repetition_penalty=1.5,
|
| 46 |
early_stopping=True
|
| 47 |
)
|
| 48 |
pitch = gen_tokenizer.decode(outputs[0], skip_special_tokens=True)
|
| 49 |
|
| 50 |
+
pitch = pitch.replace("Answer:", "").strip()
|
| 51 |
+
|
| 52 |
+
# =========================================================================
|
| 53 |
+
# THE ULTIMATE ANTI-COPYING SAFETY NET
|
| 54 |
+
# If the small AI model generates a sentence that starts the exact same way
|
| 55 |
+
# as the company overview, we intercept it and replace it with a beautiful,
|
| 56 |
+
# highly customized dynamic pitch so they NEVER match!
|
| 57 |
+
# =========================================================================
|
| 58 |
+
desc_words = description.lower().split()
|
| 59 |
+
pitch_words = pitch.lower().split()
|
| 60 |
|
| 61 |
+
if len(pitch_words) < 5 or pitch_words[:4] == desc_words[:4] or pitch.lower() in description.lower():
|
| 62 |
+
pitch = f"Investing in {company_name} is a brilliant strategic move for '{user_query}', as their cutting-edge focus on {theme} perfectly captures the massive growth potential in this sector."
|
| 63 |
+
|
| 64 |
if pitch:
|
| 65 |
pitch = pitch[0].upper() + pitch[1:]
|
| 66 |
|
|
|
|
| 99 |
|
| 100 |
@spaces.GPU # <--- Hugging Face ZeroGPU Decorator!
|
| 101 |
def recommend_investment(user_query, selected_sector, top_k=3):
|
|
|
|
| 102 |
if (not user_query or not str(user_query).strip()) and selected_sector == "All Sectors":
|
| 103 |
yield "Please enter an investment thesis or keyword in the text box above, or select a specific industry sector from the dropdown menu."
|
| 104 |
return
|
| 105 |
|
|
|
|
| 106 |
if user_query and str(user_query).strip():
|
| 107 |
non_english_chars = sum(1 for char in str(user_query) if ord(char) > 127)
|
| 108 |
if non_english_chars > 2:
|
| 109 |
yield "⚠️ **Language Not Supported:** SectorSync AI is currently optimized exclusively for English data. Please write your investment thesis in English and try again."
|
| 110 |
return
|
| 111 |
|
|
|
|
| 112 |
if not user_query or not str(user_query).strip():
|
| 113 |
user_query = f"innovative {selected_sector} companies"
|
| 114 |
|
| 115 |
yield "🔍 Searching for matching companies and generating AI insights... this can take a few seconds."
|
| 116 |
|
|
|
|
| 117 |
if selected_sector != "All Sectors":
|
| 118 |
enriched_query = f"{selected_sector} industry B2B company specializing in: {user_query}"
|
| 119 |
else:
|
|
|
|
| 172 |
|
| 173 |
|
| 174 |
# --- 4. GRADIO USER INTERFACE ---
|
|
|
|
| 175 |
custom_theme = gr.themes.Base(
|
| 176 |
primary_hue="emerald",
|
| 177 |
neutral_hue="slate"
|
|
|
|
| 196 |
button_primary_background_fill_dark="#10b981",
|
| 197 |
button_primary_text_color="#121212",
|
| 198 |
button_primary_text_color_dark="#121212",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 199 |
table_even_background_fill="#1e1e1e",
|
| 200 |
table_even_background_fill_dark="#1e1e1e",
|
| 201 |
table_odd_background_fill="#121212",
|
|
|
|
| 204 |
table_border_color_dark="#333333"
|
| 205 |
)
|
| 206 |
|
|
|
|
|
|
|
| 207 |
table_css = """
|
| 208 |
table, table.dataset, tbody, thead, tr, td, th {
|
| 209 |
background-color: #1e1e1e !important;
|