Spaces:
Runtime error
Runtime error
from scrape import scrape, get_live_matches | |
import pandas as pd | |
import streamlit as st | |
from streamlit_echarts import st_echarts | |
import joblib | |
import numpy as np | |
import math, os | |
import datetime, time | |
import matplotlib.pyplot as plt | |
import pathlib | |
for folder in ["data", "model", "history", "result", "temp"]: | |
pathlib.Path(folder).mkdir(parents=True, exist_ok=True) | |
# ## Test on realdata | |
# In[16]: | |
from model import features | |
import streamlit_analytics | |
# features = [ | |
# "batting_team", | |
# "balls", | |
# "runs", | |
# "wickets", | |
# "wkt_last_5_overs", | |
# "runrate_last_5_overs", | |
# "current_RR", | |
# "average", | |
# "balls_left", | |
# "wkts_left", | |
# "required_RR", | |
# "projected_score_more", | |
# "min_score_more", | |
# "max_score_more", | |
# "projected_avg_score_more", | |
# ] | |
all_teams_enc = list(range(len(np.load("model/team.npy", allow_pickle=True)))) | |
def overtoball(over): | |
over = str(over) | |
full = int(over.split(".")[0]) * 6 | |
part = min(int(over.split(".")[-1]), 6) | |
print(f"{over=}", "balls=", full + part) | |
return full + part | |
def save_history(fname, row, total_balls): | |
row.to_csv( | |
os.path.join("history", fname), | |
mode="a" if os.path.isfile(os.path.join("history", fname)) else "w+", | |
header=not os.path.isfile(os.path.join("history", fname)), | |
) | |
fig, ax = plt.subplots() | |
historydf = pd.read_csv(os.path.join("history", fname)) | |
balls = (total_balls - historydf["balls_left"]).to_list() | |
runs = historydf["runs"].astype(int).to_list() | |
ax.plot(balls, runs, label="So Far") | |
balls.append(total_balls) | |
pred_runs = runs + [historydf["predicted"].astype(int).iloc[-1]] | |
ax.plot(balls[-2:], pred_runs[-2:], label="Predicted") | |
proj_runs = runs + [historydf["projected"].astype(int).iloc[-1]] | |
ax.plot(balls[-2:], proj_runs[-2:], label="Projected") | |
ax.annotate(str(runs[-1]), xy=(balls[-2], runs[-1])) | |
ax.annotate(str(pred_runs[-1]), xy=(balls[-1], pred_runs[-1])) | |
ax.annotate(str(proj_runs[-1]), xy=(balls[-1], proj_runs[-1])) | |
plt.xlim([0, total_balls]) | |
plt.ylim([0, max(pred_runs[-1], proj_runs[-1]) + 100]) | |
ax.set_xlabel("Balls") | |
ax.set_ylabel("Runs") | |
ax.legend() | |
return fig | |
def load_model(format): | |
return joblib.load( | |
"model/" | |
+ ( | |
"t20features.feather.joblib" | |
if format == "T20" | |
else "odifeatures.feather.joblib" | |
if format == "ODI" | |
else None | |
) | |
) | |
def simulator(args, format): | |
inputdf = pd.DataFrame([args.values()], columns=args.keys()) | |
model = load_model(format) | |
h = model.predict(inputdf) | |
return h | |
def predict(url): | |
fname = "".join(list(filter(str.isalnum, url))) + ".csv" | |
ret = scrape(url) | |
print(ret) | |
if len(ret) == 1: | |
err = ret[0] | |
return [err] | |
else: | |
( | |
matchState, | |
score, | |
run_last_5_overs, | |
wkt_last_5_overs, | |
runs, | |
wkts, | |
overs, | |
req_rr, | |
req, | |
current_rr, | |
format, | |
title, | |
status, | |
batting_team, | |
bowling_team, | |
batting_team_enc, | |
bowling_team_enc, | |
inning, | |
) = ret | |
if matchState != "inprogress": | |
return matchState, None, score, format, title, status, None, None, None, None | |
total_balls = 120 if format == "T20" else 300 if format == "ODI" else None | |
balls = overtoball(overs) | |
rr_last_5_overs = (int(run_last_5_overs) * 6) / min(30, balls) | |
# current_rr = (runs * 6) / balls | |
avg = runs / (wkts + 1) | |
req_rr = req_rr | |
wkts_left = 10 - wkts | |
balls_left = (total_balls - balls) if inning == 1 else math.ceil(req * 6 / req_rr) | |
min_score_avg, max_score_avg = ( | |
math.ceil(balls_left * 0.5), | |
math.ceil(balls_left * 3), | |
) | |
rr_diff = rr_last_5_overs - current_rr | |
inputs = { | |
"batting_team": batting_team_enc, | |
"balls": balls, | |
"runs": runs, | |
"wickets": wkts, | |
"wkt_last_5_overs": wkt_last_5_overs, | |
"runrate_last_5_overs": rr_last_5_overs, | |
"current_RR": current_rr, | |
"runrate_last_5_overs-current_RR": rr_diff, | |
"average": avg, | |
"balls_left": int(balls_left), | |
"wkts_left": int(wkts_left), | |
"required_RR": -9999, | |
"projected_score_more": math.ceil(balls_left * ((runs) / (balls))), | |
"min_score_more": math.ceil(balls_left * 0.5), | |
"max_score_more": math.ceil(balls_left * 3), | |
"projected_avg_score_more": math.ceil((10 - wkts) * runs / (1 + wkts)), | |
} | |
inputdf = pd.DataFrame(inputs, index=[0]) | |
if batting_team_enc is None: | |
inputdf = inputdf.drop(columns=["batting_team"]) | |
inputdf = pd.concat([inputdf] * len(all_teams_enc)) | |
inputdf["batting_team"] = all_teams_enc | |
inputdf = inputdf[features] | |
model = load_model(format) | |
h = model.predict(inputdf) | |
print(f"{h=}") | |
projected_score_more = balls_left * current_rr / 6 | |
projected = math.ceil(projected_score_more + runs) | |
predicted_score_more = math.ceil(h.mean() + projected_score_more) | |
# predicted_score_more = min(max(min_score_avg, predicted_score_more), max_score_avg) | |
predicted = runs + predicted_score_more | |
print(f"{runs=}, {projected=}, {predicted=}") | |
inputdf["timestamp"] = datetime.datetime.now() | |
inputdf["runs"] = runs | |
if inning == 2: | |
target = req + runs | |
print(f"{target=}") | |
inputdf["target"] = target | |
batting_team_win = int(predicted - target) | |
else: | |
batting_team_win = None | |
inputdf["target"] = -9999 | |
inputdf["predicted"] = int(predicted) | |
inputdf["projected"] = int(projected) | |
print(inputdf.to_string()) | |
fig = save_history(fname, inputdf, total_balls) | |
return ( | |
matchState, | |
predicted, | |
score, | |
format, | |
title, | |
status, | |
inning, | |
batting_team, | |
batting_team_win, | |
fig, | |
) | |
def getoption(predicted, maxscore): | |
return { | |
"series": [ | |
{ | |
"type": "gauge", | |
"startAngle": 180, | |
"endAngle": 0, | |
"min": 0, | |
"max": maxscore, | |
"center": ["50%", "50%"], | |
"splitNumber": 4, | |
"axisLine": { | |
"lineStyle": { | |
"width": 6, | |
"color": [ | |
[0.25, "#FF403F"], | |
[0.5, "#FDDD60"], | |
[0.75, "#00FF00"], | |
[1, "#0000FF"], | |
], | |
} | |
}, | |
"pointer": { | |
"icon": "path://M12.8,0.7l12,40.1H0.7L12.8,0.7z", | |
"length": "12%", | |
"width": 30, | |
"offsetCenter": [0, "-60%"], | |
"itemStyle": {"color": "auto"}, | |
}, | |
"axisTick": { | |
"length": 10, | |
"lineStyle": {"color": "auto", "width": 2}, | |
}, | |
"splitLine": { | |
"length": 15, | |
"lineStyle": {"color": "auto", "width": 5}, | |
}, | |
"axisLabel": { | |
"fontSize": 12, | |
"distance": -60, | |
}, | |
"title": { | |
"offsetCenter": [0, "-20%"], | |
"fontSize": 20, | |
"color": "#0000FF" | |
if predicted > maxscore * 0.75 | |
else "#00FF00" | |
if predicted > maxscore * 0.5 | |
else "#FDDD60" | |
if predicted > maxscore * 0.25 | |
else "#FF403F", | |
}, | |
"detail": { | |
"fontSize": 15, | |
"offsetCenter": [0, "0%"], | |
"valueAnimation": True, | |
"color": "auto", | |
"formatter": "Predicted Score: {value}", | |
}, | |
"data": [ | |
{ | |
"value": round(predicted), | |
} | |
# { | |
# "value": round(predicted), | |
# "name": "Great" | |
# if predicted > maxscore * 0.75 | |
# else "Decent" | |
# if predicted > maxscore * 0.5 | |
# else "Average" | |
# if predicted > maxscore * 0.25 | |
# else "Bad", | |
# } | |
], | |
} | |
] | |
} | |
def timestamp(func): | |
def caller(*args): | |
print( | |
"\n---->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Initiated: ", | |
datetime.datetime.now(), | |
"<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<----", | |
) | |
ret = func(*args) | |
print( | |
"\n---->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Completed: ", | |
datetime.datetime.now(), | |
"<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<----", | |
) | |
return ret | |
return caller | |
def render(url): | |
markdown = [] | |
option = None | |
print("fetching from", url) | |
ret = predict(url.strip()) | |
if len(ret) == 1: | |
err = ret[0] | |
markdown.append("Error fetching url...") | |
return markdown, None, None | |
( | |
matchState, | |
predicted, | |
score, | |
format, | |
title, | |
status, | |
inning, | |
batting_team, | |
batting_team_win, | |
fig, | |
) = ret | |
if matchState: | |
markdown.append("Live score credits: cricbuzz.com") | |
if title: | |
if "|" in title: | |
l1 = ( | |
title.split("|")[1] | |
.replace("Cricbuzz.com", "") | |
.replace("Cricbuzz", "") | |
) | |
if l1.strip(): | |
markdown.append(l1.strip()) | |
l2 = ( | |
title.split("|")[0] | |
.replace("Cricbuzz.com", "") | |
.replace("Cricbuzz", "") | |
) | |
if l2.strip(): | |
markdown.append(l2.strip()) | |
else: | |
markdown.append( | |
title.replace("Cricbuzz.com", "").replace("Cricbuzz", "") | |
) | |
nutshell = "" | |
if status: | |
nutshell += status + "; " | |
if score: | |
nutshell += score + "; " | |
if matchState: | |
nutshell += matchState + "; " | |
if nutshell: | |
markdown.append(nutshell) | |
# if matchState and matchState != "inprogress": | |
# markdown.append(matchState) | |
if predicted: | |
if inning == 2: | |
if batting_team_win >= 0: | |
markdown.append(f"{batting_team} may win") | |
else: | |
markdown.append( | |
f"{batting_team} may lose by {-int(batting_team_win)} runs" | |
) | |
maxscore = 300 if format == "T20" else 500 if format == "ODI" else None | |
option = getoption(predicted, maxscore) | |
if matchState is None: | |
markdown.append("Error fetching url...") | |
return "\n".join(markdown), option, fig | |
if __name__ == "__main__": | |
with streamlit_analytics.track(unsafe_password="credict123"): | |
st.set_page_config(page_title="Cricket Prophet") | |
st.title("Cricket Prophet") | |
st.write("**An ML-driven Cricket Score Predictor**") | |
live_matches = get_live_matches("https://cricbuzz.com") | |
if live_matches: | |
option = st.selectbox( | |
"Choose a live match here", | |
list(live_matches.keys()) + ["Custom URL", "Simulator"], | |
) | |
if option == "Simulator": | |
format = st.selectbox("Format", ["T20", "ODI"]) | |
args = {} | |
args["batting_team"] = 1 | |
args["wkt_last_5_overs"] = st.number_input( | |
"wkt_last_5_overs", value=0.0, step=0.01, format="%f" | |
) | |
args["current_RR"] = st.number_input( | |
"current_RR", value=0.0, step=0.01, format="%f" | |
) | |
args["balls_left"] = st.number_input( | |
"balls_left", value=0.0, step=0.01, format="%f" | |
) | |
args["wkts_left"] = st.number_input( | |
"wkts_left", value=0.0, step=0.01, format="%f" | |
) | |
args["runrate_last_5_overs-current_RR"] = ( | |
st.number_input( | |
"runrate_last_5_overs", value=0.0, step=0.01, format="%f" | |
) | |
- args["current_RR"] | |
) | |
balls = 300 if format == "ODI" else 120 | |
st.text( | |
str(int((balls * args["current_RR"] / 6) + simulator(args, format))) | |
) | |
else: | |
if option == "Custom URL": | |
url = st.text_input("Enter cricbuzz match link") | |
else: | |
url = live_matches.get(option) | |
col1, col2 = st.columns([3.5, 0.6]) | |
with col1: | |
live = st.button("Live", help="Livestream") | |
with col2: | |
fetch = st.button("Fetch", help="Refresh") | |
col3, _ = st.columns([1, 4]) | |
with col3: | |
interval = st.number_input( | |
label="Sync Interval (Seconds)", step=1, min_value=1, value=100 | |
) | |
placeholder = st.empty() | |
if fetch: | |
if url: | |
markdown, option, fig = render(url) | |
placeholder.empty() | |
with placeholder.container(): | |
st.text(markdown) | |
st.text(f"Last updated at {time.strftime('%H:%M %p')}") | |
if option: | |
st_echarts( | |
option, | |
width="450px", | |
height="350px", | |
key="gauge" + str(datetime.datetime.now()), | |
) | |
if fig: | |
st.pyplot(fig) | |
if live: | |
if url: | |
while True: | |
markdown, option, fig = render(url) | |
placeholder.empty() | |
with placeholder.container(): | |
st.text(markdown) | |
st.text(f"Last updated at {time.strftime('%H:%M %p')}") | |
if option: | |
st_echarts( | |
option, | |
width="450px", | |
height="350px", | |
key="gauge" + str(datetime.datetime.now()), | |
) | |
if fig: | |
st.pyplot(fig) | |
else: | |
break | |
time.sleep(interval) | |
else: | |
st.text("Error fetching matches") | |