Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -253,15 +253,38 @@ def _stock_prompt(risks, style, r):
|
|
| 253 |
|
| 254 |
@spaces.GPU(duration=30)
|
| 255 |
def _generate_sentences(prompts):
|
| 256 |
-
"""The only function needing a real GPU, so the only one decorated.
|
| 257 |
-
|
| 258 |
-
|
| 259 |
-
|
| 260 |
-
|
| 261 |
-
|
| 262 |
-
|
| 263 |
-
|
| 264 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 265 |
|
| 266 |
def generate_rationale(risks, amount, sectors, markets, style, recs):
|
| 267 |
"""One sentence per stock, generated in a single batched pass. All factual
|
|
@@ -272,11 +295,12 @@ def generate_rationale(risks, amount, sectors, markets, style, recs):
|
|
| 272 |
{"role": "user", "content": _stock_prompt(risks, style, r)}],
|
| 273 |
tokenize=False, add_generation_prompt=True) for _, r in recs.iterrows()]
|
| 274 |
|
| 275 |
-
|
| 276 |
-
|
| 277 |
-
|
| 278 |
-
|
| 279 |
-
|
|
|
|
| 280 |
|
| 281 |
amt = parse_amount(amount)
|
| 282 |
rl = "/".join(_as_list(risks)).lower() or "flexible"
|
|
@@ -287,7 +311,7 @@ def generate_rationale(risks, amount, sectors, markets, style, recs):
|
|
| 287 |
lines = [f"Based on your {rl}-risk profile and {budget}, here are "
|
| 288 |
f"{len(recs)} stocks in {sec} from {mkt} matching your preferences.", ""]
|
| 289 |
for i, ((_, r), s) in enumerate(zip(recs.iterrows(), sents), 1):
|
| 290 |
-
sh
|
| 291 |
aff = f" ({sh} shares affordable)" if sh else ""
|
| 292 |
lines.append(f"{i}. **{r['ticker']}** β beta {r['beta']:.2f}, "
|
| 293 |
f"{r[DIV_COL]:.2f}% yield, {r['cagr_10yr_pct']:.1f}% growth, "
|
|
@@ -389,6 +413,10 @@ with gr.Blocks(title="StockMatch AI", theme=gr.themes.Soft()) as demo:
|
|
| 389 |
label="6. Company size")
|
| 390 |
go = gr.Button("π Find my stocks", variant="primary", size="lg")
|
| 391 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 392 |
gr.Markdown("### Results")
|
| 393 |
table = gr.Dataframe(label="Your matches", interactive=False, wrap=True)
|
| 394 |
text = gr.Markdown()
|
|
@@ -397,5 +425,6 @@ with gr.Blocks(title="StockMatch AI", theme=gr.themes.Soft()) as demo:
|
|
| 397 |
b1.click(lambda: run_quickstart("Cautious Retiree"), None, [table, text])
|
| 398 |
b2.click(lambda: run_quickstart("Balanced Professional"), None, [table, text])
|
| 399 |
b3.click(lambda: run_quickstart("Young Growth Seeker"), None, [table, text])
|
|
|
|
| 400 |
|
| 401 |
demo.launch()
|
|
|
|
| 253 |
|
| 254 |
@spaces.GPU(duration=30)
|
| 255 |
def _generate_sentences(prompts):
|
| 256 |
+
"""The only function needing a real GPU, so the only one decorated.
|
| 257 |
+
|
| 258 |
+
Errors are caught HERE and returned as data rather than raised. ZeroGPU
|
| 259 |
+
executes this in a separate worker process, and an exception crossing that
|
| 260 |
+
boundary arrives as a bare RuntimeError with its message stripped β which
|
| 261 |
+
makes diagnosis impossible. Returning the traceback preserves it.
|
| 262 |
+
"""
|
| 263 |
+
import traceback
|
| 264 |
+
try:
|
| 265 |
+
enc = gen_tok(prompts, return_tensors="pt", padding=True).to("cuda")
|
| 266 |
+
with torch.no_grad():
|
| 267 |
+
out = gen_model.generate(**enc, max_new_tokens=110, do_sample=True,
|
| 268 |
+
temperature=0.4, top_p=0.9,
|
| 269 |
+
repetition_penalty=1.1,
|
| 270 |
+
pad_token_id=gen_tok.pad_token_id)
|
| 271 |
+
sents = gen_tok.batch_decode(out[:, enc["input_ids"].shape[1]:],
|
| 272 |
+
skip_special_tokens=True)
|
| 273 |
+
return {"ok": True, "sentences": sents}
|
| 274 |
+
except Exception:
|
| 275 |
+
return {"ok": False, "traceback": traceback.format_exc()}
|
| 276 |
+
|
| 277 |
+
|
| 278 |
+
@spaces.GPU(duration=10)
|
| 279 |
+
def _gpu_selftest():
|
| 280 |
+
"""Diagnostic: does ZeroGPU work at all, independent of our model?
|
| 281 |
+
Isolates an infrastructure problem from a model-loading problem."""
|
| 282 |
+
import traceback
|
| 283 |
+
try:
|
| 284 |
+
x = torch.randn(4, 4).to("cuda")
|
| 285 |
+
return f"β
GPU OK β {torch.cuda.get_device_name(0)}, tensor on {x.device}"
|
| 286 |
+
except Exception:
|
| 287 |
+
return "β GPU FAILED\n```\n" + traceback.format_exc()[-1200:] + "\n```"
|
| 288 |
|
| 289 |
def generate_rationale(risks, amount, sectors, markets, style, recs):
|
| 290 |
"""One sentence per stock, generated in a single batched pass. All factual
|
|
|
|
| 295 |
{"role": "user", "content": _stock_prompt(risks, style, r)}],
|
| 296 |
tokenize=False, add_generation_prompt=True) for _, r in recs.iterrows()]
|
| 297 |
|
| 298 |
+
result = _generate_sentences(prompts)
|
| 299 |
+
if not result.get("ok"):
|
| 300 |
+
return ("_Recommendations above are complete. The written explanation "
|
| 301 |
+
"could not be generated._\n\n```\n"
|
| 302 |
+
+ result.get("traceback", "no traceback")[-1500:] + "\n```")
|
| 303 |
+
sents = result["sentences"]
|
| 304 |
|
| 305 |
amt = parse_amount(amount)
|
| 306 |
rl = "/".join(_as_list(risks)).lower() or "flexible"
|
|
|
|
| 311 |
lines = [f"Based on your {rl}-risk profile and {budget}, here are "
|
| 312 |
f"{len(recs)} stocks in {sec} from {mkt} matching your preferences.", ""]
|
| 313 |
for i, ((_, r), s) in enumerate(zip(recs.iterrows(), sents), 1):
|
| 314 |
+
sh = int(amt // r["price_usd"]) if (amt > 0 and r["price_usd"]) else None
|
| 315 |
aff = f" ({sh} shares affordable)" if sh else ""
|
| 316 |
lines.append(f"{i}. **{r['ticker']}** β beta {r['beta']:.2f}, "
|
| 317 |
f"{r[DIV_COL]:.2f}% yield, {r['cagr_10yr_pct']:.1f}% growth, "
|
|
|
|
| 413 |
label="6. Company size")
|
| 414 |
go = gr.Button("π Find my stocks", variant="primary", size="lg")
|
| 415 |
|
| 416 |
+
# Diagnostic only β remove before submitting.
|
| 417 |
+
gpu_btn = gr.Button("π§ Test GPU", variant="secondary", size="sm")
|
| 418 |
+
gpu_out = gr.Markdown()
|
| 419 |
+
|
| 420 |
gr.Markdown("### Results")
|
| 421 |
table = gr.Dataframe(label="Your matches", interactive=False, wrap=True)
|
| 422 |
text = gr.Markdown()
|
|
|
|
| 425 |
b1.click(lambda: run_quickstart("Cautious Retiree"), None, [table, text])
|
| 426 |
b2.click(lambda: run_quickstart("Balanced Professional"), None, [table, text])
|
| 427 |
b3.click(lambda: run_quickstart("Young Growth Seeker"), None, [table, text])
|
| 428 |
+
gpu_btn.click(_gpu_selftest, None, gpu_out)
|
| 429 |
|
| 430 |
demo.launch()
|