diff --git a/sorteerhoed/HITStore.py b/sorteerhoed/HITStore.py
index 8769c9a..68cae14 100644
--- a/sorteerhoed/HITStore.py
+++ b/sorteerhoed/HITStore.py
@@ -1,6 +1,6 @@
import logging
from sqlalchemy.ext.declarative import declarative_base
-from sqlalchemy import Column, Integer, String, DateTime
+from sqlalchemy import Column, Integer, String, DateTime, Float
from sqlalchemy.orm import relationship
from sqlalchemy.sql.schema import ForeignKey, Sequence
from sqlalchemy.engine import create_engine
@@ -55,6 +55,7 @@ class HIT(Base):
turk_screen_width = Column(Integer, default = None)
turk_screen_height = Column(Integer, default = None)
scanned_at = Column(DateTime, default=None)
+ fee = Column(Float(precision=2), default=None)
def getImagePath(self):
@@ -149,6 +150,11 @@ class Store:
return int(2.5*60)
return int(sum(durations) / len(durations))
+ def getHITs(self, n = 100):
+ return self.session.query(HIT).\
+ filter(HIT.submit_hit_at != None).\
+ order_by(HIT.submit_hit_at.desc()).limit(n)
+
# def rmSource(self, id: int):
# with self.getSession() as session:
# source = session.query(Source).get(id)
diff --git a/sorteerhoed/central_management.py b/sorteerhoed/central_management.py
index 8017d9d..bd93cac 100644
--- a/sorteerhoed/central_management.py
+++ b/sorteerhoed/central_management.py
@@ -226,6 +226,7 @@ class CentralManagement():
estimatedHitDuration = self.store.getAvgDurationOfPreviousNHits(5)
fee = (self.config['hour_rate_aim']/3600.) * estimatedHitDuration
+ self.currentHit.fee = fee
self.logger.debug(f"Based on average duration of {estimatedHitDuration} fee should be {fee}/hit to get hourly rate of {self.config['hour_rate_aim']}")
new_hit = self.mturk.create_hit(
Title = 'Trace the drawn line',
diff --git a/sorteerhoed/webserver.py b/sorteerhoed/webserver.py
index 185274a..ec31b01 100644
--- a/sorteerhoed/webserver.py
+++ b/sorteerhoed/webserver.py
@@ -274,6 +274,40 @@ class DrawPageHandler(tornado.web.RequestHandler):
.replace("{LEFT_PADDING}", str(self.top_padding))
self.write(contents)
+class BackendHandler(tornado.web.RequestHandler):
+ def initialize(self, store: HITStore, path: str):
+ self.store = store
+ self.path = path
+
+ def get(self):
+ rows = []
+ for hit in self.store.getHITs(100):
+ if hit.submit_hit_at and hit.accept_time:
+ seconds = (hit.submit_hit_at - hit.accept_time).total_seconds()
+ duration_m = int(seconds/60)
+ duration_s = max(int(seconds%60), 0)
+ print(duration_m, duration_s)
+ duration = (f"{duration_m}m" if duration_m else "") + f"{duration_s:02d}s"
+ else:
+ duration = "-"
+
+ fee = f"${hit.fee:.2}" if hit.fee else "-"
+
+ rows.append(
+ f"""
+
| {hit.worker_id}
+ | {hit.turk_ip} |
+ {hit.turk_country} |
+ {fee} |
+ {hit.accept_time} |
+ {duration} | |
+ """
+ )
+
+ contents = open(os.path.join(self.path, 'backend.html'), 'r').read()
+ contents = contents.replace("{{TBODY}}", "".join(rows))
+ self.write(contents)
+
class StatusPage():
"""
Properties for on the status page, which are send over websockets the moment
@@ -365,6 +399,11 @@ class Server:
top_padding=self.config['scanner']['top_padding'],
left_padding=self.config['scanner']['left_padding']
)),
+ (r"/backend", BackendHandler,
+ dict(
+ store = self.store,
+ path=self.web_root,
+ )),
(r"/(.*)", StaticFileWithHeaderHandler,
{"path": self.web_root}),
], debug=True, autoreload=False)
diff --git a/www/amazon.svg b/www/amazon.svg
new file mode 100644
index 0000000..43961b1
--- /dev/null
+++ b/www/amazon.svg
@@ -0,0 +1,26 @@
+
+
\ No newline at end of file
diff --git a/www/backend.css b/www/backend.css
new file mode 100644
index 0000000..771db0b
--- /dev/null
+++ b/www/backend.css
@@ -0,0 +1,110 @@
+@font-face {
+ font-family: 'bebas';
+ src: url('font/BebasNeue-Regular.ttf');
+}
+
+@font-face {
+ font-family: 'freesans';
+ src: url('font/FreeSans.ttf')
+}
+
+
+:root{
+
+ --base-font-size: 12px;
+ --spec_name-font-size: 120%;
+ --spec_value-font-size: 250%;
+
+ --base-color: #271601; /* tekst */
+ --alt-color: #FFF5DF; /* achtergrond */
+ --amazon-color: #F0C14C;
+
+ /* ////// GAT ACHTERKANT PLEK & POSITIE /////// */
+ /* */ /* */
+ /* */ --pos-x: 20px; /* */
+ /* */ --pos-y: 20px; /* */
+ /* */ --width: 90%; /* 115mm */
+ /* */ --height: 100%; /* 500mm */
+ /* */ /* */
+ /* //////////////////////////////////////////// */
+
+}
+
+
+html, body{
+ margin: 0;
+ padding: 0;
+ border: 0;
+ text-decoration: none;
+ font-family: 'freesans';
+ font-size: var(--base-font-size);
+ line-height: 1.1;
+ background: #555;
+ overflow: hidden;
+}
+
+#logo{
+ background: #555;
+ width: 100%;
+ padding: 2% 0% 1% 0%;
+ text-align: right;
+}
+
+#wrapper{
+
+ position: absolute;
+ left: var(--pos-x);
+ top: var(--pos-y);
+ width: var(--width);
+ /* height: var(--height); */
+
+ background: var(--alt-color);
+ box-sizing: border-box;
+ /* padding: 2%; */
+}
+
+
+table{
+ display: grid;
+ border-collapse: collapse;
+ min-width: 100%;
+ grid-template-columns: repeat(6, 1fr);
+}
+
+thead, tbody, tr{
+ display: contents;
+}
+
+
+th,
+td {
+ padding: 2%;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+th {
+ position: -webkit-sticky;
+ position: sticky;
+ background-image: linear-gradient(var(--alt-color), var(--amazon-color)) ;
+ top: 0;
+ text-align: left;
+ font-weight: normal;
+ font-size: 1.1rem;
+ color: var(--base-color);
+}
+
+th:last-child {
+ border: 0;
+}
+
+td {
+ padding-top: 2%;
+ padding-bottom: 2%;
+ color: #808080;
+}
+
+tr:nth-child(even) td {
+ background: #f8f6f9;
+}
diff --git a/www/backend.html b/www/backend.html
new file mode 100644
index 0000000..ca93064
--- /dev/null
+++ b/www/backend.html
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+ worker id |
+ ip address |
+ country |
+ fee |
+ task start time |
+ task completion time |
+ |
+
+
+
+{{TBODY}}
+
+
+
+
+
+