HIT now on https://guest.rubenvandeven.com:8888 and integrates in Mturk interface, TODO: sync timer
This commit is contained in:
parent
7abd748f18
commit
dab6245792
10 changed files with 308 additions and 249 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -3,4 +3,8 @@ __pycache__
|
||||||
node_modules
|
node_modules
|
||||||
.pydevproject
|
.pydevproject
|
||||||
.project
|
.project
|
||||||
|
config.local.yml
|
||||||
|
hit_store.db
|
||||||
|
|
||||||
|
www/scans/*.svg
|
||||||
|
#scanimation/interfa
|
||||||
|
|
2
Pipfile
2
Pipfile
|
@ -23,4 +23,4 @@ pyserial = "*"
|
||||||
python_version = "3.7"
|
python_version = "3.7"
|
||||||
|
|
||||||
[packages.a209065]
|
[packages.a209065]
|
||||||
path = "./../../AxiDraw_API_v253r3"
|
path = "./../AxiDraw_API_v253r3"
|
||||||
|
|
119
Pipfile.lock
generated
119
Pipfile.lock
generated
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"_meta": {
|
"_meta": {
|
||||||
"hash": {
|
"hash": {
|
||||||
"sha256": "89332bbe3bba257b19a9566bd526d79af55c9ea4671357aab103126c35b67797"
|
"sha256": "29b194a198b1d9a791ea020295d0ef6d5969969f9d606e2457444485e1bd6f7a"
|
||||||
},
|
},
|
||||||
"pipfile-spec": 6,
|
"pipfile-spec": 6,
|
||||||
"requires": {
|
"requires": {
|
||||||
|
@ -17,29 +17,29 @@
|
||||||
},
|
},
|
||||||
"default": {
|
"default": {
|
||||||
"a209065": {
|
"a209065": {
|
||||||
"path": "./../../AxiDraw_API_v253r3"
|
"path": "./../AxiDraw_API_v253r3"
|
||||||
},
|
},
|
||||||
"boto3": {
|
"boto3": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:2945d8246e4c8875e3ae4aafffd028330ef681efc33e1475c1a805ed42540403",
|
"sha256:5db4db12a017be2a0b07ec662584b7b9e8afa05894c8aaac145576a7c39a9886",
|
||||||
"sha256:3d84311ce0f2fba83810f0e840b08e2b66246fc80dbb0a71fb992116f47b95bd"
|
"sha256:7fb8bf70ff2403991c8ae7bc548333811be6e432c7665721364ea0c858eb824e"
|
||||||
],
|
],
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
"version": "==1.10.6"
|
"version": "==1.10.41"
|
||||||
},
|
},
|
||||||
"botocore": {
|
"botocore": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:ac1a5caa10e3c4452714b17e6f30f05b4b6e57e0c80b19c1f4d72b234edf6646",
|
"sha256:5bfffa38ebba26ab462bb40e858702390fbe3ae2093a2177a8cde050ad6cb7e3",
|
||||||
"sha256:fa6b9e619423f3891e7c11b98f2183da8173e3fed995271e93fd4a712ef45777"
|
"sha256:62ddff63be904781f97ced737836a66f5b72579af788c905cfdab32d2970e15e"
|
||||||
],
|
],
|
||||||
"version": "==1.13.6"
|
"version": "==1.13.41"
|
||||||
},
|
},
|
||||||
"certifi": {
|
"certifi": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:e4f3620cfea4f83eedc95b24abd9cd56f3c4b146dd0177e83a21b4eb49e21e50",
|
"sha256:017c25db2a153ce562900032d5bc68e9f191e44e9a0f762f373977de9df1fbb3",
|
||||||
"sha256:fd7c7c74727ddcf00e9acd26bba8da604ffec95bf1c2144e67aff7a8b50e6cef"
|
"sha256:25b64c7da4cd7479594d035c08c2d809eb4aab3a26e5a990ea98cc450c320f1f"
|
||||||
],
|
],
|
||||||
"version": "==2019.9.11"
|
"version": "==2019.11.28"
|
||||||
},
|
},
|
||||||
"chardet": {
|
"chardet": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
|
@ -124,34 +124,34 @@
|
||||||
},
|
},
|
||||||
"lxml": {
|
"lxml": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:02ca7bf899da57084041bb0f6095333e4d239948ad3169443f454add9f4e9cb4",
|
"sha256:00ac0d64949fef6b3693813fe636a2d56d97a5a49b5bbb86e4cc4cc50ebc9ea2",
|
||||||
"sha256:096b82c5e0ea27ce9138bcbb205313343ee66a6e132f25c5ed67e2c8d960a1bc",
|
"sha256:0571e607558665ed42e450d7bf0e2941d542c18e117b1ebbf0ba72f287ad841c",
|
||||||
"sha256:0a920ff98cf1aac310470c644bc23b326402d3ef667ddafecb024e1713d485f1",
|
"sha256:0e3f04a7615fdac0be5e18b2406529521d6dbdb0167d2a690ee328bef7807487",
|
||||||
"sha256:1409b14bf83a7d729f92e2a7fbfe7ec929d4883ca071b06e95c539ceedb6497c",
|
"sha256:13cf89be53348d1c17b453867da68704802966c433b2bb4fa1f970daadd2ef70",
|
||||||
"sha256:17cae1730a782858a6e2758fd20dd0ef7567916c47757b694a06ffafdec20046",
|
"sha256:217262fcf6a4c2e1c7cb1efa08bd9ebc432502abc6c255c4abab611e8be0d14d",
|
||||||
"sha256:17e3950add54c882e032527795c625929613adbd2ce5162b94667334458b5a36",
|
"sha256:223e544828f1955daaf4cefbb4853bc416b2ec3fd56d4f4204a8b17007c21250",
|
||||||
"sha256:1f4f214337f6ee5825bf90a65d04d70aab05526c08191ab888cb5149501923c5",
|
"sha256:277cb61fede2f95b9c61912fefb3d43fbd5f18bf18a14fae4911b67984486f5d",
|
||||||
"sha256:2e8f77db25b0a96af679e64ff9bf9dddb27d379c9900c3272f3041c4d1327c9d",
|
"sha256:3213f753e8ae86c396e0e066866e64c6b04618e85c723b32ecb0909885211f74",
|
||||||
"sha256:4dffd405390a45ecb95ab5ab1c1b847553c18b0ef8ed01e10c1c8b1a76452916",
|
"sha256:4690984a4dee1033da0af6df0b7a6bde83f74e1c0c870623797cec77964de34d",
|
||||||
"sha256:6b899931a5648862c7b88c795eddff7588fb585e81cecce20f8d9da16eff96e0",
|
"sha256:4fcc472ef87f45c429d3b923b925704aa581f875d65bac80f8ab0c3296a63f78",
|
||||||
"sha256:726c17f3e0d7a7200718c9a890ccfeab391c9133e363a577a44717c85c71db27",
|
"sha256:61409bd745a265a742f2693e4600e4dbd45cc1daebe1d5fad6fcb22912d44145",
|
||||||
"sha256:760c12276fee05c36f95f8040180abc7fbebb9e5011447a97cdc289b5d6ab6fc",
|
"sha256:678f1963f755c5d9f5f6968dded7b245dd1ece8cf53c1aa9d80e6734a8c7f41d",
|
||||||
"sha256:796685d3969815a633827c818863ee199440696b0961e200b011d79b9394bbe7",
|
"sha256:6c6d03549d4e2734133badb9ab1c05d9f0ef4bcd31d83e5d2b4747c85cfa21da",
|
||||||
"sha256:891fe897b49abb7db470c55664b198b1095e4943b9f82b7dcab317a19116cd38",
|
"sha256:6e74d5f4d6ecd6942375c52ffcd35f4318a61a02328f6f1bd79fcb4ffedf969e",
|
||||||
"sha256:9277562f175d2334744ad297568677056861070399cec56ff06abbe2564d1232",
|
"sha256:7b4fc7b1ecc987ca7aaf3f4f0e71bbfbd81aaabf87002558f5bc95da3a865bcd",
|
||||||
"sha256:a471628e20f03dcdfde00770eeaf9c77811f0c331c8805219ca7b87ac17576c5",
|
"sha256:7ed386a40e172ddf44c061ad74881d8622f791d9af0b6f5be20023029129bc85",
|
||||||
"sha256:a63b4fd3e2cabdcc9d918ed280bdde3e8e9641e04f3c59a2a3109644a07b9832",
|
"sha256:8f54f0924d12c47a382c600c880770b5ebfc96c9fd94cf6f6bdc21caf6163ea7",
|
||||||
"sha256:ae88588d687bd476be588010cbbe551e9c2872b816f2da8f01f6f1fda74e1ef0",
|
"sha256:ad9b81351fdc236bda538efa6879315448411a81186c836d4b80d6ca8217cdb9",
|
||||||
"sha256:b0b84408d4eabc6de9dd1e1e0bc63e7731e890c0b378a62443e5741cfd0ae90a",
|
"sha256:bbd00e21ea17f7bcc58dccd13869d68441b32899e89cf6cfa90d624a9198ce85",
|
||||||
"sha256:be78485e5d5f3684e875dab60f40cddace2f5b2a8f7fede412358ab3214c3a6f",
|
"sha256:c3c289762cc09735e2a8f8a49571d0e8b4f57ea831ea11558247b5bdea0ac4db",
|
||||||
"sha256:c27eaed872185f047bb7f7da2d21a7d8913457678c9a100a50db6da890bc28b9",
|
"sha256:cf4650942de5e5685ad308e22bcafbccfe37c54aa7c0e30cd620c2ee5c93d336",
|
||||||
"sha256:c7fccd08b14aa437fe096c71c645c0f9be0655a9b1a4b7cffc77bcb23b3d61d2",
|
"sha256:cfcbc33c9c59c93776aa41ab02e55c288a042211708b72fdb518221cc803abc8",
|
||||||
"sha256:c81cb40bff373ab7a7446d6bbca0190bccc5be3448b47b51d729e37799bb5692",
|
"sha256:e301055deadfedbd80cf94f2f65ff23126b232b0d1fea28f332ce58137bcdb18",
|
||||||
"sha256:d11874b3c33ee441059464711cd365b89fa1a9cf19ae75b0c189b01fbf735b84",
|
"sha256:ebbfe24df7f7b5c6c7620702496b6419f6a9aa2fd7f005eb731cc80d7b4692b9",
|
||||||
"sha256:e9c028b5897901361d81a4718d1db217b716424a0283afe9d6735fe0caf70f79",
|
"sha256:eff69ddbf3ad86375c344339371168640951c302450c5d3e9936e98d6459db06",
|
||||||
"sha256:fe489d486cd00b739be826e8c1be188ddb74c7a1ca784d93d06fda882a6a1681"
|
"sha256:f6ed60a62c5f1c44e789d2cf14009423cb1646b44a43e40a9cf6a21f077678a1"
|
||||||
],
|
],
|
||||||
"version": "==4.4.1"
|
"version": "==4.4.2"
|
||||||
},
|
},
|
||||||
"maxminddb": {
|
"maxminddb": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
|
@ -221,22 +221,20 @@
|
||||||
},
|
},
|
||||||
"pyyaml": {
|
"pyyaml": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:0113bc0ec2ad727182326b61326afa3d1d8280ae1122493553fd6f4397f33df9",
|
"sha256:0e7f69397d53155e55d10ff68fdfb2cf630a35e6daf65cf0bdeaf04f127c09dc",
|
||||||
"sha256:01adf0b6c6f61bd11af6e10ca52b7d4057dd0be0343eb9283c878cf3af56aee4",
|
"sha256:2e9f0b7c5914367b0916c3c104a024bb68f269a486b9d04a2e8ac6f6597b7803",
|
||||||
"sha256:5124373960b0b3f4aa7df1707e63e9f109b5263eca5976c66e08b1c552d4eaf8",
|
"sha256:35ace9b4147848cafac3db142795ee42deebe9d0dad885ce643928e88daebdcc",
|
||||||
"sha256:5ca4f10adbddae56d824b2c09668e91219bb178a1eee1faa56af6f99f11bf696",
|
"sha256:38a4f0d114101c58c0f3a88aeaa44d63efd588845c5a2df5290b73db8f246d15",
|
||||||
"sha256:7907be34ffa3c5a32b60b95f4d95ea25361c951383a894fec31be7252b2b6f34",
|
"sha256:483eb6a33b671408c8529106df3707270bfacb2447bf8ad856a4b4f57f6e3075",
|
||||||
"sha256:7ec9b2a4ed5cad025c2278a1e6a19c011c80a3caaac804fd2d329e9cc2c287c9",
|
"sha256:4b6be5edb9f6bb73680f5bf4ee08ff25416d1400fbd4535fe0069b2994da07cd",
|
||||||
"sha256:87ae4c829bb25b9fe99cf71fbb2140c448f534e24c998cc60f39ae4f94396a73",
|
"sha256:7f38e35c00e160db592091751d385cd7b3046d6d51f578b29943225178257b31",
|
||||||
"sha256:9de9919becc9cc2ff03637872a440195ac4241c80536632fffeb6a1e25a74299",
|
"sha256:8100c896ecb361794d8bfdb9c11fce618c7cf83d624d73d5ab38aef3bc82d43f",
|
||||||
"sha256:a5a85b10e450c66b49f98846937e8cfca1db3127a9d5d1e31ca45c3d0bef4c5b",
|
"sha256:c0ee8eca2c582d29c3c2ec6e2c4f703d1b7f1fb10bc72317355a746057e7346c",
|
||||||
"sha256:b0997827b4f6a7c286c01c5f60384d218dca4ed7d9efa945c3e1aa623d5709ae",
|
"sha256:e4c015484ff0ff197564917b4b4246ca03f411b9bd7f16e02a2f586eb48b6d04",
|
||||||
"sha256:b631ef96d3222e62861443cc89d6563ba3eeb816eeb96b2629345ab795e53681",
|
"sha256:ebc4ed52dcc93eeebeae5cf5deb2ae4347b3a81c3fa12b0b8c976544829396a4"
|
||||||
"sha256:bf47c0607522fdbca6c9e817a6e81b08491de50f3766a7a0e6a5be7905961b41",
|
|
||||||
"sha256:f81025eddd0327c7d4cfe9b62cf33190e1e736cc6e97502b3ec425f574b3e7a8"
|
|
||||||
],
|
],
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
"version": "==5.1.2"
|
"version": "==5.2"
|
||||||
},
|
},
|
||||||
"requests": {
|
"requests": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
|
@ -262,17 +260,17 @@
|
||||||
},
|
},
|
||||||
"six": {
|
"six": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c",
|
"sha256:1f1b7d42e254082a9db6279deae68afb421ceba6158efa6131de7b3003ee93fd",
|
||||||
"sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"
|
"sha256:30f610279e8b2578cab6db20741130331735c781b56053c59c4076da27f06b66"
|
||||||
],
|
],
|
||||||
"version": "==1.12.0"
|
"version": "==1.13.0"
|
||||||
},
|
},
|
||||||
"sqlalchemy": {
|
"sqlalchemy": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:0f0768b5db594517e1f5e1572c73d14cf295140756431270d89496dc13d5e46c"
|
"sha256:bfb8f464a5000b567ac1d350b9090cf081180ec1ab4aa87e7bca12dab25320ec"
|
||||||
],
|
],
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
"version": "==1.3.10"
|
"version": "==1.3.12"
|
||||||
},
|
},
|
||||||
"tornado": {
|
"tornado": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
|
@ -289,11 +287,10 @@
|
||||||
},
|
},
|
||||||
"urllib3": {
|
"urllib3": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:3de946ffbed6e6746608990594d08faac602528ac7015ac28d33cee6a45b7398",
|
"sha256:a8a318824cc77d1fd4b2bec2ded92646630d7fe8619497b142c84a9e6f5a7293",
|
||||||
"sha256:9a107b99a5393caf59c7aa3c1249c16e6879447533d0887f4336dde834c7be86"
|
"sha256:f3c5fd51747d450d4dcf6f923c81f78f811aab8205fda64b0aba34a4e48b0745"
|
||||||
],
|
],
|
||||||
"markers": "python_version >= '3.4'",
|
"version": "==1.25.7"
|
||||||
"version": "==1.25.6"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"develop": {}
|
"develop": {}
|
||||||
|
|
|
@ -1,6 +1,16 @@
|
||||||
from pyaxidraw import axidraw
|
from pyaxidraw import axidraw
|
||||||
ad = axidraw.AxiDraw()
|
ad = axidraw.AxiDraw()
|
||||||
|
|
||||||
|
# connect/disconnect once because often first connection attempt fails
|
||||||
|
ad.interactive()
|
||||||
|
ad.connect()
|
||||||
|
ad.pen_raise()
|
||||||
|
ad.disconnect()
|
||||||
|
|
||||||
|
|
||||||
ad.plot_setup()
|
ad.plot_setup()
|
||||||
|
ad.pen_raise()
|
||||||
ad.options.mode = "manual"
|
ad.options.mode = "manual"
|
||||||
ad.options.manual_cmd = "disable_xy"
|
ad.options.manual_cmd = "disable_xy"
|
||||||
ad.plot_run()
|
ad.plot_run()
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ class HIT(Base):
|
||||||
|
|
||||||
|
|
||||||
def getImagePath(self):
|
def getImagePath(self):
|
||||||
return os.path.join('../scanimation/interfaces/frames', f"{self.id:06d}.jpg")
|
return os.path.join('scanimation/interfaces/frames', f"{self.id:06d}.jpg")
|
||||||
|
|
||||||
# def getImageUrl(self):
|
# def getImageUrl(self):
|
||||||
# return f"{self.id}.jpg"
|
# return f"{self.id}.jpg"
|
||||||
|
|
|
@ -86,6 +86,9 @@ class CentralManagement():
|
||||||
)
|
)
|
||||||
|
|
||||||
self.logger.info(f"Mechanical turk account balance: {self.mturk.get_account_balance()['AvailableBalance']}")
|
self.logger.info(f"Mechanical turk account balance: {self.mturk.get_account_balance()['AvailableBalance']}")
|
||||||
|
if not self.config['for_real']:
|
||||||
|
self.logger.info("Remove block from sandbox worker account")
|
||||||
|
self.mturk.delete_worker_block(WorkerId='A1CK46PK9VEUH5', Reason='Myself on Sandbox')
|
||||||
|
|
||||||
# clear any pending hits:
|
# clear any pending hits:
|
||||||
pending_hits = self.mturk.list_hits(MaxResults=100)
|
pending_hits = self.mturk.list_hits(MaxResults=100)
|
||||||
|
@ -173,7 +176,7 @@ class CentralManagement():
|
||||||
self.currentHit.scanned_at = datetime.datetime.utcnow()
|
self.currentHit.scanned_at = datetime.datetime.utcnow()
|
||||||
self.server.statusPage.set('state', self.currentHit.getStatus())
|
self.server.statusPage.set('state', self.currentHit.getStatus())
|
||||||
time_diff = datetime.datetime.now() - self.lastHitTime
|
time_diff = datetime.datetime.now() - self.lastHitTime
|
||||||
to_wait = 150 - time_diff.total_seconds()
|
to_wait = 10 - time_diff.total_seconds()
|
||||||
if to_wait > 0:
|
if to_wait > 0:
|
||||||
self.logger.warn(f"Sleep until next hit: {to_wait}s")
|
self.logger.warn(f"Sleep until next hit: {to_wait}s")
|
||||||
time.sleep(to_wait)
|
time.sleep(to_wait)
|
||||||
|
@ -272,8 +275,9 @@ class CentralManagement():
|
||||||
else:
|
else:
|
||||||
sqsHit.submit_hit_at = datetime.datetime.strptime(signal.params['event']['EventTimestamp'],"%Y-%m-%dT%H:%M:%SZ")
|
sqsHit.submit_hit_at = datetime.datetime.strptime(signal.params['event']['EventTimestamp'],"%Y-%m-%dT%H:%M:%SZ")
|
||||||
# Merijn: hier block ik de worker na succesvolle submit, om dubbele workers te voorkomen
|
# Merijn: hier block ik de worker na succesvolle submit, om dubbele workers te voorkomen
|
||||||
self.mturk.create_worker_block(WorkerId=signal.params['event']['WorkerId'], Reason='Every worker can only work once on the taks.')
|
# Disabled after worker mail, use quals instead
|
||||||
self.logger.warn("Block worker after submission")
|
#self.mturk.create_worker_block(WorkerId=signal.params['event']['WorkerId'], Reason='Every worker can only work once on the taks.')
|
||||||
|
#self.logger.warn("Block worker after submission")
|
||||||
|
|
||||||
|
|
||||||
self.store.saveHIT(sqsHit)
|
self.store.saveHIT(sqsHit)
|
||||||
|
@ -312,7 +316,13 @@ class CentralManagement():
|
||||||
|
|
||||||
self.logger.info(f"Make HIT {self.currentHit.id}")
|
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))
|
# question = open(self.config['amazon']['task_xml'], mode='r').read().replace("{HIT_NR}",str(self.currentHit.id))
|
||||||
|
question = '''<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ExternalQuestion xmlns="http://mechanicalturk.amazonaws.com/AWSMechanicalTurkDataSchemas/2006-07-14/ExternalQuestion.xsd">
|
||||||
|
<ExternalURL>https://guest.rubenvandeven.com:8888/draw?id={HIT_NR}</ExternalURL>
|
||||||
|
<FrameHeight>0</FrameHeight>
|
||||||
|
</ExternalQuestion>
|
||||||
|
'''.replace("{HIT_NR}",str(self.currentHit.id))
|
||||||
estimatedHitDuration = self.store.getEstimatedHitDuration()
|
estimatedHitDuration = self.store.getEstimatedHitDuration()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,7 @@ class Plotter:
|
||||||
self.ad.options.speed_penup = 100
|
self.ad.options.speed_penup = 100
|
||||||
self.ad.options.speed_pendown = 100
|
self.ad.options.speed_pendown = 100
|
||||||
self.ad.options.model = 1 # 2 for A3, 1 for A4
|
self.ad.options.model = 1 # 2 for A3, 1 for A4
|
||||||
|
self.ad.options.pen_pos_up = 100
|
||||||
|
|
||||||
|
|
||||||
self.park()
|
self.park()
|
||||||
|
|
|
@ -38,7 +38,7 @@ class StaticFileWithHeaderHandler(tornado.web.StaticFileHandler):
|
||||||
|
|
||||||
|
|
||||||
class WebSocketHandler(tornado.websocket.WebSocketHandler):
|
class WebSocketHandler(tornado.websocket.WebSocketHandler):
|
||||||
CORS_ORIGINS = ['localhost', '.mturk.com', 'here.rubenvandeven.com']
|
CORS_ORIGINS = ['localhost', '.mturk.com', 'here.rubenvandeven.com', 'guest.rubenvandeven.com']
|
||||||
connections = set()
|
connections = set()
|
||||||
|
|
||||||
def initialize(self, config, plotterQ: Queue, eventQ: Queue, store: HITStore):
|
def initialize(self, config, plotterQ: Queue, eventQ: Queue, store: HITStore):
|
||||||
|
@ -125,7 +125,8 @@ class WebSocketHandler(tornado.websocket.WebSocketHandler):
|
||||||
|
|
||||||
self.write_message(json.dumps({
|
self.write_message(json.dumps({
|
||||||
'action': 'submitted',
|
'action': 'submitted',
|
||||||
'msg': f"Submission ok, please copy this token to your HIT at Mechanical Turk: {self.hit.uuid}"
|
'msg': f"Submission ok, please copy this token to your HIT at Mechanical Turk: {self.hit.uuid}",
|
||||||
|
'code': str(self.hit.uuid)
|
||||||
}))
|
}))
|
||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
|
@ -284,6 +285,14 @@ class DrawPageHandler(tornado.web.RequestHandler):
|
||||||
self.write("HIT already submitted")
|
self.write("HIT already submitted")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
assignmentId = self.get_query_argument('assignmentId', '')
|
||||||
|
if len(assignmentId) < 1:
|
||||||
|
logger.critical("Accessing page without assignment id. Allowing it for debug purposes... fingers crossed?")
|
||||||
|
|
||||||
|
previewOnly = False
|
||||||
|
if assignmentId == 'ASSIGNMENT_ID_NOT_AVAILABLE':
|
||||||
|
previewOnly = True
|
||||||
|
|
||||||
previous_hit = self.store.getLastSubmittedHit()
|
previous_hit = self.store.getLastSubmittedHit()
|
||||||
if not previous_hit:
|
if not previous_hit:
|
||||||
# start with basic svg
|
# start with basic svg
|
||||||
|
@ -301,7 +310,10 @@ class DrawPageHandler(tornado.web.RequestHandler):
|
||||||
.replace("{DRAW_WIDTH}", str(self.draw_width))\
|
.replace("{DRAW_WIDTH}", str(self.draw_width))\
|
||||||
.replace("{DRAW_HEIGHT}", str(self.draw_height))\
|
.replace("{DRAW_HEIGHT}", str(self.draw_height))\
|
||||||
.replace("{TOP_PADDING}", str(self.top_padding))\
|
.replace("{TOP_PADDING}", str(self.top_padding))\
|
||||||
.replace("{LEFT_PADDING}", str(self.left_padding))
|
.replace("{LEFT_PADDING}", str(self.left_padding))\
|
||||||
|
.replace("{SCRIPT}", '' if previewOnly else '<script type="text/javascript" src="/assignment.js"></script>')\
|
||||||
|
.replace("{ASSIGNMENT}", '' if previewOnly else str(assignmentId)) # TODO: fix unsafe inserting of GET variable
|
||||||
|
|
||||||
self.write(contents)
|
self.write(contents)
|
||||||
|
|
||||||
if 'X-Forwarded-For' in self.request.headers:
|
if 'X-Forwarded-For' in self.request.headers:
|
||||||
|
@ -311,16 +323,18 @@ class DrawPageHandler(tornado.web.RequestHandler):
|
||||||
|
|
||||||
|
|
||||||
logger.info(f"Request from {ip}")
|
logger.info(f"Request from {ip}")
|
||||||
self.eventQ.put(Signal('hit.info', dict(hit_id=hit.id, ip=ip)))
|
|
||||||
|
|
||||||
try:
|
if not previewOnly:
|
||||||
geoip = self.geoip_reader.country(ip)
|
self.eventQ.put(Signal('hit.info', dict(hit_id=hit.id, ip=ip)))
|
||||||
logger.debug(f"Geo {geoip}")
|
|
||||||
self.eventQ.put(Signal('hit.info', dict(hit_id=hit.id, location=geoip.country.name)))
|
try:
|
||||||
except Exception as e:
|
geoip = self.geoip_reader.country(ip)
|
||||||
logger.exception(e)
|
logger.debug(f"Geo {geoip}")
|
||||||
logger.info("No geo IP possible")
|
self.eventQ.put(Signal('hit.info', dict(hit_id=hit.id, location=geoip.country.name)))
|
||||||
self.eventQ.put(Signal('hit.info', dict(hit_id=hit.id, location='Unknown')))
|
except Exception as e:
|
||||||
|
logger.exception(e)
|
||||||
|
logger.info("No geo IP possible")
|
||||||
|
self.eventQ.put(Signal('hit.info', dict(hit_id=hit.id, location='Unknown')))
|
||||||
|
|
||||||
class BackendHandler(tornado.web.RequestHandler):
|
class BackendHandler(tornado.web.RequestHandler):
|
||||||
def initialize(self, store: HITStore, path: str):
|
def initialize(self, store: HITStore, path: str):
|
||||||
|
|
174
www/assignment.js
Normal file
174
www/assignment.js
Normal file
|
@ -0,0 +1,174 @@
|
||||||
|
let url = window.location.origin.replace('http', 'ws') +'/ws?' + window.location.search.substring(1);
|
||||||
|
let svgEl = document.getElementById("canvas");
|
||||||
|
let strokeEl = document.getElementById('stroke');
|
||||||
|
let submitEl = document.getElementById('submit');
|
||||||
|
let resetEl = document.getElementById('reset');
|
||||||
|
let messageEl = document.getElementById('message');
|
||||||
|
let innerFaceEl = document.getElementById('innerface'); // wrapper within the interface
|
||||||
|
|
||||||
|
|
||||||
|
let strokes = [];
|
||||||
|
let isDrawing = false;
|
||||||
|
let hasMouseDown = false;
|
||||||
|
let currentPoint = null;
|
||||||
|
|
||||||
|
let getCoordinates = function(e) {
|
||||||
|
// convert event coordinates into relative positions on x & y axis
|
||||||
|
let box = innerFaceEl.getBoundingClientRect();
|
||||||
|
let x = (e.x - box['left']) / box['width'];
|
||||||
|
let y = (e.y - box['top']) / box['height'];
|
||||||
|
return {'x': x, 'y': y};
|
||||||
|
}
|
||||||
|
|
||||||
|
let isInsideBounds = function(pos) {
|
||||||
|
return !(pos['x'] < 0 || pos['y'] < 0 || pos['x'] > 1 || pos['y'] > 1);
|
||||||
|
}
|
||||||
|
let isInsideDrawingBounds = function(pos) {
|
||||||
|
if(pos['x'] > xPadding && pos['x'] < (xPadding+drawWidthFactor) && pos['y'] > yPadding && pos['y'] < yPadding+drawHeightFactor) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let draw = function(e) {
|
||||||
|
let pos = getCoordinates(e);
|
||||||
|
|
||||||
|
if(!isInsideBounds(pos)) {
|
||||||
|
// outside of bounds
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isDrawing && !isInsideDrawingBounds(pos)){
|
||||||
|
stopDrawing(pos);
|
||||||
|
}
|
||||||
|
if(!isDrawing && hasMouseDown && isInsideDrawingBounds(pos)){
|
||||||
|
isDrawing = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isDrawing) {
|
||||||
|
strokes.push([pos['x'], pos['y'], 0]);
|
||||||
|
let d = strokes2D(strokes);
|
||||||
|
strokeEl.setAttribute('d', d);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log([pos['x'], pos['y']], isDrawing);
|
||||||
|
socket.send(JSON.stringify({
|
||||||
|
'action': 'move',
|
||||||
|
'direction': [pos['x'], pos['y']],
|
||||||
|
'mouse': isDrawing,
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
let stopDrawing = function(pos) {
|
||||||
|
if(!isDrawing) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
isDrawing = false;
|
||||||
|
//document.body.removeEventListener('mousemove', draw);
|
||||||
|
|
||||||
|
|
||||||
|
if(strokes.length > 0){
|
||||||
|
// mark point as last of stroke
|
||||||
|
strokes[strokes.length - 1][2] = 1;
|
||||||
|
}
|
||||||
|
socket.send(JSON.stringify({
|
||||||
|
'action': 'up',
|
||||||
|
'direction': [pos['x'], pos['y']]
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
let penup = function(e) {
|
||||||
|
if(!hasMouseDown) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
hasMouseDown = false;
|
||||||
|
|
||||||
|
let pos = getCoordinates(e);
|
||||||
|
stopDrawing(pos);
|
||||||
|
};
|
||||||
|
let strokes2D = function(strokes) {
|
||||||
|
// strokes to a d attribute for a path
|
||||||
|
let d = "";
|
||||||
|
let last_stroke = undefined;
|
||||||
|
let cmd = "";
|
||||||
|
for (let stroke of strokes) {
|
||||||
|
if(!last_stroke) {
|
||||||
|
d += `M${stroke[0]*svgWidth*10},${stroke[1]*svgHeight*10} `;
|
||||||
|
cmd = 'M';
|
||||||
|
} else {
|
||||||
|
if (last_stroke[2] == 1) {
|
||||||
|
d += " m";
|
||||||
|
cmd = 'm';
|
||||||
|
} else if (cmd != 'l') {
|
||||||
|
d+=' l ';
|
||||||
|
cmd = 'l';
|
||||||
|
}
|
||||||
|
let rel_stroke = [stroke[0] - last_stroke[0], stroke[1] - last_stroke[1]];
|
||||||
|
d += `${rel_stroke[0]*svgWidth*10},${rel_stroke[1]*svgHeight*10} `;
|
||||||
|
}
|
||||||
|
last_stroke = stroke;
|
||||||
|
|
||||||
|
}
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
let startDrawing = function(e){
|
||||||
|
hasMouseDown = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*let reset = function() {
|
||||||
|
strokes = [];
|
||||||
|
strokeEl.setAttribute('d', "");
|
||||||
|
socket.send(JSON.stringify({
|
||||||
|
'action': 'reset',
|
||||||
|
}));
|
||||||
|
}*/
|
||||||
|
|
||||||
|
|
||||||
|
let socket = new WebSocket(url);
|
||||||
|
document.body.addEventListener('mousemove', draw);
|
||||||
|
document.body.addEventListener('mouseup', penup);
|
||||||
|
document.body.addEventListener('mousedown', startDrawing);
|
||||||
|
|
||||||
|
socket.addEventListener('message', function(e){
|
||||||
|
let msg = JSON.parse(e.data);
|
||||||
|
console.log('receive', msg);
|
||||||
|
if(msg['action'] == 'submitted') {
|
||||||
|
document.body.classList.add('submitted');
|
||||||
|
messageEl.innerHTML = msg['msg'];
|
||||||
|
svgEl.removeEventListener('mousedown', startDrawing);
|
||||||
|
}
|
||||||
|
|
||||||
|
// submit the completion form only after the shape has been sent to the server
|
||||||
|
let u = new URL(location);
|
||||||
|
let url = u.searchParams.get('turkSubmitTo');
|
||||||
|
let formEl = document.getElementById('finishedForm');
|
||||||
|
document.getElementById('surveycode').value = msg['code'];
|
||||||
|
formEl.action = url + '/mturk/externalSubmit';
|
||||||
|
formEl.submit();
|
||||||
|
|
||||||
|
// let assignmentId = u.searchParams.get('assignmentId');
|
||||||
|
// var formData = new FormData();
|
||||||
|
// formData.append('assigmentId', assignmentId);
|
||||||
|
// let r = new Request(url + '/mturk/externalSubmit', {method: 'POST', body: formData});
|
||||||
|
// fetch(r).then(function(response) {
|
||||||
|
// console.log(response);
|
||||||
|
// });
|
||||||
|
});
|
||||||
|
|
||||||
|
//resetEl.addEventListener('click', reset);
|
||||||
|
submitEl.addEventListener('click', function(e){
|
||||||
|
if(!strokes.length){
|
||||||
|
alert('please draw before submitting');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.send(JSON.stringify({
|
||||||
|
'action': 'submit',
|
||||||
|
'd': strokeEl.getAttribute('d')
|
||||||
|
}));
|
||||||
|
|
||||||
|
document.body.removeEventListener('mousemove', draw);
|
||||||
|
document.body.removeEventListener('mouseup', penup);
|
||||||
|
document.body.removeEventListener('mousedown', startDrawing);
|
||||||
|
});
|
189
www/index.html
189
www/index.html
|
@ -134,7 +134,7 @@
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id='interface'">
|
<div id='interface'>
|
||||||
<div id='innerface'>
|
<div id='innerface'>
|
||||||
<div id='wrapper'>
|
<div id='wrapper'>
|
||||||
<!-- <img src="{IMAGE_URL}" id='sample'>-->
|
<!-- <img src="{IMAGE_URL}" id='sample'>-->
|
||||||
|
@ -146,13 +146,18 @@
|
||||||
<div id='info'>
|
<div id='info'>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Drag the mouse to trace the lines drawing above</li>
|
<li>Drag the mouse to trace the lines drawing above</li>
|
||||||
<li>Follow the lines as precise as possible</li>
|
<li>Follow the lines as precise as possible, it is only this image to complete the HIT.</li>
|
||||||
<li>Press submit when you're done.</li>
|
<li>Press submit when you're done.</li>
|
||||||
<li>You'll receive a submission token, to fill in at Mechanical Turk</li>
|
<li><strong>Please watch the clock!</strong> timing is strict because the tracing is live streamed to us. Unfortunately, due to high abandonment rates we have to keep the timer strict.</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class='buttons'>
|
<div class='buttons'>
|
||||||
|
|
||||||
<button id='submit'>Submit</button>
|
<button id='submit'>Submit</button>
|
||||||
<!-- <button id='reset'>Reset</button>-->
|
<!-- <button id='reset'>Reset</button>-->
|
||||||
|
<form method='post' action='' id='finishedForm'>
|
||||||
|
<input type='hidden' name='surveycode' id='surveycode'>
|
||||||
|
<input type='hidden' name='assignmentId' value='{ASSIGNMENT}'>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div id='message'></div>
|
<div id='message'></div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -162,174 +167,18 @@
|
||||||
<div class='gray' id='gray_right'></div>
|
<div class='gray' id='gray_right'></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script type="text/javascript">
|
<script type='text/javascript'>
|
||||||
let url = window.location.origin.replace('http', 'ws') +'/ws?' + window.location.search.substring(1);
|
var svgWidth = {WIDTH};
|
||||||
let svgEl = document.getElementById("canvas");
|
var svgHeight = {HEIGHT};
|
||||||
let strokeEl = document.getElementById('stroke');
|
var drawWidth = {DRAW_WIDTH};
|
||||||
let submitEl = document.getElementById('submit');
|
var drawHeight = {DRAW_HEIGHT};
|
||||||
let resetEl = document.getElementById('reset');
|
|
||||||
let messageEl = document.getElementById('message');
|
|
||||||
let innerFaceEl = document.getElementById('innerface'); // wrapper within the interface
|
|
||||||
|
|
||||||
let svgWidth = {WIDTH};
|
var xPadding = {LEFT_PADDING} / svgWidth;
|
||||||
let svgHeight = {HEIGHT};
|
var yPadding = {TOP_PADDING} / svgHeight;
|
||||||
let drawWidth = {DRAW_WIDTH};
|
var drawWidthFactor = drawWidth / svgWidth;
|
||||||
let drawHeight = {DRAW_HEIGHT};
|
var drawHeightFactor = drawHeight / svgHeight;
|
||||||
|
|
||||||
let xPadding = {LEFT_PADDING} / svgWidth;
|
|
||||||
let yPadding = {TOP_PADDING} / svgHeight;
|
|
||||||
let drawWidthFactor = drawWidth / svgWidth;
|
|
||||||
let drawHeightFactor = drawHeight / svgHeight;
|
|
||||||
|
|
||||||
let strokes = [];
|
|
||||||
let isDrawing = false;
|
|
||||||
let hasMouseDown = false;
|
|
||||||
let currentPoint = null;
|
|
||||||
|
|
||||||
let getCoordinates = function(e) {
|
|
||||||
// convert event coordinates into relative positions on x & y axis
|
|
||||||
let box = innerFaceEl.getBoundingClientRect();
|
|
||||||
let x = (e.x - box['left']) / box['width'];
|
|
||||||
let y = (e.y - box['top']) / box['height'];
|
|
||||||
return {'x': x, 'y': y};
|
|
||||||
}
|
|
||||||
|
|
||||||
let isInsideBounds = function(pos) {
|
|
||||||
return !(pos['x'] < 0 || pos['y'] < 0 || pos['x'] > 1 || pos['y'] > 1);
|
|
||||||
}
|
|
||||||
let isInsideDrawingBounds = function(pos) {
|
|
||||||
if(pos['x'] > xPadding && pos['x'] < (xPadding+drawWidthFactor) && pos['y'] > yPadding && pos['y'] < yPadding+drawHeightFactor) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let draw = function(e) {
|
|
||||||
let pos = getCoordinates(e);
|
|
||||||
|
|
||||||
if(!isInsideBounds(pos)) {
|
|
||||||
// outside of bounds
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(isDrawing && !isInsideDrawingBounds(pos)){
|
|
||||||
stopDrawing(pos);
|
|
||||||
}
|
|
||||||
if(!isDrawing && hasMouseDown && isInsideDrawingBounds(pos)){
|
|
||||||
isDrawing = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(isDrawing) {
|
|
||||||
strokes.push([pos['x'], pos['y'], 0]);
|
|
||||||
let d = strokes2D(strokes);
|
|
||||||
strokeEl.setAttribute('d', d);
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log([pos['x'], pos['y']], isDrawing);
|
|
||||||
socket.send(JSON.stringify({
|
|
||||||
'action': 'move',
|
|
||||||
'direction': [pos['x'], pos['y']],
|
|
||||||
'mouse': isDrawing,
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
let stopDrawing = function(pos) {
|
|
||||||
if(!isDrawing) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
isDrawing = false;
|
|
||||||
//document.body.removeEventListener('mousemove', draw);
|
|
||||||
|
|
||||||
|
|
||||||
if(strokes.length > 0){
|
|
||||||
// mark point as last of stroke
|
|
||||||
strokes[strokes.length - 1][2] = 1;
|
|
||||||
}
|
|
||||||
socket.send(JSON.stringify({
|
|
||||||
'action': 'up',
|
|
||||||
'direction': [pos['x'], pos['y']]
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
let penup = function(e) {
|
|
||||||
if(!hasMouseDown) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
hasMouseDown = false;
|
|
||||||
|
|
||||||
let pos = getCoordinates(e);
|
|
||||||
stopDrawing(pos);
|
|
||||||
};
|
|
||||||
let strokes2D = function(strokes) {
|
|
||||||
// strokes to a d attribute for a path
|
|
||||||
let d = "";
|
|
||||||
let last_stroke = undefined;
|
|
||||||
let cmd = "";
|
|
||||||
for (let stroke of strokes) {
|
|
||||||
if(!last_stroke) {
|
|
||||||
d += `M${stroke[0]*svgWidth*10},${stroke[1]*svgHeight*10} `;
|
|
||||||
cmd = 'M';
|
|
||||||
} else {
|
|
||||||
if (last_stroke[2] == 1) {
|
|
||||||
d += " m";
|
|
||||||
cmd = 'm';
|
|
||||||
} else if (cmd != 'l') {
|
|
||||||
d+=' l ';
|
|
||||||
cmd = 'l';
|
|
||||||
}
|
|
||||||
let rel_stroke = [stroke[0] - last_stroke[0], stroke[1] - last_stroke[1]];
|
|
||||||
d += `${rel_stroke[0]*svgWidth*10},${rel_stroke[1]*svgHeight*10} `;
|
|
||||||
}
|
|
||||||
last_stroke = stroke;
|
|
||||||
|
|
||||||
}
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
|
|
||||||
let startDrawing = function(e){
|
|
||||||
hasMouseDown = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*let reset = function() {
|
|
||||||
strokes = [];
|
|
||||||
strokeEl.setAttribute('d', "");
|
|
||||||
socket.send(JSON.stringify({
|
|
||||||
'action': 'reset',
|
|
||||||
}));
|
|
||||||
}*/
|
|
||||||
|
|
||||||
|
|
||||||
let socket = new WebSocket(url);
|
|
||||||
document.body.addEventListener('mousemove', draw);
|
|
||||||
document.body.addEventListener('mouseup', penup);
|
|
||||||
document.body.addEventListener('mousedown', startDrawing);
|
|
||||||
|
|
||||||
socket.addEventListener('message', function(e){
|
|
||||||
let msg = JSON.parse(e.data);
|
|
||||||
console.log('receive', msg);
|
|
||||||
if(msg['action'] == 'submitted') {
|
|
||||||
document.body.classList.add('submitted');
|
|
||||||
messageEl.innerHTML = msg['msg'];
|
|
||||||
svgEl.removeEventListener('mousedown', startDrawing);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
//resetEl.addEventListener('click', reset);
|
|
||||||
submitEl.addEventListener('click', function(e){
|
|
||||||
if(!strokes.length){
|
|
||||||
alert('please draw before submitting');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
socket.send(JSON.stringify({
|
|
||||||
'action': 'submit',
|
|
||||||
'd': strokeEl.getAttribute('d')
|
|
||||||
}));
|
|
||||||
|
|
||||||
document.body.removeEventListener('mousemove', draw);
|
|
||||||
document.body.removeEventListener('mouseup', penup);
|
|
||||||
document.body.removeEventListener('mousedown', startDrawing);
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
{SCRIPT}
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
Loading…
Reference in a new issue