nexusbert commited on
Commit
64f1083
·
verified ·
1 Parent(s): 7c2a41d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +55 -3
app.py CHANGED
@@ -63,7 +63,7 @@ SOCCER_LEAGUES = {
63
 
64
  def get_team_news(team: str, sport: str = "football"):
65
  url = f"https://news.google.com/search?q={team}+{sport}&hl=en"
66
- r = requests.get(url, headers={"User-Agent": "Mozilla/5.0"})
67
  soup = BeautifulSoup(r.text, "html.parser")
68
  headlines = [h.text for h in soup.select("h3")[:5]]
69
  return " ".join(headlines)
@@ -142,7 +142,7 @@ def scrape_nba_preseason_pairs_for_dates(dates):
142
  q = qtpl.format(d=d)
143
  url = f"https://www.google.com/search?q={q}"
144
  try:
145
- r = requests.get(url, headers=headers, timeout=20)
146
  soup = BeautifulSoup(r.text, "html.parser")
147
  h3s = [h.text for h in soup.select("h3")[:30]]
148
  pairs = _extract_pairs_from_texts(h3s)
@@ -168,6 +168,48 @@ def build_soccer_verdict(home, away, agg):
168
  conf_ou = max(ou_25.get("over", 0.0), ou_25.get("under", 0.0))
169
  return f"{home} vs {away}: {pick_1x2} ({conf_1x2:.2f}), {pick_ou} ({conf_ou:.2f})"
170
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
171
  # --- Helpers: Football-Data last-5 and simple Poisson model ---
172
  def football_headers():
173
  return {"X-Auth-Token": FOOTBALL_API_KEY}
@@ -323,6 +365,10 @@ def soccer_predictions():
323
  continue
324
 
325
  for match in matches:
 
 
 
 
326
  home, away = match["homeTeam"]["name"], match["awayTeam"]["name"]
327
  home_id = match["homeTeam"].get("id")
328
  away_id = match["awayTeam"].get("id")
@@ -567,20 +613,26 @@ def nba_predictions():
567
  home_sent = sentiment_model(default_text, labels)
568
  away_sent = sentiment_model(default_text, labels)
569
 
 
 
 
570
  context = f"""
571
  Match: {home} vs {away}.
572
  Home news: {home_news}.
573
  Away news: {away_news}.
 
574
  """
575
  reasoning = reasoning_model(
576
  f"Provide a concise NBA verdict: likely winner and Over/Under guidance. Context: {context}",
577
  max_new_tokens=256
578
  )[0]['generated_text']
579
 
 
 
580
  predictions.append({
581
  "match": f"{home} vs {away}",
582
  "reason": reasoning,
583
- "verdict": f"{home} vs {away}: {reasoning[:140]}...",
584
  "news_summary": {
585
  home: home_sent,
586
  away: away_sent
 
63
 
64
  def get_team_news(team: str, sport: str = "football"):
65
  url = f"https://news.google.com/search?q={team}+{sport}&hl=en"
66
+ r = requests.get(url, headers={"User-Agent": "Mozilla/5.0"}, timeout=10)
67
  soup = BeautifulSoup(r.text, "html.parser")
68
  headlines = [h.text for h in soup.select("h3")[:5]]
69
  return " ".join(headlines)
 
142
  q = qtpl.format(d=d)
143
  url = f"https://www.google.com/search?q={q}"
144
  try:
145
+ r = requests.get(url, headers=headers, timeout=10)
146
  soup = BeautifulSoup(r.text, "html.parser")
147
  h3s = [h.text for h in soup.select("h3")[:30]]
148
  pairs = _extract_pairs_from_texts(h3s)
 
168
  conf_ou = max(ou_25.get("over", 0.0), ou_25.get("under", 0.0))
169
  return f"{home} vs {away}: {pick_1x2} ({conf_1x2:.2f}), {pick_ou} ({conf_ou:.2f})"
170
 
171
+ def _score_zero_shot(sent_result):
172
+ # Expecting HF zero-shot output: {labels: [...], scores: [...]} possibly wrapped
173
+ try:
174
+ labels = sent_result.get('labels') or []
175
+ scores = sent_result.get('scores') or []
176
+ table = {lbl: scores[i] for i, lbl in enumerate(labels)}
177
+ positive = float(table.get('positive', 0.0))
178
+ negative = float(table.get('negative', 0.0))
179
+ injury = float(table.get('injury', 0.0))
180
+ motivation = float(table.get('motivation', 0.0))
181
+ transfer = float(table.get('transfer', 0.0))
182
+ return {
183
+ 'positive': positive,
184
+ 'negative': negative,
185
+ 'injury': injury,
186
+ 'motivation': motivation,
187
+ 'transfer': transfer,
188
+ 'net': positive - negative - 0.5 * injury + 0.25 * motivation
189
+ }
190
+ except Exception:
191
+ return {'positive': 0.0, 'negative': 0.0, 'injury': 0.0, 'motivation': 0.0, 'transfer': 0.0, 'net': 0.0}
192
+
193
+ def build_nba_verdict(home, away, home_sig, away_sig):
194
+ # Convert net signals into a simple probability with softmax-like scaling
195
+ h = home_sig.get('net', 0.0)
196
+ a = away_sig.get('net', 0.0)
197
+ margin = h - a
198
+ # logistic transform to [0,1]
199
+ import math
200
+ p_home = 1.0 / (1.0 + math.exp(-3.0 * margin))
201
+ p_away = 1.0 - p_home
202
+ # Over/Under lean from total sentiment energy
203
+ energy = max(0.0, home_sig.get('positive', 0.0) + away_sig.get('positive', 0.0) + home_sig.get('motivation', 0.0) + away_sig.get('motivation', 0.0))
204
+ injury_load = home_sig.get('injury', 0.0) + away_sig.get('injury', 0.0)
205
+ ou_pick = 'Over' if energy >= (0.6 + 0.3 * injury_load) else 'Under'
206
+ return {
207
+ 'winner_probs': { home: p_home, away: p_away },
208
+ 'winner_pick': home if p_home >= p_away else away,
209
+ 'winner_confidence': max(p_home, p_away),
210
+ 'ou_pick': ou_pick
211
+ }
212
+
213
  # --- Helpers: Football-Data last-5 and simple Poisson model ---
214
  def football_headers():
215
  return {"X-Auth-Token": FOOTBALL_API_KEY}
 
365
  continue
366
 
367
  for match in matches:
368
+ # Skip matches that are already played or not upcoming
369
+ m_status = (match.get("status") or "").upper()
370
+ if m_status and m_status not in ("SCHEDULED", "TIMED", "POSTPONED"): # e.g., FINISHED, IN_PLAY, PAUSED
371
+ continue
372
  home, away = match["homeTeam"]["name"], match["awayTeam"]["name"]
373
  home_id = match["homeTeam"].get("id")
374
  away_id = match["awayTeam"].get("id")
 
613
  home_sent = sentiment_model(default_text, labels)
614
  away_sent = sentiment_model(default_text, labels)
615
 
616
+ sig_home = _score_zero_shot(home_sent if isinstance(home_sent, dict) else (home_sent[0] if isinstance(home_sent, list) else {}))
617
+ sig_away = _score_zero_shot(away_sent if isinstance(away_sent, dict) else (away_sent[0] if isinstance(away_sent, list) else {}))
618
+
619
  context = f"""
620
  Match: {home} vs {away}.
621
  Home news: {home_news}.
622
  Away news: {away_news}.
623
+ Signals: home={sig_home}, away={sig_away}.
624
  """
625
  reasoning = reasoning_model(
626
  f"Provide a concise NBA verdict: likely winner and Over/Under guidance. Context: {context}",
627
  max_new_tokens=256
628
  )[0]['generated_text']
629
 
630
+ verdict = build_nba_verdict(home, away, sig_home, sig_away)
631
+
632
  predictions.append({
633
  "match": f"{home} vs {away}",
634
  "reason": reasoning,
635
+ "verdict": verdict,
636
  "news_summary": {
637
  home: home_sent,
638
  away: away_sent