Spaces:
Running
Running
BraydenMoore
commited on
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)
|