Michael Paonam commited on
Commit
f357ac3
·
1 Parent(s): 7c06ee6

Fix missing market odds handling for matches without betting data

Browse files

- make_prob_chart: skip market bars when no odds available
- format_edge_badge: handle missing actual results gracefully
- format_match_info: only show implied probability when present
- build_live_context: guard against missing market_odds
- get_scorecard: skip matches without actual results

Files changed (1) hide show
  1. app.py +44 -28
app.py CHANGED
@@ -89,32 +89,40 @@ def get_match_choices():
89
 
90
  def get_scorecard():
91
  correct = 0
 
92
  for m in MATCHES:
93
- edge = m["vlm_assessment"]["edge"]
94
- actual = result_key(m["actual_result"])
 
 
 
95
  best = max(edge.items(), key=lambda x: x[1])
96
  if best[0] == actual:
97
  correct += 1
98
- return correct, len(MATCHES)
 
99
 
100
 
101
  def make_prob_chart(match):
102
- market = match["market_odds"]
103
- vlm = match["vlm_assessment"]["probabilities"]
104
 
105
  categories = ["Home", "Draw", "Away"]
106
- market_vals = [market["home"] * 100, market["draw"] * 100, market["away"] * 100]
107
  vlm_vals = [vlm.get("home", 0) * 100, vlm.get("draw", 0) * 100, vlm.get("away", 0) * 100]
108
 
109
  fig = go.Figure()
