diff --git a/mt_task.xml b/mt_task.xml index 7ff4488..767656a 100644 --- a/mt_task.xml +++ b/mt_task.xml @@ -38,7 +38,7 @@ - drawing page + drawing page diff --git a/sorteerhoed.py b/sorteerhoed.py index f251125..ac6097e 100644 --- a/sorteerhoed.py +++ b/sorteerhoed.py @@ -16,6 +16,11 @@ if __name__ == '__main__': type=str, help='The yaml config file to load' ) + argParser.add_argument( + '--no-plotter', + action='store_true', + help='Skip attempt to connect to plotter' + ) argParser.add_argument( '--verbose', '-v', @@ -49,5 +54,5 @@ if __name__ == '__main__': logger.info("Start server") command = CentralManagement(debug_mode=args.verbose > 0) - command.loadConfig(args.config) + command.loadConfig(args.config, args) command.start() diff --git a/sorteerhoed/HITStore.py b/sorteerhoed/HITStore.py index a0e5848..c3caf9d 100644 --- a/sorteerhoed/HITStore.py +++ b/sorteerhoed/HITStore.py @@ -66,6 +66,9 @@ class HIT(Base): def getSvgImageUrl(self): return f"scans/{self.id:06d}.svg" + + def getSvgImagePath(self): + return os.path.join('www', self.getSvgImageUrl()) def getStatus(self): if self.scanned_at: @@ -155,6 +158,9 @@ class Store: return int(2.5*60) return int(sum(durations) / len(durations)) + def getEstimatedHitDuration(self): + return self.getAvgDurationOfPreviousNHits(5) + def getHITs(self, n = 100): return self.session.query(HIT).\ filter(HIT.submit_hit_at != None).\ diff --git a/sorteerhoed/central_management.py b/sorteerhoed/central_management.py index a20f8c2..24f01a6 100644 --- a/sorteerhoed/central_management.py +++ b/sorteerhoed/central_management.py @@ -40,10 +40,13 @@ class CentralManagement(): self.scanLock = threading.Lock() - def loadConfig(self, filename): + def loadConfig(self, filename, args): with open(filename, 'r') as fp: self.logger.debug('Load config from {}'.format(filename)) self.config = yaml.safe_load(fp) + + if args.no_plotter: + self.config['dummy_plotter'] = True varDb = os.path.join( # self.config['storage_dir'], @@ -242,7 +245,7 @@ class CentralManagement(): self.logger.info(f"Make HIT {self.currentHit.id}") question = open(self.config['amazon']['task_xml'], mode='r').read().replace("{HIT_NR}",str(self.currentHit.id)) - estimatedHitDuration = self.store.getAvgDurationOfPreviousNHits(5) + estimatedHitDuration = self.store.getEstimatedHitDuration() fee = (self.config['hour_rate_aim']/3600.) * estimatedHitDuration self.currentHit.fee = fee @@ -254,7 +257,7 @@ class CentralManagement(): Reward = "{:.2f}".format(fee), MaxAssignments = 1, LifetimeInSeconds = self.config['hit_lifetime'], - AssignmentDurationInSeconds = self.config['hit_assignment_duration'], + AssignmentDurationInSeconds = estimatedHitDuration * 2, # give people twice as long as we expect them to take AutoApprovalDelayInSeconds = self.config['hit_autoapprove_delay'], Question = question, ) @@ -317,6 +320,7 @@ class CentralManagement(): def reset(self) -> str: # TODO: for returns & abandons + self.plotter.park() scan = threading.Thread(target=self.cleanDrawing, name='reset') scan.start() diff --git a/sorteerhoed/plotter.py b/sorteerhoed/plotter.py index 9b555c0..c27c6f2 100644 --- a/sorteerhoed/plotter.py +++ b/sorteerhoed/plotter.py @@ -53,10 +53,9 @@ class Plotter: self.ad.options.speed_pendown = 100 self.ad.options.model = 1 # 2 for A3, 1 for A4 - self.ad.moveto(0,0) -# plotterWidth = 25 -# plotterHeight = 21 + self.park() +# self.ad.moveto(0,0) else: self.ad = None @@ -66,11 +65,15 @@ class Plotter: finally: self.logger.warning("Close Axidraw connection") if self.ad: - with self.scannerLock: - self.ad.moveto(0,0) - self.ad.disconnect() + try: + with self.scannerLock: + self.ad.moveto(0,0) + self.ad.disconnect() + except Exception as e: + self.logger.warning("Error on closing axidraw:") + self.logger.exception(e) - self.logger.critical("Clear running Event") + self.logger.info("Clear running Event") # send shutdown signal (if not already set) self.isRunning.clear() diff --git a/sorteerhoed/webserver.py b/sorteerhoed/webserver.py index 214113a..8c32ba9 100644 --- a/sorteerhoed/webserver.py +++ b/sorteerhoed/webserver.py @@ -16,6 +16,7 @@ import httpagentparser import geoip2.database import queue import datetime +import html logger = logging.getLogger("sorteerhoed").getChild("webserver") @@ -62,6 +63,8 @@ class WebSocketHandler(tornado.websocket.WebSocketHandler): self.hit = self.store.currentHit + self.timeout = datetime.datetime.now() + datetime.timedelta(seconds=self.store.getEstimatedHitDuration() * 2) + if self.hit.submit_hit_at: raise Exception("Opening websocket for already submitted hit") @@ -80,6 +83,12 @@ class WebSocketHandler(tornado.websocket.WebSocketHandler): # the client sent the message def on_message(self, message): logger.debug(f"recieve: {message}") + + if datetime.datetime.now() > self.timeout: + logger.critical("Close websocket after timeout (abandon?)") + self.close() + return + try: msg = json.loads(message) # TODO: sanitize input: min/max, limit strokes @@ -100,6 +109,19 @@ class WebSocketHandler(tornado.websocket.WebSocketHandler): if not id: self.write_message(json.dumps('error')) return + #store svg: + d = html.escape(msg['d']) + svg = f""" + + + + """ + + with open(self.store.currentHit.getSvgImagePath(), 'w') as fp: + fp.write(svg) self.write_message(json.dumps({ 'action': 'submitted', diff --git a/www/index.html b/www/index.html index bce56bd..c0ea839 100644 --- a/www/index.html +++ b/www/index.html @@ -13,6 +13,17 @@ width:100%; height:100%; font-family: sans-serif; + z-index:2; + } + img{ + position:absolute; + top:0; + bottom:0; + right:0; + left:0; + width:100%; + height:100%; + z-index:1; } path { @@ -81,11 +92,10 @@ background:gray; } #interface{ - background:white; + background:black; height: 0; overflow: hidden; padding-top: calc({HEIGHT}/{WIDTH} * 100%); - background: white; position: relative; margin: 0 auto; background-size: 100% 100%; @@ -117,17 +127,18 @@ -
+
+
    -
  • Drag the mouse to trace the clearest lines drawing above
  • +
  • Drag the mouse to trace the lines drawing above
  • Follow the lines as precise as possible
  • Press submit when you're done.
  • You'll receive a submission token, to fill in at Mechanical Turk
  • @@ -304,7 +315,8 @@ } socket.send(JSON.stringify({ - 'action': 'submit' + 'action': 'submit', + 'd': strokeEl.getAttribute('d') })); document.body.removeEventListener('mousemove', draw);