Spaces:
Runtime error
Runtime error
Commit
·
1a89c67
1
Parent(s):
623a8f8
Update site title
Browse files- Source/Data/gbg_and_odds_this_year.csv +1 -1
- Source/Data/gbg_this_year.csv +1 -1
- Source/Data/lines.json +56 -0
- Source/Predict/__pycache__/predict.cpython-311.pyc +0 -0
- Source/Predict/predict.py +17 -14
- Templates/index.html +129 -36
- main.py +50 -34
Source/Data/gbg_and_odds_this_year.csv
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
size 27668
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:8cf6bbbabaf4d15ab0c59ff18348c88bbcf67b8eac7161b662b7e77cd6fcb4f4
|
| 3 |
size 27668
|
Source/Data/gbg_this_year.csv
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
size 24329
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:5d085f5ecdd8cf42ee64b7ae6d2d3221ca0402864bddbc02c89f23edf2ed9389
|
| 3 |
size 24329
|
Source/Data/lines.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"2":[
|
| 3 |
+
49,
|
| 4 |
+
40.5,
|
| 5 |
+
47,
|
| 6 |
+
45.5,
|
| 7 |
+
47,
|
| 8 |
+
39.5,
|
| 9 |
+
51.5,
|
| 10 |
+
41,
|
| 11 |
+
45,
|
| 12 |
+
40,
|
| 13 |
+
44.5,
|
| 14 |
+
39,
|
| 15 |
+
37.5,
|
| 16 |
+
47,
|
| 17 |
+
39.5,
|
| 18 |
+
39
|
| 19 |
+
],
|
| 20 |
+
"3":[
|
| 21 |
+
44.5,
|
| 22 |
+
43,
|
| 23 |
+
38,
|
| 24 |
+
47,
|
| 25 |
+
41.5,
|
| 26 |
+
43.5,
|
| 27 |
+
47.5,
|
| 28 |
+
54.5,
|
| 29 |
+
35,
|
| 30 |
+
43,
|
| 31 |
+
42.5,
|
| 32 |
+
44,
|
| 33 |
+
48.8,
|
| 34 |
+
43.5,
|
| 35 |
+
45,
|
| 36 |
+
43.5
|
| 37 |
+
],
|
| 38 |
+
"4":[
|
| 39 |
+
45.5,
|
| 40 |
+
43,
|
| 41 |
+
53.5,
|
| 42 |
+
45.5,
|
| 43 |
+
46,
|
| 44 |
+
41,
|
| 45 |
+
42.5,
|
| 46 |
+
46.5,
|
| 47 |
+
40.5,
|
| 48 |
+
43.5,
|
| 49 |
+
41,
|
| 50 |
+
48,
|
| 51 |
+
43,
|
| 52 |
+
44.5,
|
| 53 |
+
41.5,
|
| 54 |
+
47
|
| 55 |
+
]
|
| 56 |
+
}
|
Source/Predict/__pycache__/predict.cpython-311.pyc
CHANGED
|
Binary files a/Source/Predict/__pycache__/predict.cpython-311.pyc and b/Source/Predict/__pycache__/predict.cpython-311.pyc differ
|
|
|
Source/Predict/predict.py
CHANGED
|
@@ -7,6 +7,7 @@ import requests
|
|
| 7 |
from bs4 import BeautifulSoup
|
| 8 |
import warnings
|
| 9 |
warnings.filterwarnings("ignore")
|
|
|
|
| 10 |
|
| 11 |
# set dirs for other files
|
| 12 |
current_directory = os.path.dirname(os.path.abspath(__file__))
|
|
@@ -30,6 +31,20 @@ file_path = os.path.join(pickle_directory, 'team_abbreviation_to_name.pkl')
|
|
| 30 |
with open(file_path, 'rb') as f:
|
| 31 |
team_abbreviation_to_name = pkl.load(f)
|
| 32 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
def get_week():
|
| 34 |
headers = {
|
| 35 |
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
|
|
@@ -47,7 +62,6 @@ def get_week():
|
|
| 47 |
h2_tags = soup.find_all('h2')
|
| 48 |
year = h2_tags[0].getText().split(' ')[0]
|
| 49 |
week = h2_tags[0].getText().split(' ')[-1]
|
| 50 |
-
print(week)
|
| 51 |
return int(week), int(year)
|
| 52 |
|
| 53 |
|
|
@@ -103,13 +117,8 @@ def predict(home,away,season,week,total):
|
|
| 103 |
matrix = xgb.DMatrix(data.astype(float).values)
|
| 104 |
|
| 105 |
# create game id
|
| 106 |
-
game_id = str(season) + '_0' + str(week) + '_' + away_abbrev + '_' + home_abbrev
|
| 107 |
-
|
| 108 |
-
# moneyline
|
| 109 |
-
model = 'xgboost_ML_no_odds_71.4%'
|
| 110 |
-
file_path = os.path.join(model_directory, f'{model}.json')
|
| 111 |
-
xgb_ml = xgb.Booster()
|
| 112 |
-
xgb_ml.load_model(file_path)
|
| 113 |
|
| 114 |
try:
|
| 115 |
moneyline_result = results.loc[results['game_id']==game_id, 'winner'].item()
|
|
@@ -126,12 +135,6 @@ def predict(home,away,season,week,total):
|
|
| 126 |
moneyline = {'Winner': 'NA',
|
| 127 |
'Probabilities':['N/A'],
|
| 128 |
'Result': moneyline_result}
|
| 129 |
-
|
| 130 |
-
# over/under
|
| 131 |
-
model = 'xgboost_OU_no_odds_59.8%'
|
| 132 |
-
file_path = os.path.join(model_directory, f'{model}.json')
|
| 133 |
-
xgb_ou = xgb.Booster()
|
| 134 |
-
xgb_ou.load_model(file_path)
|
| 135 |
|
| 136 |
try:
|
| 137 |
result = results.loc[results['game_id']==game_id, 'total'].item()
|
|
|
|
| 7 |
from bs4 import BeautifulSoup
|
| 8 |
import warnings
|
| 9 |
warnings.filterwarnings("ignore")
|
| 10 |
+
from datetime import datetime
|
| 11 |
|
| 12 |
# set dirs for other files
|
| 13 |
current_directory = os.path.dirname(os.path.abspath(__file__))
|
|
|
|
| 31 |
with open(file_path, 'rb') as f:
|
| 32 |
team_abbreviation_to_name = pkl.load(f)
|
| 33 |
|
| 34 |
+
# load models
|
| 35 |
+
# moneyline
|
| 36 |
+
model = 'xgboost_ML_no_odds_71.4%'
|
| 37 |
+
file_path = os.path.join(model_directory, f'{model}.json')
|
| 38 |
+
xgb_ml = xgb.Booster()
|
| 39 |
+
xgb_ml.load_model(file_path)
|
| 40 |
+
|
| 41 |
+
# over/under
|
| 42 |
+
model = 'xgboost_OU_no_odds_59.8%'
|
| 43 |
+
file_path = os.path.join(model_directory, f'{model}.json')
|
| 44 |
+
xgb_ou = xgb.Booster()
|
| 45 |
+
xgb_ou.load_model(file_path)
|
| 46 |
+
|
| 47 |
+
|
| 48 |
def get_week():
|
| 49 |
headers = {
|
| 50 |
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
|
|
|
|
| 62 |
h2_tags = soup.find_all('h2')
|
| 63 |
year = h2_tags[0].getText().split(' ')[0]
|
| 64 |
week = h2_tags[0].getText().split(' ')[-1]
|
|
|
|
| 65 |
return int(week), int(year)
|
| 66 |
|
| 67 |
|
|
|
|
| 117 |
matrix = xgb.DMatrix(data.astype(float).values)
|
| 118 |
|
| 119 |
# create game id
|
| 120 |
+
game_id = str(season) + '_0' + str(int(week)) + '_' + away_abbrev + '_' + home_abbrev
|
| 121 |
+
print(game_id)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 122 |
|
| 123 |
try:
|
| 124 |
moneyline_result = results.loc[results['game_id']==game_id, 'winner'].item()
|
|
|
|
| 135 |
moneyline = {'Winner': 'NA',
|
| 136 |
'Probabilities':['N/A'],
|
| 137 |
'Result': moneyline_result}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 138 |
|
| 139 |
try:
|
| 140 |
result = results.loc[results['game_id']==game_id, 'total'].item()
|
Templates/index.html
CHANGED
|
@@ -3,7 +3,7 @@
|
|
| 3 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 4 |
<head>
|
| 5 |
<link rel="shortcut icon" type="image/x-icon" href="https://images.squarespace-cdn.com/content/v1/64790f5777b5d772678cce83/6d71eaee-f825-4324-be9b-2def32469eac/favicon.ico?format=100w">
|
| 6 |
-
<title>MARCI</title>
|
| 7 |
</head>
|
| 8 |
<style>
|
| 9 |
body {
|
|
@@ -35,6 +35,7 @@
|
|
| 35 |
}
|
| 36 |
|
| 37 |
table {
|
|
|
|
| 38 |
margin-top: 20px;
|
| 39 |
width: 80%;
|
| 40 |
border-collapse: collapse;
|
|
@@ -95,12 +96,14 @@
|
|
| 95 |
cursor: pointer;
|
| 96 |
}
|
| 97 |
.winner-wrapper {
|
|
|
|
| 98 |
position: relative;
|
| 99 |
width: 100%;
|
| 100 |
text-align: center;
|
| 101 |
display: flex;
|
| 102 |
justify-content: center;
|
| 103 |
align-items: center;
|
|
|
|
| 104 |
}
|
| 105 |
.winner-image {
|
| 106 |
height: auto;
|
|
@@ -108,31 +111,15 @@
|
|
| 108 |
transition: 0.3s ease;
|
| 109 |
}
|
| 110 |
|
| 111 |
-
.overlay {
|
| 112 |
-
position: absolute;
|
| 113 |
-
top: 0;
|
| 114 |
-
left: 0;
|
| 115 |
-
width: 100%;
|
| 116 |
-
height: 100%;
|
| 117 |
-
background-color: rgba(0, 0, 0, 0.8);
|
| 118 |
-
color: white;
|
| 119 |
-
display: flex;
|
| 120 |
-
justify-content: center;
|
| 121 |
-
align-items: center;
|
| 122 |
-
opacity: 0;
|
| 123 |
-
transition: opacity 0.3s ease;
|
| 124 |
-
}
|
| 125 |
-
.winner-wrapper:hover .overlay {
|
| 126 |
-
opacity: 1;
|
| 127 |
-
}
|
| 128 |
.over-under-wrapper {
|
|
|
|
| 129 |
position: relative;
|
| 130 |
width: 100%;
|
| 131 |
height: 50px;
|
| 132 |
display: flex;
|
| 133 |
align-items: center;
|
| 134 |
justify-content: center;
|
| 135 |
-
transition:
|
| 136 |
}
|
| 137 |
.over-under-text {
|
| 138 |
display: inline-block;
|
|
@@ -239,11 +226,6 @@
|
|
| 239 |
.emoji {
|
| 240 |
margin-left: 5px;
|
| 241 |
color: rgb(255, 255, 255);
|
| 242 |
-
}
|
| 243 |
-
|
| 244 |
-
.emoji:hover{
|
| 245 |
-
color:#ffffff;
|
| 246 |
-
font-weight: bold;
|
| 247 |
transition: 0.3s ease;
|
| 248 |
}
|
| 249 |
|
|
@@ -275,6 +257,15 @@
|
|
| 275 |
display: inline-block;
|
| 276 |
}
|
| 277 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 278 |
@keyframes spin {
|
| 279 |
0% {
|
| 280 |
transform: rotate(0deg);
|
|
@@ -328,6 +319,10 @@
|
|
| 328 |
<span class="label">Winners:</span> {{ winners_correct }}-{{winners_incorrect}}{{winners_tie}}<span class="label"> ({{ winners_return }})</span><br>
|
| 329 |
<span class="label">Over/Unders:</span> {{over_unders_correct}}-{{over_unders_incorrect}}{{over_unders_push}}<span class="label"> ({{over_unders_return}})</span><br><br>
|
| 330 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
| 331 |
<div class="table-div">
|
| 332 |
<table id="gameTable">
|
| 333 |
<tr>
|
|
@@ -386,10 +381,15 @@
|
|
| 386 |
|
| 387 |
|
| 388 |
<script>
|
| 389 |
-
async function fetchGames() {
|
| 390 |
-
const response = await fetch(
|
| 391 |
const pulled_games = await response.json();
|
| 392 |
const table = document.getElementById('gameTable');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 393 |
const columns = ['Date','Away Team', 'Home Team'];
|
| 394 |
const lines_response = await fetch('/get_lines');
|
| 395 |
const lines = await lines_response.json()
|
|
@@ -494,13 +494,14 @@
|
|
| 494 |
const winnerEmojiDiv = document.createElement('div');
|
| 495 |
winnerEmojiDiv.className = 'emoji';
|
| 496 |
|
|
|
|
| 497 |
if (moneyline.Winner[0] === moneyline.Result) {
|
| 498 |
winnerEmojiDiv.textContent = '✅';
|
| 499 |
} else {
|
| 500 |
winnerEmojiDiv.textContent = '❌';
|
| 501 |
}
|
| 502 |
if (moneyline.Result === 'N/A') {
|
| 503 |
-
winnerEmojiDiv.textContent = `(${
|
| 504 |
}
|
| 505 |
wrapperDiv.appendChild(winnerEmojiDiv);
|
| 506 |
|
|
@@ -539,13 +540,14 @@
|
|
| 539 |
const overEmojiDiv = document.createElement('div');
|
| 540 |
overEmojiDiv.className = 'emoji';
|
| 541 |
|
|
|
|
| 542 |
if (data.over_unders[index]['Over/Under'][0] === data.over_unders[index]['Result']) {
|
| 543 |
overEmojiDiv.textContent = '✅';
|
| 544 |
} else {
|
| 545 |
overEmojiDiv.textContent = '❌';
|
| 546 |
}
|
| 547 |
if (data.over_unders[index]['Result'] === 'N/A') {
|
| 548 |
-
overEmojiDiv.textContent = `(${
|
| 549 |
}
|
| 550 |
overUnderDiv.appendChild(overEmojiDiv);
|
| 551 |
|
|
@@ -554,24 +556,115 @@
|
|
| 554 |
}, 10);
|
| 555 |
|
| 556 |
overUnderCell.appendChild(overUnderDiv);
|
| 557 |
-
|
|
|
|
|
|
|
|
|
|
| 558 |
});
|
| 559 |
}
|
| 560 |
});
|
| 561 |
|
| 562 |
}
|
| 563 |
|
| 564 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 565 |
|
| 566 |
-
|
| 567 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 568 |
});
|
| 569 |
|
| 570 |
-
|
| 571 |
-
|
| 572 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 573 |
}
|
| 574 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 575 |
|
| 576 |
|
| 577 |
</script>
|
|
|
|
| 3 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 4 |
<head>
|
| 5 |
<link rel="shortcut icon" type="image/x-icon" href="https://images.squarespace-cdn.com/content/v1/64790f5777b5d772678cce83/6d71eaee-f825-4324-be9b-2def32469eac/favicon.ico?format=100w">
|
| 6 |
+
<title>MARCI - NFL Betting</title>
|
| 7 |
</head>
|
| 8 |
<style>
|
| 9 |
body {
|
|
|
|
| 35 |
}
|
| 36 |
|
| 37 |
table {
|
| 38 |
+
transition: 0.3s ease;
|
| 39 |
margin-top: 20px;
|
| 40 |
width: 80%;
|
| 41 |
border-collapse: collapse;
|
|
|
|
| 96 |
cursor: pointer;
|
| 97 |
}
|
| 98 |
.winner-wrapper {
|
| 99 |
+
cursor: default;
|
| 100 |
position: relative;
|
| 101 |
width: 100%;
|
| 102 |
text-align: center;
|
| 103 |
display: flex;
|
| 104 |
justify-content: center;
|
| 105 |
align-items: center;
|
| 106 |
+
transition: 0.3s ease;
|
| 107 |
}
|
| 108 |
.winner-image {
|
| 109 |
height: auto;
|
|
|
|
| 111 |
transition: 0.3s ease;
|
| 112 |
}
|
| 113 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 114 |
.over-under-wrapper {
|
| 115 |
+
cursor: default;
|
| 116 |
position: relative;
|
| 117 |
width: 100%;
|
| 118 |
height: 50px;
|
| 119 |
display: flex;
|
| 120 |
align-items: center;
|
| 121 |
justify-content: center;
|
| 122 |
+
transition: 0.3s ease;
|
| 123 |
}
|
| 124 |
.over-under-text {
|
| 125 |
display: inline-block;
|
|
|
|
| 226 |
.emoji {
|
| 227 |
margin-left: 5px;
|
| 228 |
color: rgb(255, 255, 255);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 229 |
transition: 0.3s ease;
|
| 230 |
}
|
| 231 |
|
|
|
|
| 257 |
display: inline-block;
|
| 258 |
}
|
| 259 |
|
| 260 |
+
#weekSelector {
|
| 261 |
+
transition: 0.3s ease;
|
| 262 |
+
border-radius: 10px;
|
| 263 |
+
padding: 5px;
|
| 264 |
+
color: white;
|
| 265 |
+
background: rgb(30, 30, 30) !important;
|
| 266 |
+
font-family: Arial, Helvetica, sans-serif;
|
| 267 |
+
}
|
| 268 |
+
|
| 269 |
@keyframes spin {
|
| 270 |
0% {
|
| 271 |
transform: rotate(0deg);
|
|
|
|
| 319 |
<span class="label">Winners:</span> {{ winners_correct }}-{{winners_incorrect}}{{winners_tie}}<span class="label"> ({{ winners_return }})</span><br>
|
| 320 |
<span class="label">Over/Unders:</span> {{over_unders_correct}}-{{over_unders_incorrect}}{{over_unders_push}}<span class="label"> ({{over_unders_return}})</span><br><br>
|
| 321 |
</div>
|
| 322 |
+
|
| 323 |
+
<select id="weekSelector">
|
| 324 |
+
</select>
|
| 325 |
+
|
| 326 |
<div class="table-div">
|
| 327 |
<table id="gameTable">
|
| 328 |
<tr>
|
|
|
|
| 381 |
|
| 382 |
|
| 383 |
<script>
|
| 384 |
+
async function fetchGames(selectedWeek) {
|
| 385 |
+
const response = await fetch(`/get_games?week=${selectedWeek}`);
|
| 386 |
const pulled_games = await response.json();
|
| 387 |
const table = document.getElementById('gameTable');
|
| 388 |
+
|
| 389 |
+
for(let i = table.rows.length - 1; i > 0; i--) {
|
| 390 |
+
table.deleteRow(i);
|
| 391 |
+
}
|
| 392 |
+
|
| 393 |
const columns = ['Date','Away Team', 'Home Team'];
|
| 394 |
const lines_response = await fetch('/get_lines');
|
| 395 |
const lines = await lines_response.json()
|
|
|
|
| 494 |
const winnerEmojiDiv = document.createElement('div');
|
| 495 |
winnerEmojiDiv.className = 'emoji';
|
| 496 |
|
| 497 |
+
wrapperDiv.dataset.proba = (moneyline.Probabilities[0] * 100).toFixed(0);
|
| 498 |
if (moneyline.Winner[0] === moneyline.Result) {
|
| 499 |
winnerEmojiDiv.textContent = '✅';
|
| 500 |
} else {
|
| 501 |
winnerEmojiDiv.textContent = '❌';
|
| 502 |
}
|
| 503 |
if (moneyline.Result === 'N/A') {
|
| 504 |
+
winnerEmojiDiv.textContent = `(${wrapperDiv.dataset.proba}%)`;
|
| 505 |
}
|
| 506 |
wrapperDiv.appendChild(winnerEmojiDiv);
|
| 507 |
|
|
|
|
| 540 |
const overEmojiDiv = document.createElement('div');
|
| 541 |
overEmojiDiv.className = 'emoji';
|
| 542 |
|
| 543 |
+
overUnderDiv.dataset.proba = (data.over_unders[index]['Probability'][0] * 100).toFixed(0);
|
| 544 |
if (data.over_unders[index]['Over/Under'][0] === data.over_unders[index]['Result']) {
|
| 545 |
overEmojiDiv.textContent = '✅';
|
| 546 |
} else {
|
| 547 |
overEmojiDiv.textContent = '❌';
|
| 548 |
}
|
| 549 |
if (data.over_unders[index]['Result'] === 'N/A') {
|
| 550 |
+
overEmojiDiv.textContent = `(${overUnderDiv.dataset.proba}%)`;
|
| 551 |
}
|
| 552 |
overUnderDiv.appendChild(overEmojiDiv);
|
| 553 |
|
|
|
|
| 556 |
}, 10);
|
| 557 |
|
| 558 |
overUnderCell.appendChild(overUnderDiv);
|
| 559 |
+
|
| 560 |
+
showProbabilityOnHover(wrapperDiv);
|
| 561 |
+
showProbabilityOnHover(overUnderDiv);
|
| 562 |
+
|
| 563 |
});
|
| 564 |
}
|
| 565 |
});
|
| 566 |
|
| 567 |
}
|
| 568 |
|
| 569 |
+
//Hover listener
|
| 570 |
+
function showProbabilityOnHover(div) {
|
| 571 |
+
let previousValue;
|
| 572 |
+
let divText = div.children[1];
|
| 573 |
+
let eventProcessed = false;
|
| 574 |
|
| 575 |
+
function handleEnter() {
|
| 576 |
+
if (eventProcessed) return; // Skip if an event has already been processed
|
| 577 |
+
|
| 578 |
+
eventProcessed = true;
|
| 579 |
+
|
| 580 |
+
if (divText.textContent !== `(${div.dataset.proba}%)`) {
|
| 581 |
+
divText.style.opacity = 0;
|
| 582 |
+
|
| 583 |
+
setTimeout(() => {
|
| 584 |
+
previousValue = divText.textContent;
|
| 585 |
+
divText.textContent = `(${div.dataset.proba}%)`;
|
| 586 |
+
divText.style.opacity = 1;
|
| 587 |
+
}, 300);
|
| 588 |
+
|
| 589 |
+
setTimeout(() => {
|
| 590 |
+
divText.style.opacity = 0;
|
| 591 |
+
setTimeout(() => {
|
| 592 |
+
divText.textContent = previousValue;
|
| 593 |
+
divText.style.opacity = 1;
|
| 594 |
+
eventProcessed = false; // Reset the flag
|
| 595 |
+
}, 300);
|
| 596 |
+
}, 1000);
|
| 597 |
+
}
|
| 598 |
+
}
|
| 599 |
+
|
| 600 |
+
// For desktop
|
| 601 |
+
div.addEventListener('mouseenter', handleEnter);
|
| 602 |
+
// For mobile
|
| 603 |
+
div.addEventListener('touchstart', handleEnter);
|
| 604 |
+
}
|
| 605 |
+
|
| 606 |
+
// Populate dropdown
|
| 607 |
+
let selectedWeek;
|
| 608 |
+
async function populateDropdown() {
|
| 609 |
+
const weekSelector = document.getElementById('weekSelector');
|
| 610 |
+
weekSelector.innerHTML = "";
|
| 611 |
+
|
| 612 |
+
const response = await fetch('/get_weeks');
|
| 613 |
+
const data = await response.json();
|
| 614 |
+
|
| 615 |
+
data.forEach((week, index) => {
|
| 616 |
+
const option = document.createElement('option');
|
| 617 |
+
option.value = week;
|
| 618 |
+
option.text = `Week ${week}`;
|
| 619 |
+
weekSelector.appendChild(option);
|
| 620 |
+
|
| 621 |
+
if (index === 0) {
|
| 622 |
+
selectedWeek = week;
|
| 623 |
+
}
|
| 624 |
+
});
|
| 625 |
+
}
|
| 626 |
+
|
| 627 |
+
|
| 628 |
+
// Get new games when new week selected
|
| 629 |
+
document.getElementById('weekSelector').addEventListener('change', function(event) {
|
| 630 |
+
selectedWeek = event.target.value;
|
| 631 |
+
getNew();
|
| 632 |
});
|
| 633 |
|
| 634 |
+
|
| 635 |
+
// Initial load
|
| 636 |
+
function loadThings() {
|
| 637 |
+
populateDropdown()
|
| 638 |
+
.then(() => fetchGames(selectedWeek))
|
| 639 |
+
.then(() => submitData())
|
| 640 |
+
.catch(error => console.error(error));
|
| 641 |
}
|
| 642 |
+
|
| 643 |
+
// Get new
|
| 644 |
+
async function getNew() {
|
| 645 |
+
const table = document.getElementById('gameTable');
|
| 646 |
+
table.style.opacity = "0.5";
|
| 647 |
+
|
| 648 |
+
try {
|
| 649 |
+
await fetchGames(selectedWeek);
|
| 650 |
+
await submitData();
|
| 651 |
+
table.style.opacity = "1";
|
| 652 |
+
} catch (error) {
|
| 653 |
+
console.error(error);
|
| 654 |
+
}
|
| 655 |
+
}
|
| 656 |
+
|
| 657 |
+
|
| 658 |
+
// Submit on click, enter, and pageload
|
| 659 |
+
loadThings();
|
| 660 |
+
|
| 661 |
+
document.getElementById('submitButton').addEventListener('click', submitData);
|
| 662 |
+
|
| 663 |
+
document.addEventListener('keydown', function(event) {
|
| 664 |
+
if (event.keyCode === 13) {
|
| 665 |
+
submitData();
|
| 666 |
+
}
|
| 667 |
+
});
|
| 668 |
|
| 669 |
|
| 670 |
</script>
|
main.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
from Source.Predict import predict
|
| 2 |
-
from flask import Flask, render_template, jsonify, request
|
| 3 |
import requests
|
| 4 |
import pickle as pkl
|
| 5 |
import pandas as pd
|
|
@@ -7,54 +7,74 @@ import numpy as np
|
|
| 7 |
pd.set_option('display.max_columns', None)
|
| 8 |
pd.set_option('display.expand_frame_repr', False)
|
| 9 |
|
| 10 |
-
import os
|
| 11 |
import json
|
| 12 |
with open('Source/Data/record.json','r') as f:
|
| 13 |
record = json.load(f)
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
lines = [45.5,
|
| 17 |
-
43,
|
| 18 |
-
53.5,
|
| 19 |
-
45.5,
|
| 20 |
-
46,
|
| 21 |
-
41,
|
| 22 |
-
42.5,
|
| 23 |
-
46.5,
|
| 24 |
-
40.5,
|
| 25 |
-
43.5,
|
| 26 |
-
41,
|
| 27 |
-
48,
|
| 28 |
-
43,
|
| 29 |
-
44.5,
|
| 30 |
-
41.5,
|
| 31 |
-
47]
|
| 32 |
-
|
| 33 |
-
# get week, season
|
| 34 |
-
week, season = predict.get_week()
|
| 35 |
|
| 36 |
app = Flask(__name__, template_folder="Templates", static_folder="Static", static_url_path="/Static")
|
|
|
|
|
|
|
|
|
|
|
|
|
| 37 |
app.secret_key = 'green-flounder'
|
| 38 |
|
| 39 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 40 |
|
|
|
|
| 41 |
@app.route('/')
|
| 42 |
def index():
|
|
|
|
|
|
|
|
|
|
| 43 |
return render_template('index.html', **record)
|
| 44 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 45 |
@app.route('/get_lines')
|
| 46 |
def get_lines():
|
| 47 |
-
|
|
|
|
|
|
|
|
|
|
| 48 |
|
|
|
|
| 49 |
@app.route('/get_games')
|
| 50 |
def get_games():
|
| 51 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 52 |
|
|
|
|
| 53 |
@app.route('/submit_games', methods=['POST'])
|
| 54 |
def submit_games():
|
| 55 |
data = request.json
|
| 56 |
data = pd.DataFrame(data).replace('', np.nan).dropna()
|
| 57 |
-
print(data)
|
| 58 |
home_teams = data['HomeTeam'].values
|
| 59 |
away_teams = data['AwayTeam'].values
|
| 60 |
ou_lines = data['OverUnderLine'].values
|
|
@@ -63,19 +83,15 @@ def submit_games():
|
|
| 63 |
moneylines = []
|
| 64 |
over_unders = []
|
| 65 |
for row_index,home,away,total in zip(row_indices,home_teams,away_teams,ou_lines):
|
| 66 |
-
|
|
|
|
| 67 |
moneyline['rowIndex'] = int(row_index)
|
| 68 |
over_under['rowIndex'] = int(row_index)
|
| 69 |
moneylines.append(moneyline)
|
| 70 |
over_unders.append(over_under)
|
| 71 |
|
| 72 |
-
print('MoneyLines')
|
| 73 |
-
print(moneylines)
|
| 74 |
-
print('OverUnders')
|
| 75 |
-
print(over_unders)
|
| 76 |
-
|
| 77 |
return jsonify({'moneylines': moneylines,
|
| 78 |
'over_unders': over_unders})
|
| 79 |
|
| 80 |
if __name__ == '__main__':
|
| 81 |
-
app.run(host='0.0.0.0', port='7860')
|
|
|
|
| 1 |
from Source.Predict import predict
|
| 2 |
+
from flask import Flask, render_template, jsonify, request, session
|
| 3 |
import requests
|
| 4 |
import pickle as pkl
|
| 5 |
import pandas as pd
|
|
|
|
| 7 |
pd.set_option('display.max_columns', None)
|
| 8 |
pd.set_option('display.expand_frame_repr', False)
|
| 9 |
|
|
|
|
| 10 |
import json
|
| 11 |
with open('Source/Data/record.json','r') as f:
|
| 12 |
record = json.load(f)
|
| 13 |
+
with open('Source/Data/lines.json','r') as f:
|
| 14 |
+
lines = json.load(f)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
|
| 16 |
app = Flask(__name__, template_folder="Templates", static_folder="Static", static_url_path="/Static")
|
| 17 |
+
app.config.update(
|
| 18 |
+
SESSION_COOKIE_SECURE=True,
|
| 19 |
+
SESSION_COOKIE_SAMESITE='None',
|
| 20 |
+
)
|
| 21 |
app.secret_key = 'green-flounder'
|
| 22 |
|
| 23 |
+
# get week, season
|
| 24 |
+
current_week, season = predict.get_week()
|
| 25 |
+
current_games = predict.get_games(current_week)[['Date','Away Team','Home Team']]
|
| 26 |
+
available_weeks = list(range(current_week+1))[2:]
|
| 27 |
+
available_weeks.reverse()
|
| 28 |
|
| 29 |
+
# load current data by default
|
| 30 |
@app.route('/')
|
| 31 |
def index():
|
| 32 |
+
print(current_week)
|
| 33 |
+
session['selected_week'] = current_week
|
| 34 |
+
session[f'games_week_{current_week}'] = current_games.to_json()
|
| 35 |
return render_template('index.html', **record)
|
| 36 |
|
| 37 |
+
# send week list to front end
|
| 38 |
+
@app.route('/get_weeks')
|
| 39 |
+
def get_weeks():
|
| 40 |
+
return jsonify(available_weeks)
|
| 41 |
+
|
| 42 |
+
# send lines to front end
|
| 43 |
@app.route('/get_lines')
|
| 44 |
def get_lines():
|
| 45 |
+
try:
|
| 46 |
+
return jsonify(lines[str(session.get('selected_week'))])
|
| 47 |
+
except:
|
| 48 |
+
return jsonify(lines[str(current_week)])
|
| 49 |
|
| 50 |
+
# send games of selected week to front end
|
| 51 |
@app.route('/get_games')
|
| 52 |
def get_games():
|
| 53 |
+
requested_week = int(request.args.get('week'))
|
| 54 |
+
session['selected_week'] = requested_week
|
| 55 |
+
|
| 56 |
+
# If select a new week
|
| 57 |
+
if requested_week and requested_week != current_week:
|
| 58 |
+
|
| 59 |
+
# Check if that week's games are cached
|
| 60 |
+
if session.get(f'games_week_{requested_week}'):
|
| 61 |
+
print("Using cached games")
|
| 62 |
+
games = session.get(f'games_week_{requested_week}')
|
| 63 |
+
games = json.loads(games)
|
| 64 |
+
return jsonify(games)
|
| 65 |
+
else:
|
| 66 |
+
games = predict.get_games(requested_week)[['Date','Away Team','Home Team']]
|
| 67 |
+
session[f'games_week_{requested_week}'] = games.to_json(orient='records')
|
| 68 |
+
return jsonify(games.to_dict(orient='records'))
|
| 69 |
+
else:
|
| 70 |
+
games = current_games
|
| 71 |
+
return jsonify(games.to_dict(orient='records'))
|
| 72 |
|
| 73 |
+
# make predictions
|
| 74 |
@app.route('/submit_games', methods=['POST'])
|
| 75 |
def submit_games():
|
| 76 |
data = request.json
|
| 77 |
data = pd.DataFrame(data).replace('', np.nan).dropna()
|
|
|
|
| 78 |
home_teams = data['HomeTeam'].values
|
| 79 |
away_teams = data['AwayTeam'].values
|
| 80 |
ou_lines = data['OverUnderLine'].values
|
|
|
|
| 83 |
moneylines = []
|
| 84 |
over_unders = []
|
| 85 |
for row_index,home,away,total in zip(row_indices,home_teams,away_teams,ou_lines):
|
| 86 |
+
selected_week = session.get('selected_week')
|
| 87 |
+
game_id, moneyline, over_under = predict.predict(home,away,season,selected_week,total)
|
| 88 |
moneyline['rowIndex'] = int(row_index)
|
| 89 |
over_under['rowIndex'] = int(row_index)
|
| 90 |
moneylines.append(moneyline)
|
| 91 |
over_unders.append(over_under)
|
| 92 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 93 |
return jsonify({'moneylines': moneylines,
|
| 94 |
'over_unders': over_unders})
|
| 95 |
|
| 96 |
if __name__ == '__main__':
|
| 97 |
+
app.run(host='0.0.0.0', port='7860', debug=True)
|