-
Notifications
You must be signed in to change notification settings - Fork 3
/
app.py
113 lines (86 loc) · 3.11 KB
/
app.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import os
import json
import pickle
import joblib
import pandas as pd
from flask import Flask, jsonify, request
from peewee import (
Model, IntegerField, FloatField,
TextField, IntegrityError
)
from playhouse.shortcuts import model_to_dict
from playhouse.db_url import connect
########################################
# Begin database stuff
# The connect function checks if there is a DATABASE_URL env var.
# If it exists, it uses it to connect to a remote postgres db.
# Otherwise, it connects to a local sqlite db stored in predictions.db.
DB = connect(os.environ.get('DATABASE_URL') or 'sqlite:///predictions.db')
class Prediction(Model):
observation_id = IntegerField(unique=True)
observation = TextField()
proba = FloatField()
true_class = IntegerField(null=True)
class Meta:
database = DB
DB.create_tables([Prediction], safe=True)
# End database stuff
########################################
########################################
# Unpickle the previously-trained model
with open('columns.json') as fh:
columns = json.load(fh)
pipeline = joblib.load('pipeline.pickle')
with open('dtypes.pickle', 'rb') as fh:
dtypes = pickle.load(fh)
# End model un-pickling
########################################
########################################
# Begin webserver stuff
app = Flask(__name__)
@app.route('/predict', methods=['POST'])
def predict():
# Flask provides a deserialization convenience function called
# get_json that will work if the mimetype is application/json.
obs_dict = request.get_json()
_id = obs_dict['id']
observation = obs_dict['observation']
# Now do what we already learned in the notebooks about how to transform
# a single observation into a dataframe that will work with a pipeline.
obs = pd.DataFrame([observation], columns=columns).astype(dtypes)
# Now get ourselves an actual prediction of the positive class.
proba = pipeline.predict_proba(obs)[0, 1]
response = {'proba': proba}
p = Prediction(
observation_id=_id,
proba=proba,
observation=request.data
)
try:
p.save()
except IntegrityError:
error_msg = 'Observation ID: "{}" already exists'.format(_id)
response['error'] = error_msg
print(error_msg)
DB.rollback()
return jsonify(response)
@app.route('/update', methods=['POST'])
def update():
obs = request.get_json()
try:
p = Prediction.get(Prediction.observation_id == obs['id'])
p.true_class = obs['true_class']
p.save()
return jsonify(model_to_dict(p))
except Prediction.DoesNotExist:
error_msg = 'Observation ID: "{}" does not exist'.format(obs['id'])
return jsonify({'error': error_msg})
@app.route('/list-db-contents')
def list_db_contents():
return jsonify([
model_to_dict(obs) for obs in Prediction.select()
])
# End webserver stuff
########################################
if __name__ == "__main__":
app.run(host='0.0.0.0', debug=True, port=5000)