import gradio as gr
import plotly.graph_objects as go
import json
import requests
import os
from PIL import Image
import hopsworks
import joblib
import pandas as pd
import numpy as np
API_KEY = os.environ['API_KEY_TOMTOM']
print("API KEY", API_KEY)
# Log into hopsworks
project = hopsworks.login()
fs = project.get_feature_store()
mr = project.get_model_registry()
model = mr.get_model("sthlm_incidents_model", version=4)
model_dir = model.download()
model = joblib.load(model_dir + "/sthlm_model.pkl")
print("Model downloaded")
api_params_incidents = {
'base_url': 'api.tomtom.com',
'API_KEY': API_KEY,
'min_lon': 18.00,
'max_lon': 18.16,
'min_lat': 59.25,
'max_lat': 59.40,
'version_number': 5,
'category_filter': '0%2C1%2C2%2C3%2C4%2C5%2C6%2C7%2C8%2C9%2C10%2C11%2C14',
'time_validity_filter': 'present',
'language': 'en-GB',
'fields': '%7Bincidents%7Btype%2Cgeometry%7Bcoordinates%7D%2Cproperties%7Bid%2CmagnitudeOfDelay%2Cevents%7Bdescription%2Ccode%2CiconCategory%7D%2CstartTime%2CendTime%7D%7D%7D'
}
def get_incident_details(params):
url = f"https://{params['base_url']}/traffic/services/{params['version_number']}/incidentDetails?bbox={params['min_lon']}%2C{params['min_lat']}%2C{params['max_lon']}%2C{params['max_lat']}&fields={params['fields']}&language={params['language']}&categoryFilter={params['category_filter']}&timeValidityFilter={params['time_validity_filter']}&key={params['API_KEY']}"
return json.loads(requests.get(url).text)
# Function that handles an incident
def handle_incident(incident):
hour_value = incident['properties']['startTime'][11:13]
# Create a dictionary with the incident details
dict_incident = {
'id': incident['properties']['id'],
'magnitudeOfDelay': incident['properties']['magnitudeOfDelay'],
'startTime': incident['properties']['startTime'],
'endTime': incident['properties']['endTime'],
'type': incident['type'],
'code': incident['properties']['events'][0]['code'],
'iconCategory': incident['properties']['events'][0]['iconCategory'],
'description': incident['properties']['events'][0]['description'],
'month': incident['properties']['startTime'][5:7],
'hour': hour_value,
}
# Get the coordinates of the incident, if statement is for if the incident only has one coordinate
if any(isinstance(j, list) for j in incident['geometry']['coordinates']):
dict_incident['longitude'] = incident['geometry']['coordinates'][0][0]
dict_incident['latitude'] = incident['geometry']['coordinates'][0][1]
else:
dict_incident['longitude'] = incident['geometry']['coordinates'][0]
dict_incident['latitude'] = incident['geometry']['coordinates'][1]
return dict_incident
def filter_map():
latitude_list = []
longitude_list = []
index_list = []
# Get the data from the json
incidents = get_incident_details(api_params_incidents)['incidents']
for (_, i) in enumerate(incidents):
# Add the coordinates to the list
if any(isinstance(j, list) for j in i['geometry']['coordinates']):
latitude_list.append(i['geometry']['coordinates'][0][1])
longitude_list.append(i['geometry']['coordinates'][0][0])
else:
latitude_list.append(i['geometry']['coordinates'][1])
longitude_list.append(i['geometry']['coordinates'][0])
if type(i['properties']['events']) == list:
description = i['properties']['events'][0]['description']
else:
description = i['properties']['events']['description']
starting_date = i['properties']['startTime'].split('T')[0]
starting_time = i['properties']['startTime'].split('T')[1].split('+')[0]
starting_string = f"started at {starting_time} on {starting_date}"
# Check if it has an end time
if i['properties']['endTime'] is not None:
ending_date = i['properties']['endTime'].split('T')[0]
ending_time = i['properties']['endTime'].split('T')[1].split('+')[0]
ending_string = f"will end at {ending_time} on {ending_date}
"
else:
# Use the model
row = handle_incident(i)
# Create a df from the row
df_row = pd.DataFrame(row, index=[row['id']])
df_row = df_row.drop(["startTime", "endTime", "type", "id", "description"], axis=1)
# change the order to code hour iconCategory latitude longitude magnitudeOfDelay month duration
df_row = df_row[['code', 'hour', 'iconCategory', 'latitude', 'longitude', 'magnitudeOfDelay', 'month']]
# make the features lower case
df_row.columns = df_row.columns.str.lower()
df_row.columns = df_row.columns.str.replace(' ', '_')
# Get the prediction
prediction = model.predict(df_row)
prediction = prediction[0]
print(prediction)
# add the prediction to the starting time
ending_time = pd.to_datetime(starting_time) + pd.Timedelta(seconds=int(min(prediction, 100000)))
ending_date = str(ending_time).split(' ')[0]
ending_time = str(ending_time).split(' ')[1].split('+')[0]
ending_string = f"Predicted ending time: {ending_time} on {ending_date}
"
index_list.append((starting_string, ending_string, description))
fig = go.Figure(go.Scattermapbox(
customdata=index_list,
lat=latitude_list,
lon=longitude_list,
mode='markers',
marker=go.scattermapbox.Marker(
size=6
),
hoverinfo="text",
hovertemplate="""
Incident in Stockholm started at %{customdata[0]}
%{customdata[1]}
Additional Information: %{customdata[2]}
"""
))
fig.update_layout(
mapbox_style="open-street-map",
hoverlabel=dict(
bgcolor="rgba(255, 255, 255, 0)",
font_size=16,
font_family="Arial"
),
hovermode='closest',
mapbox=dict(
bearing=0,
center=go.layout.mapbox.Center(
lat=59.32,
lon=18.08
),
pitch=0,
zoom=9
),
)
return fig
with gr.Blocks() as demo:
with gr.Column():
btn = gr.Button(value="Update Filter")
map = gr.Plot()
demo.load(filter_map, outputs=map)
btn.click(filter_map, outputs=map)
demo.launch()