110
- fig.add_trace(go.Bar(
111
- name="Market Implied",
112
- x=categories,
113
- y=market_vals,
114
- marker_color="#6366f1",
115
- text=[f"{v:.0f}%" for v in market_vals],
116
- textposition="outside",
117
- ))
 
 
 
 
118
  fig.add_trace(go.Bar(
119
  name="VLM Assessment",
120
  x=categories,
@@ -563,19 +571,25 @@ def predict_matchup(team_a: str, team_b: str):
563
 
564
 
565
  def format_edge_badge(match):
566
- edge = match["vlm_assessment"]["edge"]
567
- actual = result_key(match["actual_result"])
 
 
568
  best = max(edge.items(), key=lambda x: x[1])
569
  best_outcome, best_val = best
570
-
571
- correct = best_outcome == actual
572
  outcome_label = {"home": match["home_team"], "draw": "Draw", "away": match["away_team"]}
573
- badge = f"Edge: +{best_val*100:.0f}pp on {outcome_label[best_outcome]}"
574
 
575
- if correct:
576
- return f"## {badge}\n\nActual result: **{match['actual_score']}** ({match['actual_result'].replace('_', ' ')}) — CORRECT"
577
- else:
578
- return f"## {badge}\n\nActual result: **{match['actual_score']}** ({match['actual_result'].replace('_', ' ')})"
 
 
 
 
 
 
579
 
580
 
581
  def format_reasoning(match):
@@ -699,8 +713,9 @@ def format_match_info(match):
699
  odds = match.get("odds", {})
700
  if odds:
701
  lines.append(f"- Decimal odds: {match['home_team']} {odds.get('home', '-')} / Draw {odds.get('draw', '-')} / {match['away_team']} {odds.get('away', '-')}")
702
- market = match["market_odds"]
703
- lines.append(f"- Implied probability: {match['home_team']} {market['home']*100:.0f}% / Draw {market['draw']*100:.0f}% / {match['away_team']} {market['away']*100:.0f}%")
 
704
  if match.get("narrative"):
705
  lines.append(f"\n*{match['narrative']}*")
706
  return "\n".join(lines)
@@ -761,9 +776,10 @@ def select_clip_for_match(clip_label, match_choice):
761
  def build_live_context(match_idx: int) -> str:
762
  match = MATCHES[match_idx]
763
  lines = []
764
- lines.append(f"Match: {match['home_team']} vs {match['away_team']} ({match['stage']}, {match['date']})")
765
- market = match["market_odds"]
766
- lines.append(f"Market implied: {match['home_team']} {market['home']*100:.0f}% / Draw {market['draw']*100:.0f}% / {match['away_team']} {market['away']*100:.0f}%")
 
767
  stats = match.get("stats", {})
768
  for side in ["home", "away"]:
769
  s = stats.get(side, {})
 
89
 
90
  def get_scorecard():
91
  correct = 0
92
+ total = 0
93
  for m in MATCHES:
94
+ edge = m.get("vlm_assessment", {}).get("edge", {})
95
+ actual_result = m.get("actual_result", "")
96
+ if not edge or not actual_result:
97
+ continue
98
+ actual = result_key(actual_result)
99
  best = max(edge.items(), key=lambda x: x[1])
100
  if best[0] == actual:
101
  correct += 1
102
+ total += 1
103
+ return correct, total
104
 
105
 
106
  def make_prob_chart(match):
107
+ market = match.get("market_odds", {})
108
+ vlm = match.get("vlm_assessment", {}).get("probabilities", {})
109
 
110
  categories = ["Home", "Draw", "Away"]
 
111
  vlm_vals = [vlm.get("home", 0) * 100, vlm.get("draw", 0) * 100, vlm.get("away", 0) * 100]
112
 
113
  fig = go.Figure()
114
+
115
+ if market and market.get("home"):
116
+ market_vals = [market["home"] * 100, market["draw"] * 100, market["away"] * 100]
117
+ fig.add_trace(go.Bar(
118
+ name="Market Implied",
119
+ x=categories,
120
+ y=market_vals,
121
+ marker_color="#6366f1",
122
+ text=[f"{v:.0f}%" for v in market_vals],
123
+ textposition="outside",
124
+ ))
125
+
126
  fig.add_trace(go.Bar(
127
  name="VLM Assessment",
128
  x=categories,
 
571
 
572
 
573
  def format_edge_badge(match):
574
+ edge = match.get("vlm_assessment", {}).get("edge", {})
575
+ if not edge:
576
+ return "## No edge data available"
577
+
578
  best = max(edge.items(), key=lambda x: x[1])
579
  best_outcome, best_val = best
 
 
580
  outcome_label = {"home": match["home_team"], "draw": "Draw", "away": match["away_team"]}
581
+ badge = f"Edge: +{best_val*100:.0f}pp on {outcome_label.get(best_outcome, best_outcome)}"
582
 
583
+ actual_result = match.get("actual_result", "")
584
+ actual_score = match.get("actual_score", "")
585
+ if actual_result and actual_score:
586
+ actual = result_key(actual_result)
587
+ correct = best_outcome == actual
588
+ if correct:
589
+ return f"## {badge}\n\nActual result: **{actual_score}** ({actual_result.replace('_', ' ')}) — CORRECT"
590
+ else:
591
+ return f"## {badge}\n\nActual result: **{actual_score}** ({actual_result.replace('_', ' ')})"
592
+ return f"## {badge}"
593
 
594
 
595
  def format_reasoning(match):
 
713
  odds = match.get("odds", {})
714
  if odds:
715
  lines.append(f"- Decimal odds: {match['home_team']} {odds.get('home', '-')} / Draw {odds.get('draw', '-')} / {match['away_team']} {odds.get('away', '-')}")
716
+ market = match.get("market_odds", {})
717
+ if market and market.get("home"):
718
+ lines.append(f"- Implied probability: {match['home_team']} {market['home']*100:.0f}% / Draw {market['draw']*100:.0f}% / {match['away_team']} {market['away']*100:.0f}%")
719
  if match.get("narrative"):
720
  lines.append(f"\n*{match['narrative']}*")
721
  return "\n".join(lines)
 
776
  def build_live_context(match_idx: int) -> str:
777
  match = MATCHES[match_idx]
778
  lines = []
779
+ lines.append(f"Match: {match['home_team']} vs {match['away_team']} ({match.get('stage', '')}, {match['date']})")
780
+ market = match.get("market_odds", {})
781
+ if market and market.get("home"):
782
+ lines.append(f"Market implied: {match['home_team']} {market['home']*100:.0f}% / Draw {market['draw']*100:.0f}% / {match['away_team']} {market['away']*100:.0f}%")
783
  stats = match.get("stats", {})
784
  for side in ["home", "away"]:
785
  s = stats.get(side, {})