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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
|
# -*- coding: utf-8 -*-
import datetime
import logging
from flask import render_template, flash, url_for, redirect, request
from flask_login import current_user
from app import db
from app.decorators import login_required
from app.main import bp
from app.main.email import send_annotation_backup
from app.models import Annotation, Task
from app.utils.datasets import load_data_for_chart
from app.utils.tasks import generate_user_task
logger = logging.getLogger(__name__)
RUBRIC = """
Please mark the point(s) in the time series where an <b>abrupt change</b> in
the behaviour of the series occurs. The goal is to define segments of the time
series that are separated by places where these abrupt changes occur. Recall
that it is also possible for there to be <i>no change points</i>.
<br>
"""
@bp.route("/")
@bp.route("/index")
def index():
if not current_user.is_anonymous and not current_user.is_confirmed:
return redirect(url_for("auth.not_confirmed"))
if current_user.is_authenticated:
user_id = current_user.id
tasks = Task.query.filter_by(annotator_id=user_id).all()
tasks_done = [t for t in tasks if t.done and not t.dataset.is_demo]
tasks_todo = [
t for t in tasks if (not t.done) and (not t.dataset.is_demo)
]
return render_template(
"index.html",
title="Home",
tasks_done=tasks_done,
tasks_todo=tasks_todo,
)
return render_template("index.html", title="Home")
@bp.route("/assign")
@login_required
def assign():
# Intermediate page that assigns a task to a user if needed and then
# redirects to /annotate/task.id
user_tasks = Task.query.filter_by(annotator_id=current_user.id).all()
user_tasks = [t for t in user_tasks if not t.dataset.is_demo]
user_tasks = [t for t in user_tasks if not t.done]
# if the user has, for some reason, a unfinished assigned task, redirect to
# that
if len(user_tasks) > 0:
task = user_tasks[0]
return redirect(url_for("main.annotate", task_id=task.id))
task = generate_user_task(current_user)
if task is None:
flash(
"There are no more datasets to annotate at the moment, thanks for all your help!",
"info",
)
return redirect(url_for("main.index"))
db.session.add(task)
db.session.commit()
return redirect(url_for("main.annotate", task_id=task.id))
@bp.route("/annotate/<int:task_id>", methods=("GET", "POST"))
@login_required
def annotate(task_id):
if request.method == "POST":
# record post time
now = datetime.datetime.utcnow()
# get the json from the client
annotation = request.get_json()
if annotation["identifier"] != task_id:
flash("Internal error: task id doesn't match.", "error")
return redirect(url_for(task_id=task_id))
task = Task.query.filter_by(id=task_id).first()
# remove all previous annotations for this task
for ann in Annotation.query.filter_by(task_id=task_id).all():
db.session.delete(ann)
task.done = False
task.annotated_on = None
db.session.commit()
# record the annotation
if annotation["changepoints"] is None:
ann = Annotation(cp_index=None, task_id=task_id)
db.session.add(ann)
db.session.commit()
else:
for cp in annotation["changepoints"]:
ann = Annotation(cp_index=cp["x"], task_id=task_id)
db.session.add(ann)
db.session.commit()
# mark the task as done
task.done = True
task.annotated_on = now
db.session.commit()
flash("Your annotation has been recorded, thank you!", "success")
# send the annotation as email to the admin for backup
record = {
"user_id": task.annotator_id,
"dataset_name": task.dataset.name,
"dataset_id": task.dataset_id,
"task_id": task.id,
"annotations_raw": annotation,
}
send_annotation_backup(record)
return url_for("main.index")
task = Task.query.filter_by(id=task_id).first()
if task is None:
flash("No task with id %r exists." % task_id, "error")
return redirect(url_for("main.index"))
if not task.annotator_id == current_user.id:
flash(
"No task with id %r has been assigned to you." % task_id, "error"
)
return redirect(url_for("main.index"))
if task.done:
flash("It's not possible to edit annotations at the moment.")
return redirect(url_for("main.index"))
data = load_data_for_chart(task.dataset.name, task.dataset.md5sum)
if data is None:
flash(
"An internal error occurred loading this dataset, the admin has been notified. Please try again later. We apologise for the inconvenience."
)
title = f"Dataset: {task.dataset.id}"
is_multi = len(data["chart_data"]["values"]) > 1
return render_template(
"annotate/index.html",
title=title,
identifier=task.id,
data=data,
rubric=RUBRIC,
is_multi=is_multi,
)
|