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
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
|
| 94 |
-
|
|
|
|
|
|
|
|
|
|
| 95 |
best = max(edge.items(), key=lambda x: x[1])
|
| 96 |
if best[0] == actual:
|
| 97 |
correct += 1
|
| 98 |
-
|
|
|
|
| 99 |
|
| 100 |
|
| 101 |
def make_prob_chart(match):
|
| 102 |
-
market = match
|
| 103 |
-
vlm = match
|
| 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 |
-
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
| 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
|
| 567 |
-
|
|
|
|
|
|
|
| 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
|
| 574 |
|
| 575 |
-
|
| 576 |
-
|
| 577 |
-
|
| 578 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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
|
| 703 |
-
|
|
|
|
| 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
|
| 765 |
-
market = match
|
| 766 |
-
|
|
|
|
| 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, {})
|