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") | |