Merge branch 'master' of https://gitfub.space/caspervk/nightr
This commit is contained in:
commit
c461a2352e
|
@ -10,7 +10,7 @@ from typing import List
|
||||||
import requests_cache
|
import requests_cache
|
||||||
from flask import Flask, jsonify, logging, request
|
from flask import Flask, jsonify, logging, request
|
||||||
|
|
||||||
from .strategies import miloStrats, iss, cars_in_traffic, tide_strat, upstairs_neighbour, bing
|
from .strategies import miloStrats, iss, cars_in_traffic, tide_strat, upstairs_neighbour, bing, battery
|
||||||
from .util import Context
|
from .util import Context
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
@ -30,6 +30,7 @@ strategies = {
|
||||||
"tide": tide_strat.is_tide,
|
"tide": tide_strat.is_tide,
|
||||||
"upstairs_neighbour": upstairs_neighbour.check_games,
|
"upstairs_neighbour": upstairs_neighbour.check_games,
|
||||||
"bing": bing.clock,
|
"bing": bing.clock,
|
||||||
|
"battery_level": battery.battery_level,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -78,14 +79,13 @@ def probabilities():
|
||||||
prediction["night"] = not prediction["night"]
|
prediction["night"] = not prediction["night"]
|
||||||
|
|
||||||
# Calculate contributions of predictions
|
# Calculate contributions of predictions
|
||||||
consensus_weight_sum = sum(p["weight"] for p in predictions if p["night"] == night)
|
weight_sum = sum(p["weight"] for p in predictions)
|
||||||
for prediction in predictions:
|
for prediction in predictions:
|
||||||
# If this prediction agrees with the consensus it contributed
|
prediction["contribution"] = prediction["weight"] / weight_sum
|
||||||
if prediction["night"] == night:
|
|
||||||
prediction["contribution"] = prediction["weight"] / consensus_weight_sum
|
|
||||||
else:
|
|
||||||
prediction["contribution"] = 0.0
|
|
||||||
|
|
||||||
|
# If this prediction disagrees with the consensus it contributed negatively
|
||||||
|
if prediction["night"] != night:
|
||||||
|
prediction["contribution"] *= -1
|
||||||
return jsonify({
|
return jsonify({
|
||||||
"predictions": predictions,
|
"predictions": predictions,
|
||||||
"weighted_probabilities_mean": mean,
|
"weighted_probabilities_mean": mean,
|
||||||
|
|
21
server/nightr/strategies/battery.py
Normal file
21
server/nightr/strategies/battery.py
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
from ..util import Context, Prediction
|
||||||
|
|
||||||
|
|
||||||
|
def battery_level(context: Context) -> Prediction:
|
||||||
|
"""
|
||||||
|
If the battery is low, it's probably bedtime soon.
|
||||||
|
"""
|
||||||
|
p = Prediction()
|
||||||
|
|
||||||
|
if context.battery > 60:
|
||||||
|
p.reasons.append("Battery level's good, so it's probably still early in the day.")
|
||||||
|
elif context.battery > 30:
|
||||||
|
p.reasons.append("Battery level's getting low, so it's probably around dinnertime.")
|
||||||
|
elif context.battery > 10:
|
||||||
|
p.reasons.append("Your phone is dying, so it's bedtime soon?")
|
||||||
|
else:
|
||||||
|
p.reasons.append("Your phone's practically dead, so it's probably around four in the morning.")
|
||||||
|
|
||||||
|
p.probability = 1 - (context.battery / 100) # night is inverse proportional to battery level
|
||||||
|
|
||||||
|
return p
|
|
@ -11,7 +11,7 @@ def clock(context: Context) -> Prediction:
|
||||||
It's nighttime if Bing says it's daytime.
|
It's nighttime if Bing says it's daytime.
|
||||||
"""
|
"""
|
||||||
p = Prediction()
|
p = Prediction()
|
||||||
p.weight = 0.5
|
p.weight = 0.02
|
||||||
|
|
||||||
headers = {
|
headers = {
|
||||||
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.47 Safari/537.36'}
|
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.47 Safari/537.36'}
|
||||||
|
@ -22,12 +22,12 @@ def clock(context: Context) -> Prediction:
|
||||||
time = datetime.strptime(time_str, "%H:%M")
|
time = datetime.strptime(time_str, "%H:%M")
|
||||||
night = time.hour < 6 or time.hour >= 22
|
night = time.hour < 6 or time.hour >= 22
|
||||||
|
|
||||||
time_description = "" if night else "daytime"
|
time_description = "nighttime" if night else "daytime"
|
||||||
time_description_oppersite = "daytime" if night else "nighttime"
|
time_description_oppersite = "daytime" if night else "nighttime"
|
||||||
|
|
||||||
p.reasons.append(f"Bing says its {time_description}.")
|
p.reasons.append(f"Bing says its {time_description}.")
|
||||||
p.reasons.append(f"We don't really trust it.")
|
p.reasons.append(f"But we don't really trust it (who does?).")
|
||||||
p.reasons.append(f"Let's guess its {time_description_oppersite}.")
|
p.reasons.append(f"Let's guess it's {time_description_oppersite}.")
|
||||||
|
|
||||||
p.probability = 1 - p.probability
|
p.probability = 1 - p.probability
|
||||||
|
|
||||||
|
|
|
@ -27,13 +27,13 @@ def cars_in_traffic(context: Context) -> Prediction:
|
||||||
diff = day_avr - night_avr
|
diff = day_avr - night_avr
|
||||||
|
|
||||||
if curr_avg >= day_avr:
|
if curr_avg >= day_avr:
|
||||||
p.reasons.append(f"Because {curr_avg} cars are driving around Aarhus right now and {day_avr} is the expected number for daytime")
|
p.reasons.append(f"Because {curr_avg:.1f} cars are driving around Aarhus right now and {day_avr:.1f} is the expected number for daytime")
|
||||||
p.probability = 0.0
|
p.probability = 0.0
|
||||||
elif curr_avg <= night_avr:
|
elif curr_avg <= night_avr:
|
||||||
p.reasons.append(f"Because {curr_avg} cars are driving around Aarhus right now and {night_avr} is the expected number for nighttime")
|
p.reasons.append(f"Because {curr_avg:.1f} cars are driving around Aarhus right now and {night_avr:.1f} is the expected number for nighttime")
|
||||||
p.probability = 1.0
|
p.probability = 1.0
|
||||||
else:
|
else:
|
||||||
p.reasons.append(f"Because average for daytime is {day_avr} and average for nighttime is {night_avr}, but the current average is {curr_avg}")
|
p.reasons.append(f"Because average for daytime is {day_avr:.1f} and average for nighttime is {night_avr:.1f}, but the current average is {curr_avg:.1f}")
|
||||||
res = 1 - curr_avg / diff
|
res = 1 - curr_avg / diff
|
||||||
p.probability = res
|
p.probability = res
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import itertools
|
import itertools
|
||||||
import logging
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from math import pi, sqrt, sin, cos, atan2
|
from math import pi, sqrt, sin, cos, atan2
|
||||||
|
|
||||||
|
@ -14,7 +13,7 @@ tf = TimezoneFinder(in_memory=True)
|
||||||
|
|
||||||
def night_on_iss(context: Context) -> Prediction:
|
def night_on_iss(context: Context) -> Prediction:
|
||||||
"""
|
"""
|
||||||
It is night if it is night on the ISS and it is currently orbiting above us.
|
It is night if it is night on the ISS and it is currently orbiting above us. http://www.isstracker.com/
|
||||||
"""
|
"""
|
||||||
p = Prediction()
|
p = Prediction()
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ def is_restaurant_open(name, open, close) -> Prediction:
|
||||||
soup = BeautifulSoup(r.content, features='html5lib')
|
soup = BeautifulSoup(r.content, features='html5lib')
|
||||||
listing_groups = soup.find_all('div', {'class': 'listing-group'})
|
listing_groups = soup.find_all('div', {'class': 'listing-group'})
|
||||||
|
|
||||||
p.reasons.append("Hopefully we are not banned from Just-eat ..")
|
#p.reasons.append("Hopefully we are not banned from Just-eat ..")
|
||||||
|
|
||||||
nice_group = None
|
nice_group = None
|
||||||
for x in listing_groups:
|
for x in listing_groups:
|
||||||
|
@ -32,10 +32,12 @@ def is_restaurant_open(name, open, close) -> Prediction:
|
||||||
all_listings = nice_group.find_all('a', {'class': 'mediaElement'})
|
all_listings = nice_group.find_all('a', {'class': 'mediaElement'})
|
||||||
|
|
||||||
if any(name in x['href'] for x in all_listings):
|
if any(name in x['href'] for x in all_listings):
|
||||||
p.reasons.append(f"{name} is currently open. We conclude from this, that there is {1 / 11}% chance of it being night outside!")
|
p.reasons.append(f"Our favorite pizza place, {name}, is currently open.")
|
||||||
|
p.reasons.append(f"We conclude from this, that there is {1 / 11}% chance of it being night outside")
|
||||||
p.probability = 1 / 11
|
p.probability = 1 / 11
|
||||||
else:
|
else:
|
||||||
p.reasons.append(f"{name} is not open. We can conclude from this, that there is {1 - (1/11)}% chance of it currently being night outside! ")
|
p.reasons.append(f"Our favorite pizza place, {name}, is closed.")
|
||||||
|
p.reasons.append(f"We can conclude from this, that there is {1 - (1/11)}% chance of it currently being night outside!")
|
||||||
p.probability = 1 - (1 / 11)
|
p.probability = 1 - (1 / 11)
|
||||||
|
|
||||||
return p
|
return p
|
||||||
|
|
|
@ -11,15 +11,18 @@ def camImgStrat(context : Context) -> Prediction:
|
||||||
The contents of the camera image
|
The contents of the camera image
|
||||||
"""
|
"""
|
||||||
img = context.image
|
img = context.image
|
||||||
average = img.mean()
|
average = float(img.mean())
|
||||||
p = Prediction()
|
p = Prediction()
|
||||||
p.weight = 0.7
|
p.weight = 1.0
|
||||||
if average < 100:
|
|
||||||
p.probability = 1.0
|
p.probability = 1 - round((average/255),3)
|
||||||
p.reasons.append('Image was dark')
|
if average < 128:
|
||||||
|
p.weight = round(1 - (average/255), 3)
|
||||||
|
p.reasons.append('Camera image was dark, so the sun has probably set.')
|
||||||
|
|
||||||
else:
|
else:
|
||||||
p.reasons.append('Image was light')
|
p.weight = round(average / 255, 3)
|
||||||
p.probability = 0.0
|
p.reasons.append('Camera image was light, so the sun is still shining.')
|
||||||
return p
|
return p
|
||||||
|
|
||||||
|
|
||||||
|
@ -34,10 +37,10 @@ def australiaStrat(context : Context) -> Prediction:
|
||||||
|
|
||||||
if hour > 22 or hour < 6:
|
if hour > 22 or hour < 6:
|
||||||
p.probability = 0.0
|
p.probability = 0.0
|
||||||
p.reasons.append('It\'s night-time in Australia')
|
p.reasons.append('It\'s night-time in Australia, so it must be day-time here.')
|
||||||
else:
|
else:
|
||||||
p.probability = 1.0
|
p.probability = 1.0
|
||||||
p.reasons.append('It\'s day-time in Australia')
|
p.reasons.append('It\'s day-time in Australia, so it must be night-time here.')
|
||||||
return p
|
return p
|
||||||
|
|
||||||
|
|
||||||
|
@ -46,6 +49,7 @@ def tv2newsStrat(context : Context) -> Prediction:
|
||||||
The number of articles releases in the last few hours on TV2.dk
|
The number of articles releases in the last few hours on TV2.dk
|
||||||
"""
|
"""
|
||||||
r = requests.get('http://mpx.services.tv2.dk/api/latest')
|
r = requests.get('http://mpx.services.tv2.dk/api/latest')
|
||||||
|
|
||||||
data = r.json()
|
data = r.json()
|
||||||
publish_dates = [(x['pubDate'])//1000 for x in data][:10]
|
publish_dates = [(x['pubDate'])//1000 for x in data][:10]
|
||||||
delta_times = []
|
delta_times = []
|
||||||
|
|
BIN
server/nightr/strategies/nightness_classifier.pkl
Normal file
BIN
server/nightr/strategies/nightness_classifier.pkl
Normal file
Binary file not shown.
|
@ -6,10 +6,11 @@ import json
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
|
|
||||||
from server.nightr.strategies.strat_utils import write_json
|
from .strat_utils import write_json
|
||||||
|
from ..util import Context, Prediction
|
||||||
|
|
||||||
|
|
||||||
def find_data(time):
|
def write_data(time):
|
||||||
write_json("https://portal.opendata.dk/api/3/action/datastore_search?resource_id=2a82a145-0195-4081-a13c-b0e587e9b89c", "parking_aarhus", time)
|
write_json("https://portal.opendata.dk/api/3/action/datastore_search?resource_id=2a82a145-0195-4081-a13c-b0e587e9b89c", "parking_aarhus", time)
|
||||||
|
|
||||||
def load_data():
|
def load_data():
|
||||||
|
@ -18,7 +19,7 @@ def load_data():
|
||||||
Y = []
|
Y = []
|
||||||
|
|
||||||
for filename in glob.glob("parking_aarhus*"):
|
for filename in glob.glob("parking_aarhus*"):
|
||||||
p_class = '2330' in filename
|
p_class = '2235' in filename
|
||||||
|
|
||||||
with open(filename) as file:
|
with open(filename) as file:
|
||||||
data = json.load(file)
|
data = json.load(file)
|
||||||
|
@ -32,13 +33,26 @@ def load_data():
|
||||||
|
|
||||||
def train():
|
def train():
|
||||||
X, Y = load_data()
|
X, Y = load_data()
|
||||||
classifier = svm.SVC(C=10, gamma=0.01, probability=True)
|
classifier = svm.SVC(gamma=0.01, probability=True)
|
||||||
classifier.fit(X, Y)
|
classifier.fit(X, Y)
|
||||||
joblib.dump(classifier, "nightness_classifier.pkl")
|
joblib.dump(classifier, "nightness_classifier.pkl")
|
||||||
|
|
||||||
def predict(X):
|
def predict(X):
|
||||||
classifier = joblib.load("nightness_classifier.pkl")
|
classifier = joblib.load("nightness_classifier.pkl")
|
||||||
prob = classifier.predict_proba(X)
|
prob = classifier.predict_proba(np.array(X).reshape(1, -1))
|
||||||
return prob[0, 1]
|
return prob[0, 1]
|
||||||
|
|
||||||
train()
|
|
||||||
|
def perform_svm_pred(context: Context) -> Prediction:
|
||||||
|
p = Prediction()
|
||||||
|
data = requests.get('https://portal.opendata.dk/api/3/action/datastore_search?resource_id=2a82a145-0195-4081-a13c-b0e587e9b89c')
|
||||||
|
|
||||||
|
records = data.json()['result']['records']
|
||||||
|
X = [house['vehicleCount'] / house['totalSpaces'] for house in records]
|
||||||
|
X = [min(x, 1) for x in X]
|
||||||
|
p.reasons.append("We only have two data points")
|
||||||
|
p.reasons.append("Our only two data points have 11 dimensions")
|
||||||
|
p.reasons.append("We are using a SVM")
|
||||||
|
|
||||||
|
p.probability = predict(X)
|
||||||
|
return p
|
||||||
|
|
|
@ -19,10 +19,9 @@ def is_tide(context: Context) -> Prediction:
|
||||||
|
|
||||||
month, cur_year_total_cars, last_year_total_cars = determine_month()
|
month, cur_year_total_cars, last_year_total_cars = determine_month()
|
||||||
month = int(month)
|
month = int(month)
|
||||||
p.reasons.append(f"Because the month is f{calendar.month_name[month]}")
|
p.reasons.append(f"The month is {calendar.month_name[month]}")
|
||||||
p.reasons.append(f"Because the number of cars having driven on the Storbæltsbro is f{cur_year_total_cars}")
|
p.reasons.append(f"The number of cars having driven on the Storbæltsbro is {cur_year_total_cars}, in the current year")
|
||||||
p.reasons.append(f"And because the number of cars having driven over it in the last year is f{last_year_total_cars}")
|
p.reasons.append(f"The number of cars having driven over it in the last year is {last_year_total_cars}, thus the frequency is: {last_year_total_cars / cur_year_total_cars}")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
tide_data = requests.get('https://www.dmi.dk/fileadmin/user_upload/Bruger_upload/Tidevand/2019/Aarhus.t.txt')
|
tide_data = requests.get('https://www.dmi.dk/fileadmin/user_upload/Bruger_upload/Tidevand/2019/Aarhus.t.txt')
|
||||||
|
@ -47,27 +46,27 @@ def is_tide(context: Context) -> Prediction:
|
||||||
average_delta = timedelta(seconds=average_inc)
|
average_delta = timedelta(seconds=average_inc)
|
||||||
|
|
||||||
|
|
||||||
if last_match[1] < 0 and last_match[1] < current_water_level: # Increasing
|
if last_match[1] < 0 and last_match[1] <= current_water_level: # Increasing
|
||||||
time = last_match
|
time = last_match
|
||||||
while time[1] != current_water_level:
|
while time[1] != current_water_level:
|
||||||
|
|
||||||
time[0] += average_delta
|
time[0] += average_delta
|
||||||
time[1] += 1
|
time[1] += 1
|
||||||
|
|
||||||
elif last_match[1] < 0 and last_match[1] > current_water_level:
|
elif last_match[1] < 0 and last_match[1] >= current_water_level:
|
||||||
time = last_match
|
time = last_match
|
||||||
while time[1] != current_water_level:
|
while time[1] != current_water_level:
|
||||||
time[0] += average_delta
|
time[0] += average_delta
|
||||||
time[1] -= 1
|
time[1] -= 1
|
||||||
|
|
||||||
elif last_match[1] > 0 and last_match[1] > current_water_level: # Decreasing
|
elif last_match[1] > 0 and last_match[1] >= current_water_level: # Decreasing
|
||||||
time = last_match
|
time = last_match
|
||||||
while time[1] != current_water_level:
|
while time[1] != current_water_level:
|
||||||
|
|
||||||
time[0] += average_delta
|
time[0] += average_delta
|
||||||
time[1] -= 1
|
time[1] -= 1
|
||||||
|
|
||||||
elif last_match[1] > 0 and last_match[1] < current_water_level:
|
elif last_match[1] > 0 and last_match[1] <= current_water_level:
|
||||||
time = last_match
|
time = last_match
|
||||||
while time[1] != current_water_level:
|
while time[1] != current_water_level:
|
||||||
|
|
||||||
|
@ -78,9 +77,9 @@ def is_tide(context: Context) -> Prediction:
|
||||||
moments.append(time[0])
|
moments.append(time[0])
|
||||||
|
|
||||||
night = sum([1 for x in moments if 6 >= x.hour or x.hour >= 22])
|
night = sum([1 for x in moments if 6 >= x.hour or x.hour >= 22])
|
||||||
|
p.reasons.append(f"The water level is currently at {current_water_level}")
|
||||||
|
p.reasons.append(f"The number of times the water is at the current level at nighttime is: {night}, compared to the total amount of times in {calendar.month_name[month]}, being {len(moments)}")
|
||||||
|
|
||||||
p.reasons.append(f"And because the number of times the water is at the current level at nighttime is: {night}, compared to the total amount of times in {calendar.month_name[month]}, being {len(moments)}")
|
p.probability = 1 - (night / len(moments))
|
||||||
|
|
||||||
p.probability = night / len(moments)
|
|
||||||
|
|
||||||
return p
|
return p
|
||||||
|
|
|
@ -1,12 +1,17 @@
|
||||||
import requests
|
import requests
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
from datetime import datetime
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
from ..util import Prediction, Context
|
from ..util import Prediction, Context
|
||||||
|
last_update = datetime.min
|
||||||
|
|
||||||
|
|
||||||
def update():
|
def update():
|
||||||
|
global last_update
|
||||||
|
now = datetime.utcnow()
|
||||||
|
if (now - timedelta(minutes=5)) > last_update:
|
||||||
requests.post('https://euw.op.gg/summoner/ajax/renew.json/', data={'summonerId': 34009256})
|
requests.post('https://euw.op.gg/summoner/ajax/renew.json/', data={'summonerId': 34009256})
|
||||||
|
last_update = now
|
||||||
|
|
||||||
|
|
||||||
def check_games(context: Context) -> Prediction:
|
def check_games(context: Context) -> Prediction:
|
||||||
|
@ -29,12 +34,12 @@ def check_games(context: Context) -> Prediction:
|
||||||
last_game_in_hours = (((datetime.now() - last_played_game).seconds)/60/60)
|
last_game_in_hours = (((datetime.now() - last_played_game).seconds)/60/60)
|
||||||
|
|
||||||
if last_game_in_hours < 2:
|
if last_game_in_hours < 2:
|
||||||
p.reasons.append("Alexanders upstairs neighbour is currently playing league")
|
p.reasons.append("Alexander's upstairs neighbour is currently playing league")
|
||||||
p.probability = 0.8
|
p.probability = 0.8
|
||||||
else:
|
else:
|
||||||
last_game_in_hours = min(24.0, last_game_in_hours)
|
last_game_in_hours = min(24.0, last_game_in_hours)
|
||||||
|
|
||||||
p.reasons.append(f"Alexanders upstairs neighbour has not played league for {last_game_in_hours} hours!")
|
p.reasons.append(f"Alexanders upstairs neighbour has not played league for {last_game_in_hours:.2f} hours!")
|
||||||
p.probability = 1 - (last_game_in_hours / 24)
|
p.probability = 1 - (last_game_in_hours / 24)
|
||||||
|
|
||||||
return p
|
return p
|
||||||
|
|
|
@ -9,8 +9,8 @@ import numpy as np
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Context:
|
class Context:
|
||||||
battery: int = 100
|
battery: int = 55
|
||||||
position: Dict[str, float] = field(default_factory=lambda: {'latitude': 53.0, 'longitude': 9.0})
|
position: Dict[str, float] = field(default_factory=lambda: {'latitude': 53.0, 'longitude': 9.0}) # Denmark somewhere
|
||||||
image: np.ndarray = None
|
image: np.ndarray = None
|
||||||
|
|
||||||
# App settings
|
# App settings
|
||||||
|
|
Loading…
Reference in New Issue
Block a user