1
1
from app import app , db
2
2
from flask import render_template , redirect , url_for , jsonify , send_file
3
- from app .forms import ActiveQueryForm , ClassifierForm , BlobForm , DetectForm , ClassifierEvaluateForm
4
- from app .models import User , Classifier , PatchQuery , PatchResponse , HitResponse , Estimator , Detection , Round , Dataset , ValPrediction , Blob , Patch , dataset_x_blob
3
+ from app .forms import (
4
+ ActiveQueryForm ,
5
+ ClassifierForm ,
6
+ BlobForm ,
7
+ DetectForm ,
8
+ ClassifierEvaluateForm ,
9
+ )
10
+ from app .models import (
11
+ User ,
12
+ Classifier ,
13
+ PatchQuery ,
14
+ PatchResponse ,
15
+ HitResponse ,
16
+ Estimator ,
17
+ Detection ,
18
+ Round ,
19
+ Dataset ,
20
+ ValPrediction ,
21
+ Blob ,
22
+ Patch ,
23
+ dataset_x_blob ,
24
+ )
5
25
6
26
7
27
import tasks
8
28
9
29
import time , itertools
10
30
11
- @app .route ('/classifier/' )
12
- def classifier_top ():
13
- classifiers = Classifier .query .filter_by (is_ready = True ).order_by (Classifier .id .desc ()).limit (50 )
14
- return render_template ('classifier_top.html' ,
15
- title = 'Classifier Library' ,
16
- classifiers = classifiers ,
17
- next = next )
18
31
19
- @app .route ('/classifier/<int:id>' )
32
+ @app .route ("/classifier/" )
33
+ def classifier_top ():
34
+ classifiers = (
35
+ Classifier .query .filter_by (is_ready = True )
36
+ .order_by (Classifier .id .desc ())
37
+ .limit (50 )
38
+ )
39
+ return render_template (
40
+ "classifier_top.html" ,
41
+ title = "Classifier Library" ,
42
+ classifiers = classifiers ,
43
+ next = next ,
44
+ )
45
+
46
+
47
+ @app .route ("/classifier/<int:id>" )
20
48
def classifier (id , r_id = None ):
21
49
classifier = Classifier .query .get_or_404 (id )
22
50
23
51
if r_id is not None :
24
- round = Round .query .filter (Round .classifier == classifier , Round .number == r_id ).first ()
52
+ round = Round .query .filter (
53
+ Round .classifier == classifier , Round .number == r_id
54
+ ).first ()
25
55
else :
26
56
round = classifier .latest_round
27
57
@@ -30,49 +60,59 @@ def classifier(id, r_id=None):
30
60
form = ActiveQueryForm ()
31
61
form .classifier .data = classifier
32
62
form .round .data = round
33
- classifier_title = classifier .keyword .name if classifier .keyword else "Export Classifier"
63
+ classifier_title = (
64
+ classifier .keyword .name if classifier .keyword else "Export Classifier"
65
+ )
34
66
35
- return render_template ('classifier.html' , classifier = classifier , round = round ,
36
- title = '%s %d' % (classifier_title ,
37
- classifier .rounds .count ()),
38
- form = form , hits = hits )
67
+ return render_template (
68
+ "classifier.html" ,
69
+ classifier = classifier ,
70
+ round = round ,
71
+ title = "%s %d" % (classifier_title , classifier .rounds .count ()),
72
+ form = form ,
73
+ hits = hits ,
74
+ )
39
75
40
- @app .route ('/classifier/<int:id>/<int:i>/' )
76
+
77
+ @app .route ("/classifier/<int:id>/<int:i>/" )
41
78
def classifier_round (id , i ):
42
79
return classifier (id , r_id = i )
43
-
80
+
44
81
# return render_template( 'classifier_round.html', classifier=classifier,
45
82
# title='%s %d' % (classifier_title, i),
46
83
# form=form, round = round, hits = hits)
47
84
48
- @app .route ('/classifier/<int:id>/download' )
85
+
86
+ @app .route ("/classifier/<int:id>/download" )
49
87
def classifier_dl (id ):
50
88
classifier = Classifier .query .get_or_404 (id )
51
89
round = classifier .latest_round
52
90
return send_file (round .location )
53
91
54
- @app .route ('/classifier/update/<int:id>' , methods = ['POST' ])
92
+
93
+ @app .route ("/classifier/update/<int:id>" , methods = ["POST" ])
55
94
def classifier_update (id ):
56
- form = ActiveQueryForm ();
95
+ form = ActiveQueryForm ()
57
96
58
97
if form .validate_on_submit ():
59
- print (' form.user.data: ' + form .user .data )
60
- user = None # current_user
98
+ print (" form.user.data: " + form .user .data )
99
+ user = None # current_user
61
100
62
- if True :# user.is_anonymous and form.user.data:
101
+ if True : # user.is_anonymous and form.user.data:
63
102
# TODO fix when authentication is fixed
64
- user = User .query .get (1 )# User.find(form.user.data)
103
+ user = User .query .get (1 ) # User.find(form.user.data)
65
104
# if user:
66
105
# assert user.password == None
67
106
# else:
68
107
# user = User(username=form.user.data, password=None)
69
108
# db.session.add(user)
70
109
# user.location = form.location.data
71
110
# user.nationality = form.nationality.data
72
- print (' update classifier %s from %s.....' % (id , user ))
111
+ print (" update classifier %s from %s....." % (id , user ))
73
112
74
- hit_resp = HitResponse (time = form .time .data ,
75
- user = None if user .is_anonymous else user )
113
+ hit_resp = HitResponse (
114
+ time = form .time .data , user = None if user .is_anonymous else user
115
+ )
76
116
db .session .add (hit_resp )
77
117
db .session .commit ()
78
118
print (str (time .time ()) + ": " + str (hit_resp ))
@@ -82,7 +122,7 @@ def classifier_update(id):
82
122
83
123
for patch , v in itertools .chain (pos_response , neg_response ):
84
124
pq = PatchQuery .query .filter_by (patch = patch , round = form .round .data ).one ()
85
- pr = PatchResponse (value = v , hitresponse = hit_resp , patchquery = pq )
125
+ pr = PatchResponse (value = v , hitresponse = hit_resp , patchquery = pq )
86
126
db .session .add (pr )
87
127
88
128
print (str (time .time ()) + ": done" )
@@ -96,26 +136,32 @@ def classifier_update(id):
96
136
print (field .name )
97
137
print (field .errors )
98
138
print (field .data )
99
- return jsonify (results = ' success' )
139
+ return jsonify (results = " success" )
100
140
101
- @app .route ('/classifier/new' , methods = ['POST' ])
141
+
142
+ @app .route ("/classifier/new" , methods = ["POST" ])
102
143
def classifier_new ():
103
144
form = ClassifierForm ()
104
145
105
146
if form .validate_on_submit ():
106
- c = Classifier (dataset = form .dataset .data ,
107
- keyword = form .keyword .data ,
108
- estimator = form .estimator .data )
147
+ c = Classifier (
148
+ dataset = form .dataset .data ,
149
+ keyword = form .keyword .data ,
150
+ estimator = form .estimator .data ,
151
+ )
109
152
db .session .add (c )
110
153
db .session .commit ()
111
- tasks .if_classifier (c )
154
+
155
+ # TODO: for now, a new classifier randomly samples at most 100k features; consider parameterizing this.
156
+ tasks .if_classifier (c , limited_number_of_features_to_evaluate = 100000 )
112
157
return redirect (c .url )
113
158
else :
114
- print (' did not validate' )
159
+ print (" did not validate" )
115
160
print (form .dataset .errors )
116
- return redirect (url_for ('classifier_top' ))
161
+ return redirect (url_for ("classifier_top" ))
162
+
117
163
118
- @app .route (' /classifier/<int:classifier_id>/<int:round_id>/evaluate/<int:dataset_id>' )
164
+ @app .route (" /classifier/<int:classifier_id>/<int:round_id>/evaluate/<int:dataset_id>" )
119
165
def classifier_evaluate (classifier_id , round_id , dataset_id ):
120
166
classifier = Classifier .query .get_or_404 (classifier_id )
121
167
round = Round .query .get_or_404 (round_id )
@@ -127,33 +173,44 @@ def classifier_evaluate(classifier_id, round_id, dataset_id):
127
173
form .dataset .data = dataset
128
174
129
175
if dataset .is_train :
130
- return ' not validation set'
176
+ return " not validation set"
131
177
132
- #maybe instead I can check the notes in the round
133
- predicts = db .engine .execute ('SELECT * from val_prediction where patch_id in\
178
+ # maybe instead I can check the notes in the round
179
+ predicts = db .engine .execute (
180
+ "SELECT * from val_prediction where patch_id in\
134
181
(select id from patch where blob_id in \
135
182
(select blob_id from dataset_x_blob where dataset_id=%d)) \
136
183
and round_id=%d\
137
- ORDER BY value DESC;' \
138
- % (dataset .id , round .id )).fetchmany (100 )
184
+ ORDER BY value DESC;"
185
+ % (dataset .id , round .id )
186
+ ).fetchmany (100 )
139
187
if predicts :
140
188
first_last_patches = None
141
189
form .note .data = None
142
190
if round .notes :
143
191
rn = eval (round .notes )
144
192
for note_id in rn :
145
- user_id = - 1 #if current_user.is_anonymous else current_user.id
146
- if rn [note_id ]["dataset" ] == dataset .id and rn [note_id ]["user" ] == user_id :
193
+ user_id = - 1 # if current_user.is_anonymous else current_user.id
194
+ if (
195
+ rn [note_id ]["dataset" ] == dataset .id
196
+ and rn [note_id ]["user" ] == user_id
197
+ ):
147
198
first_last_patches = rn [note_id ]["first_last_patches" ]
148
199
form .note .data = note_id
149
- return render_template ('classifier_evaluate.html' , predicts = predicts , form = form , eval = first_last_patches )
150
- return redirect (url_for ('evaluate_top' ))
200
+ return render_template (
201
+ "classifier_evaluate.html" ,
202
+ predicts = predicts ,
203
+ form = form ,
204
+ eval = first_last_patches ,
205
+ )
206
+ return redirect (url_for ("evaluate_top" ))
151
207
152
- @app .route ("/classifier/eval_range" , methods = ['POST' ])
208
+
209
+ @app .route ("/classifier/eval_range" , methods = ["POST" ])
153
210
def classifier_eval_range ():
154
211
form = ClassifierEvaluateForm ()
155
212
if form .validate_on_submit ():
156
- user = None # current_user
213
+ user = None # current_user
157
214
round = form .round .data
158
215
round = Round .query .get (round .id )
159
216
@@ -166,28 +223,39 @@ def classifier_eval_range():
166
223
167
224
if note :
168
225
note = int (note )
169
- tops_bottoms = {"eval_score" : abs (first_incorrect .id - last_correct .id ),
170
- "first_last_patches" : (first_incorrect .id , last_correct .id )}
226
+ tops_bottoms = {
227
+ "eval_score" : abs (first_incorrect .id - last_correct .id ),
228
+ "first_last_patches" : (first_incorrect .id , last_correct .id ),
229
+ }
171
230
new_note = {** prev_notes [note ], ** tops_bottoms }
172
- round .notes = str ({** prev_notes , ** {note :new_note }})
231
+ round .notes = str ({** prev_notes , ** {note : new_note }})
173
232
else :
174
233
# pass
175
234
insert_id = - 1 if user .is_anonymous else user .id
176
- note = max (prev_notes )+ 1
177
- tops_bottoms = {note : {"user" :insert_id , "dataset" :dataset .id ,
178
- "eval_score" : abs (first_incorrect .id - last_correct .id ),
179
- "first_last_patches" : (first_incorrect .id , last_correct .id )}}
180
- round .notes = str ({** prev_notes , ** tops_bottoms }) if round .notes else str (tops_bottoms )
235
+ note = max (prev_notes ) + 1
236
+ tops_bottoms = {
237
+ note : {
238
+ "user" : insert_id ,
239
+ "dataset" : dataset .id ,
240
+ "eval_score" : abs (first_incorrect .id - last_correct .id ),
241
+ "first_last_patches" : (first_incorrect .id , last_correct .id ),
242
+ }
243
+ }
244
+ round .notes = (
245
+ str ({** prev_notes , ** tops_bottoms })
246
+ if round .notes
247
+ else str (tops_bottoms )
248
+ )
181
249
db .session .commit ()
182
250
return jsonify ({"note_id" : note })
183
251
else :
184
- return redirect (url_for (' evaluate_top' ))
252
+ return redirect (url_for (" evaluate_top" ))
185
253
186
254
187
255
####################
188
256
### Detect Views ###
189
257
####################
190
- @app .route (' /detect/' , methods = [ ' GET' , ' POST' ])
258
+ @app .route (" /detect/" , methods = [ " GET" , " POST" ])
191
259
def detect_top ():
192
260
form = BlobForm ()
193
261
detect_form = DetectForm ()
@@ -202,19 +270,27 @@ def detect_top():
202
270
for d in detects :
203
271
tasks .detect .delay (d .id )
204
272
205
- return render_template ('detect.html' , title = 'Detect' , form = form ,
206
- detect_form = detect_form , detects = Detection .query .all ())
273
+ return render_template (
274
+ "detect.html" ,
275
+ title = "Detect" ,
276
+ form = form ,
277
+ detect_form = detect_form ,
278
+ detects = Detection .query .all (),
279
+ )
280
+
207
281
208
- @app .route (' /detect/<int:id>/' )
282
+ @app .route (" /detect/<int:id>/" )
209
283
def detect (id ):
210
284
detect = Detection .query .get_or_404 (id )
211
285
212
- return render_template ('detection.html' , detect = detect ,
213
- title = 'Detect %d' % (detect .id ))
286
+ return render_template (
287
+ "detection.html" , detect = detect , title = "Detect %d" % (detect .id )
288
+ )
289
+
214
290
215
291
def make_hit (examples , patch_queries ):
216
292
return {
217
- "positives" : [ex .patch .id for ex in examples if ex .value ],
293
+ "positives" : [ex .patch .id for ex in examples if ex .value ],
218
294
"negatives" : [ex .patch .id for ex in examples if not ex .value ],
219
- "queries" : [pq .patch .id for pq in patch_queries ]
295
+ "queries" : [pq .patch .id for pq in patch_queries ],
220
296
}
0 commit comments