|
|
from flask import Flask, render_template, request, jsonify |
|
|
import pandas as pd |
|
|
import hopsworks |
|
|
import os |
|
|
import json |
|
|
import math |
|
|
|
|
|
app = Flask(__name__) |
|
|
|
|
|
try: |
|
|
with open("../hopsworks/hopsworks-api-key.txt", "r") as file: |
|
|
os.environ["HOPSWORKS_API_KEY"] = file.read().rstrip() |
|
|
except: |
|
|
print("In production mode") |
|
|
|
|
|
project = hopsworks.login() |
|
|
fs = project.get_feature_store() |
|
|
|
|
|
players = fs.get_feature_group("fpl_predictions") |
|
|
|
|
|
player_df = players.read() |
|
|
|
|
|
player_data = player_df.to_json(orient="records") |
|
|
|
|
|
players = json.loads(player_data) |
|
|
|
|
|
for player in players: |
|
|
if player["predicted_score"] != None: |
|
|
player["predicted_score"] = round(player["predicted_score"]) |
|
|
|
|
|
|
|
|
display_players = [] |
|
|
|
|
|
for player in players: |
|
|
if not any( |
|
|
p["first_name"] == player["first_name"] |
|
|
and p["second_name"] == player["second_name"] |
|
|
for p in display_players |
|
|
): |
|
|
|
|
|
all_predictions = [ |
|
|
p |
|
|
for p in players |
|
|
if p["first_name"] == player["first_name"] |
|
|
and p["second_name"] == player["second_name"] |
|
|
] |
|
|
|
|
|
latest_prediction_entry = max(all_predictions, key=lambda x: x["gameweek"]) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
latest_predictions = [] |
|
|
|
|
|
|
|
|
for p in all_predictions: |
|
|
if p != latest_prediction_entry: |
|
|
latest_predictions.append( |
|
|
{ |
|
|
"gameweek": p["gameweek"], |
|
|
"points": p["predicted_score"], |
|
|
"predicted_score": p["points"], |
|
|
} |
|
|
) |
|
|
|
|
|
|
|
|
latest_prediction_entry["latest_predictions"] = latest_predictions |
|
|
|
|
|
latest_prediction_entry["prev_value"] /= 10 |
|
|
|
|
|
latest_prediction_entry["prev_value"] = ( |
|
|
f"""£{latest_prediction_entry["prev_value"]}m""" |
|
|
) |
|
|
|
|
|
|
|
|
display_players.append(latest_prediction_entry) |
|
|
|
|
|
|
|
|
sample_players = [ |
|
|
{ |
|
|
"first_name": "Harry", |
|
|
"second_name": "Kane", |
|
|
"position": "Midfielder", |
|
|
"team": "Tottenham", |
|
|
"total_points": 100, |
|
|
"latest_predictions": [ |
|
|
{"gameweek": 21, "total_points": 18, "predicted_points": 15}, |
|
|
{"gameweek": 20, "total_points": 12, "predicted_points": 8}, |
|
|
{"gameweek": 19, "total_points": 9, "predicted_points": 5}, |
|
|
{"gameweek": 18, "total_points": 5, "predicted_points": 7}, |
|
|
{"gameweek": 17, "total_points": 11, "predicted_points": 7}, |
|
|
], |
|
|
"predicted_score": 7, |
|
|
}, |
|
|
{ |
|
|
"first_name": "Harry2", |
|
|
"second_name": "Kane2", |
|
|
"position": "Midfielder", |
|
|
"team": "Tottenham", |
|
|
"total_points": 100, |
|
|
"latest_predictions": [ |
|
|
{"gameweek": 21, "total_points": 10, "predicted_points": 8}, |
|
|
{"gameweek": 20, "total_points": 5, "predicted_points": 8}, |
|
|
{"gameweek": 19, "total_points": 13, "predicted_points": 15}, |
|
|
{"gameweek": 18, "total_points": 5, "predicted_points": 7}, |
|
|
{"gameweek": 17, "total_points": 14, "predicted_points": 18}, |
|
|
], |
|
|
"predicted_score": 7, |
|
|
}, |
|
|
{ |
|
|
"first_name": "Harry3", |
|
|
"second_name": "Kane3", |
|
|
"position": "Midfielder", |
|
|
"team": "Tottenham", |
|
|
"total_points": 100, |
|
|
"latest_predictions": [ |
|
|
{"gameweek": 21, "total_points": 14, "predicted_points": 11}, |
|
|
{"gameweek": 20, "total_points": 8, "predicted_points": 4}, |
|
|
{"gameweek": 19, "total_points": 11, "predicted_points": 7}, |
|
|
{"gameweek": 18, "total_points": 6, "predicted_points": 8}, |
|
|
{"gameweek": 17, "total_points": 12, "predicted_points": 9}, |
|
|
], |
|
|
"predicted_score": 7, |
|
|
}, |
|
|
{ |
|
|
"first_name": "Harry4", |
|
|
"second_name": "Kane4", |
|
|
"position": "Midfielder", |
|
|
"team": "Tottenham", |
|
|
"total_points": 100, |
|
|
"latest_predictions": [ |
|
|
{"gameweek": 21, "total_points": 10, "predicted_points": 8}, |
|
|
{"gameweek": 20, "total_points": 7, "predicted_points": 6}, |
|
|
{"gameweek": 19, "total_points": 13, "predicted_points": 10}, |
|
|
{"gameweek": 18, "total_points": 5, "predicted_points": 4}, |
|
|
{"gameweek": 17, "total_points": 11, "predicted_points": 9}, |
|
|
], |
|
|
"predicted_score": 7, |
|
|
}, |
|
|
{ |
|
|
"first_name": "Harry5", |
|
|
"second_name": "Kane5", |
|
|
"position": "Midfielder", |
|
|
"team": "Tottenham", |
|
|
"total_points": 100, |
|
|
"latest_predictions": [ |
|
|
{"gameweek": 21, "total_points": 10, "predicted_points": 8}, |
|
|
{"gameweek": 20, "total_points": 7, "predicted_points": 6}, |
|
|
{"gameweek": 19, "total_points": 13, "predicted_points": 10}, |
|
|
{"gameweek": 18, "total_points": 5, "predicted_points": 4}, |
|
|
{"gameweek": 17, "total_points": 11, "predicted_points": 9}, |
|
|
], |
|
|
"predicted_score": 7, |
|
|
}, |
|
|
] |
|
|
|
|
|
|
|
|
for player in sample_players: |
|
|
player["latest_predictions_str"] = ", ".join( |
|
|
[ |
|
|
f"GW{pred['gameweek']}: {pred['total_points']} pts (Pred: {pred['predicted_points']} pts)" |
|
|
for pred in player["latest_predictions"] |
|
|
] |
|
|
) |
|
|
|
|
|
|
|
|
@app.route("/test") |
|
|
def test(): |
|
|
|
|
|
display_players = [] |
|
|
|
|
|
for player in players: |
|
|
if not any( |
|
|
p["first_name"] == player["first_name"] |
|
|
and p["second_name"] == player["second_name"] |
|
|
for p in display_players |
|
|
): |
|
|
|
|
|
all_predictions = [ |
|
|
p |
|
|
for p in players |
|
|
if p["first_name"] == player["first_name"] |
|
|
and p["second_name"] == player["second_name"] |
|
|
] |
|
|
|
|
|
latest_prediction_entry = max(all_predictions, key=lambda x: x["gameweek"]) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
latest_predictions = [] |
|
|
|
|
|
|
|
|
for p in all_predictions: |
|
|
if p != latest_prediction_entry: |
|
|
latest_predictions.append( |
|
|
{ |
|
|
"gameweek": p["gameweek"], |
|
|
"points": p["points"], |
|
|
"predicted_score": p["predicted_score"], |
|
|
} |
|
|
) |
|
|
|
|
|
|
|
|
latest_prediction_entry["latest_predictions"] = latest_predictions |
|
|
|
|
|
|
|
|
display_players.append(latest_prediction_entry) |
|
|
|
|
|
return display_players |
|
|
|
|
|
|
|
|
@app.route("/") |
|
|
def index(): |
|
|
"""Render the main page.""" |
|
|
return render_template("players.html", players=display_players, current_gameweek=20) |
|
|
|
|
|
|
|
|
@app.route("/api/players", methods=["POST", "GET"]) |
|
|
def get_players(): |
|
|
"""API endpoint to fetch players with all 5 gameweeks, filtering by player name and position if provided.""" |
|
|
player_name = request.form.get( |
|
|
"player", "" |
|
|
).lower() |
|
|
position = request.form.get("position", "").upper() |
|
|
|
|
|
|
|
|
filtered_players = [ |
|
|
player |
|
|
for player in sample_players |
|
|
if ( |
|
|
player_name in player["first_name"].lower() |
|
|
or player_name in player["second_name"].lower() |
|
|
) |
|
|
and (not position or position == player["position"]) |
|
|
] |
|
|
|
|
|
|
|
|
if not player_name and not position: |
|
|
filtered_players = sample_players |
|
|
|
|
|
|
|
|
player_rows = "" |
|
|
for player in filtered_players: |
|
|
player_rows += f""" |
|
|
<tr> |
|
|
<td>{player['first_name']} {player['second_name']}</td> |
|
|
<td>{player['position']}</td> |
|
|
<td>{player['club']}</td> |
|
|
<td>{player['points']}</td> |
|
|
<td> |
|
|
<table class="inner-table"> |
|
|
<tr> |
|
|
<th>Gameweek</th> |
|
|
<th>Points</th> |
|
|
<th>Predicted Points</th> |
|
|
</tr> |
|
|
""" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
player_rows += f"""</table></td> |
|
|
<td>{player["nextGwPrediction"]}</td</tr>""" |
|
|
|
|
|
return player_rows |
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
app.run(debug=True) |
|
|
|