Fake everything for easier (semi-)permanent hosting.

This commit is contained in:
Casper V. Kristensen 2019-04-08 18:41:54 +02:00
parent 73e3c14e18
commit 904ed7a705
Signed by: caspervk
GPG key ID: 289CA03790535054
14 changed files with 1587 additions and 223 deletions

View file

@ -3,11 +3,9 @@ import json
import statistics
import timeit
from dataclasses import asdict
from datetime import timedelta
from logging import DEBUG
from typing import List
import requests_cache
from flask import Flask, jsonify, logging, request
from .strategies import miloStrats, iss, cars_in_traffic, tide_strat, upstairs_neighbour, bing, svm_strat, battery, just_eat, steam
@ -17,8 +15,6 @@ app = Flask(__name__)
logger = logging.create_logger(app)
logger.setLevel(DEBUG)
requests_cache.install_cache("requests_cache", expire_after=timedelta(minutes=2))
strategies = {
# name: (weight, probability function)
@ -44,7 +40,7 @@ def probabilities():
context = Context()
else:
phone_data = request.get_json(force=True)
logger.debug("phone_data:\n%s", json.dumps(phone_data, indent=2))
#logger.debug("phone_data:\n%s", json.dumps(phone_data, indent=2))
context = Context(**phone_data["data"])
#logger.debug("Context: %s", context)
@ -101,7 +97,7 @@ def probabilities():
def main():
app.run(host='0.0.0.0', debug=True)
app.run(host='0.0.0.0', port=3301, debug=False)
if __name__ == '__main__':

File diff suppressed because it is too large Load diff

View file

@ -1,8 +1,5 @@
from datetime import datetime
import requests
from bs4 import BeautifulSoup
from ..util import Context, Prediction
@ -13,13 +10,7 @@ def clock(context: Context) -> Prediction:
p = Prediction()
p.weight = 0.01
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'}
r = requests.get("https://www.bing.com/search?q=time+in+denmark", headers=headers)
soup = BeautifulSoup(r.content, features='html5lib')
time_str = soup.find("div", {"id": "digit_time"}).text
time = datetime.strptime(time_str, "%H:%M")
time = datetime.now()
night = time.hour < 6 or time.hour >= 22
time_description = "nighttime" if night else "daytime"

View file

@ -1,4 +1,5 @@
import requests
import random
from datetime import datetime
from ..util import Prediction, Context
@ -7,22 +8,18 @@ def cars_in_traffic(context: Context) -> Prediction:
"""
How many cars are currently driving around Aarhus?
"""
r = requests.get('https://portal.opendata.dk/api/3/action/datastore_search?resource_id=b3eeb0ff-c8a8-4824-99d6-e0a3747c8b0d')
night_avr = 3.38
day_avr = 6.98
p = Prediction()
data = r.json()
sum = 0
len = 0
for lel in data['result']['records']:
sum += lel['vehicleCount']
len += 1
if sum > 0:
curr_avg = len / sum
time = datetime.now()
night = time.hour < 6 or time.hour >= 22
if night:
curr_avg = max(0, random.normalvariate(night_avr, 2))
else:
curr_avg = 0
curr_avg = max(0, random.normalvariate(day_avr, 3))
diff = day_avr - night_avr

View file

@ -1,9 +1,10 @@
import datetime
import math
import operator
from datetime import datetime, timezone
import random
from datetime import datetime
from math import pi, sqrt, sin, cos, atan2
import requests
from ..util import Context, Prediction
@ -14,7 +15,7 @@ def night_on_iss(context: Context) -> Prediction:
p = Prediction()
if not context.flat_earth:
iss_position = requests.get("http://api.open-notify.org/iss-now.json").json()["iss_position"]
iss_position = {'latitude': random.uniform(-70, 70), 'longitude': random.uniform(-180, 180)}
the_iss = "The ISS"
at_iss_location = "at the ISS's location"
iss_position_description = "on board the ISS"
@ -25,18 +26,14 @@ def night_on_iss(context: Context) -> Prediction:
at_iss_location = "in Hollywood"
iss_position_description = "in the Hollywood studio"
sun_times = requests.get(f"https://api.sunrise-sunset.org/json", params={
"lat": iss_position["latitude"],
"lng": iss_position["longitude"],
"formatted": 0
}).json()["results"]
iss_position_sunrise = datetime.strptime(sun_times["sunrise"], "%Y-%m-%dT%H:%M:%S%z")
iss_position_sunset = datetime.strptime(sun_times["sunset"], "%Y-%m-%dT%H:%M:%S%z")
sunrise = Sun().getSunriseTime(iss_position)
sunset = Sun().getSunsetTime(iss_position)
iss_position_sunrise = datetime.utcnow().replace(hour=int(sunrise["hr"]), minute=int(sunrise["min"]))
iss_position_sunset = datetime.utcnow().replace(hour=int(sunset["hr"]), minute=int(sunset["min"]))
p.reasons.append(f"The sun rises and sets at UTC {iss_position_sunrise.strftime('%H:%M')} and {iss_position_sunset.strftime('%H:%M')}, respectively, {at_iss_location}.")
utcnow = datetime.now(timezone.utc)
utcnow = datetime.utcnow()
p.reasons.append(f"It is currently {utcnow.strftime('%H:%M')} UTC")
iss_night = utcnow < iss_position_sunrise or iss_position_sunset < utcnow
@ -92,3 +89,110 @@ def haversine(pos1, pos2):
km = 6367 * c
return km
class Sun:
def getSunriseTime( self, coords ):
return self.calcSunTime( coords, True )
def getSunsetTime( self, coords ):
return self.calcSunTime( coords, False )
def getCurrentUTC( self ):
now = datetime.now()
return [ now.day, now.month, now.year ]
def calcSunTime( self, coords, isRiseTime, zenith = 90.8 ):
# isRiseTime == False, returns sunsetTime
day, month, year = self.getCurrentUTC()
longitude = coords['longitude']
latitude = coords['latitude']
TO_RAD = math.pi/180
#1. first calculate the day of the year
N1 = math.floor(275 * month / 9)
N2 = math.floor((month + 9) / 12)
N3 = (1 + math.floor((year - 4 * math.floor(year / 4) + 2) / 3))
N = N1 - (N2 * N3) + day - 30
#2. convert the longitude to hour value and calculate an approximate time
lngHour = longitude / 15
if isRiseTime:
t = N + ((6 - lngHour) / 24)
else: #sunset
t = N + ((18 - lngHour) / 24)
#3. calculate the Sun's mean anomaly
M = (0.9856 * t) - 3.289
#4. calculate the Sun's true longitude
L = M + (1.916 * math.sin(TO_RAD*M)) + (0.020 * math.sin(TO_RAD * 2 * M)) + 282.634
L = self.forceRange( L, 360 ) #NOTE: L adjusted into the range [0,360)
#5a. calculate the Sun's right ascension
RA = (1/TO_RAD) * math.atan(0.91764 * math.tan(TO_RAD*L))
RA = self.forceRange( RA, 360 ) #NOTE: RA adjusted into the range [0,360)
#5b. right ascension value needs to be in the same quadrant as L
Lquadrant = (math.floor( L/90)) * 90
RAquadrant = (math.floor(RA/90)) * 90
RA = RA + (Lquadrant - RAquadrant)
#5c. right ascension value needs to be converted into hours
RA = RA / 15
#6. calculate the Sun's declination
sinDec = 0.39782 * math.sin(TO_RAD*L)
cosDec = math.cos(math.asin(sinDec))
#7a. calculate the Sun's local hour angle
cosH = (math.cos(TO_RAD*zenith) - (sinDec * math.sin(TO_RAD*latitude))) / (cosDec * math.cos(TO_RAD*latitude))
if cosH > 1:
return {'status': False, 'msg': 'the sun never rises on this location (on the specified date)'}
if cosH < -1:
return {'status': False, 'msg': 'the sun never sets on this location (on the specified date)'}
#7b. finish calculating H and convert into hours
if isRiseTime:
H = 360 - (1/TO_RAD) * math.acos(cosH)
else: #setting
H = (1/TO_RAD) * math.acos(cosH)
H = H / 15
#8. calculate local mean time of rising/setting
T = H + RA - (0.06571 * t) - 6.622
#9. adjust back to UTC
UT = T - lngHour
UT = self.forceRange( UT, 24) # UTC time in decimal format (e.g. 23.23)
#10. Return
hr = self.forceRange(int(UT), 24)
min = round((UT - int(UT))*60,0)
return {
'status': True,
'decimal': UT,
'hr': hr,
'min': min
}
def forceRange( self, v, max ):
# force v to be >= 0 and < max
if v < 0:
return v + max
elif v >= max:
return v - max
return v

View file

@ -1,5 +1,4 @@
import requests
from bs4 import BeautifulSoup
from datetime import datetime
from ..util import Context, Prediction
@ -7,27 +6,7 @@ from ..util import Context, Prediction
def is_restaurant_open(name, open, close) -> Prediction:
p = Prediction()
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'}
r = requests.get("https://www.just-eat.dk/area/8000-århusc", headers=headers)
soup = BeautifulSoup(r.content, features='html5lib')
listing_groups = soup.find_all('div', {'class': 'listing-group'})
#p.reasons.append("Hopefully we are not banned from Just-eat ..")
nice_group = None
for x in listing_groups:
if x['data-test-id'] == 'listingGroupOpen':
nice_group = x
if nice_group is None:
p.reasons.append("Apparently we are banned from just-eat. We therefore have no clue.")
p.probability = 0.5
return p
all_listings = nice_group.find_all('a', {'class': 'mediaElement'})
if any(name in x['href'] for x in all_listings):
if open <= datetime.now().hour < close:
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

View file

@ -1,7 +1,4 @@
from datetime import datetime
import requests
from pytz import timezone
from datetime import datetime, timedelta
from ..util import Context, Prediction
@ -10,8 +7,7 @@ def camImgStrat(context : Context) -> Prediction:
"""
The contents of the camera image
"""
img = context.image
average = float(img.mean())
average = 255 - abs(datetime.now().hour - 12) / 12 * 255
p = Prediction()
p.weight = 1.0
@ -30,8 +26,7 @@ def australiaStrat(context : Context) -> Prediction:
"""
Using time in Australia
"""
australia = timezone('Australia/Melbourne')
t = datetime.now().astimezone(australia)
t = datetime.now() + timedelta(hours=10)
hour = t.hour
p = Prediction()
@ -56,27 +51,12 @@ def tv2newsStrat(context : Context) -> Prediction:
"""
The number of articles releases in the last few hours on TV2.dk
"""
r = requests.get('http://mpx.services.tv2.dk/api/latest')
data = r.json()
publish_dates = [(x['pubDate'])//1000 for x in data[:5]]
delta_times = []
for i in range(len(publish_dates)):
if i == 0 : continue
delta_times.append(publish_dates[i-1] - publish_dates[i])
avg_delta = 0
for d in delta_times:
avg_delta += d
avg_timestamp = avg_delta // len(delta_times) // 60
p = Prediction()
if avg_timestamp < 0:
p.weight = 0.0
else:
p.weight = 0.7
print(avg_timestamp)
p.probability = 0.75 if avg_timestamp > 40 else 0.25
few_or_many = 'few' if avg_timestamp > 40 else 'many'
p.weight = 0.7
night = datetime.now().hour < 6 or datetime.now().hour >= 22
p.probability = 0.75 if night else 0.25
few_or_many = 'few' if night else 'many'
p.reasons.append('There were ' + few_or_many + ' recent articles on TV2 News')
if few_or_many == "few":
p.reasons.append("The journalists are therefore either sleeping or busy brainstorming new innovative clickbait methods.")

View file

@ -1,8 +1,7 @@
import random
from datetime import datetime
from pathlib import Path
import requests
from ..util import Context, Prediction
@ -32,9 +31,8 @@ def dota2_players(context: Context) -> Prediction:
def get_dota2_players():
header = {"Client-ID": "F07D7ED5C43A695B3EBB01C28B6A18E5"}
appId = 570
game_players_url = 'https://api.steampowered.com/ISteamUserStats/GetNumberOfCurrentPlayers/v1/?format=json&appid=' + str(appId)
game_players = requests.get(game_players_url, headers=header)
players_str = str(game_players.json()['response']['player_count'])
return int(players_str)
time = datetime.now()
night = time.hour < 6 or time.hour >= 22
if night:
return int(max(0, random.normalvariate(400_000, 100_000)))
return int(max(0, random.normalvariate(700_000, 200_000)))

View file

@ -1,22 +1,5 @@
import pandas as pd
import urllib.request
import json
import requests
from datetime import datetime
def determine_month():
ds = pd.read_excel(urllib.request.urlopen('https://sundogbaelt.dk/wp-content/uploads/2019/04/trafiktal-maaned.xls'))
cur_year = 2019
amount_of_cur_year = sum([x == cur_year for x in ds['År']])
cur_year_total = sum(ds['Total'][1:amount_of_cur_year+1])
last_year_total = sum(ds['Total'][amount_of_cur_year+1:amount_of_cur_year+13])
return ((12/(last_year_total//cur_year_total))+1), cur_year_total, last_year_total
def write_json(url, data_name, time):
r = requests.get(url)
with open(f"{data_name}_{time}.json", 'w') as f:
json.dump(r.json(), f)
return datetime.now().month, 2799622.0, 13029955.0

View file

@ -1,47 +1,5 @@
from pathlib import Path
from sklearn import svm
from sklearn.externals import joblib
import requests
import glob
import json
import numpy as np
from .strat_utils import write_json
from ..util import Context, Prediction
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)
def load_data():
X = []
Y = []
for filename in glob.glob("parking_aarhus*"):
p_class = '2235' in filename
with open(filename) as file:
data = json.load(file)
records = data['result']['records']
frequencies = [house['vehicleCount'] / house['totalSpaces'] for house in records]
X.append(frequencies)
Y.append(int(p_class))
return np.array(X), np.array(Y)
def train():
X, Y = load_data()
classifier = svm.SVC(gamma=0.01, probability=True)
classifier.fit(X, Y)
joblib.dump(classifier, "nightness_classifier.pkl")
def predict(X):
classifier = joblib.load(str(Path(__file__).parent.joinpath("nightness_classifier.pkl")))
prob = classifier.predict_proba(np.array(X).reshape(1, -1))
return prob[0, 1]
def perform_svm_pred(context: Context) -> Prediction:
"""
@ -49,14 +7,8 @@ def perform_svm_pred(context: Context) -> Prediction:
"""
p = Prediction()
p.weight = 0.5
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. Apparently that's a poor idea.")
p.probability = float(predict(X))
p.probability = 0.5
return p

View file

@ -1,9 +1,6 @@
import calendar
from datetime import datetime, timedelta
import json
import requests
from pathlib import Path
from .strat_utils import determine_month
from ..util import Context, Prediction
@ -23,16 +20,15 @@ def is_tide(context: Context) -> Prediction:
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:.2f}")
p.reasons.append(f"The month is therefore {calendar.month_name[month]}")
tide_data = requests.get('https://www.dmi.dk/fileadmin/user_upload/Bruger_upload/Tidevand/2019/Aarhus.t.txt')
lines = tide_data.text[570:].split('\n')
tide_data = Path(__file__).parent.joinpath("Tidevand2019Aarhus.t.txt").open().read()
lines = tide_data[570:].split('\n')
tuples = [x.split('\t') for x in lines]
lel = [[datetime.strptime(x[0], '%Y%m%d%H%M'), x[1]] for x in tuples[:-1]]
matches = [[x[0], int(x[1])] for x in lel if x[0].month == month]
all_the_data = requests.get('https://www.dmi.dk/NinJo2DmiDk/ninjo2dmidk?cmd=odj&stations=22331&datatype=obs')
current_water_level = int(json.loads(all_the_data.content)[0]['values'][-1]['value'])
now = datetime.now().replace(year=2000, month=1, day=1)
current_water_level = int(min(lel, key=lambda d: abs(d[0].replace(year=2000, month=1, day=1) - now))[1])
# Generate average of when the water is high
last_match = matches[0]

View file

@ -1,37 +1,21 @@
import requests
from bs4 import BeautifulSoup
from datetime import datetime, timedelta
import random
from datetime import datetime
from ..util import Prediction, Context
last_update = datetime.min
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})
last_update = now
def check_games(context: Context) -> Prediction:
"""
Is Alexanders upstairs neighbour currently playing League of Legends?
"""
update()
r = requests.get('https://euw.op.gg/summoner/userName=Im+Eating+Pros')
#if not "is not in an active game" in str(r.content):
# return 1.0
p = Prediction()
soup = BeautifulSoup(r.content, features='html5lib')
night = datetime.now().hour < 6 or datetime.now().hour >= 22
timestamp = int(soup.find('div', {'class': 'GameItemList'}).find('div', {'class': 'GameItem'})['data-game-time'])
last_played_game = datetime.fromtimestamp(timestamp)
last_game_in_hours = (((datetime.now() - last_played_game).seconds)/60/60)
if night:
last_game_in_hours = max(0, random.normalvariate(1.5, 1))
else:
last_game_in_hours = max(0, random.normalvariate(12, 5))
if last_game_in_hours < 2:
p.reasons.append("Alexander's upstairs neighbour is currently playing league")

View file

@ -1,31 +1,18 @@
import base64
import random
from dataclasses import dataclass, field
from pathlib import Path
from typing import List, Dict
import cv2
import numpy as np
@dataclass
class Context:
battery: int = field(default_factory=lambda: random.randint(0, 100))
position: Dict[str, float] = field(default_factory=lambda: {'latitude': 53.0, 'longitude': 9.0}) # Denmark somewhere
image: np.ndarray = None
image: str = None
# App settings
in_australia: bool = False
flat_earth: bool = False
def __post_init__(self):
if self.image is None: # no image given
self.image = cv2.imread(str(Path(__file__).parent.joinpath("gray.png")))
else:
img_original = base64.b64decode(self.image)
img_as_np = np.frombuffer(img_original, dtype=np.uint8)
self.image = cv2.imdecode(img_as_np, flags=1)
@dataclass
class Prediction:

View file

@ -1,10 +1 @@
Flask
requests
requests-cache
pytz
beautifulsoup4
pandas
opencv-python
scikit-learn
html5lib
xlrd