pearmut 0.2.6__py3-none-any.whl → 0.2.8__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pearmut/app.py +36 -29
- pearmut/cli.py +19 -23
- pearmut/static/dashboard.bundle.js +1 -1
- pearmut/static/listwise.bundle.js +1 -1
- pearmut/static/pointwise.bundle.js +1 -1
- pearmut-0.2.8.dist-info/METADATA +330 -0
- pearmut-0.2.8.dist-info/RECORD +19 -0
- pearmut-0.2.8.dist-info/licenses/LICENSE +21 -0
- pearmut-0.2.6.dist-info/METADATA +0 -350
- pearmut-0.2.6.dist-info/RECORD +0 -19
- pearmut-0.2.6.dist-info/licenses/LICENSE +0 -201
- {pearmut-0.2.6.dist-info → pearmut-0.2.8.dist-info}/WHEEL +0 -0
- {pearmut-0.2.6.dist-info → pearmut-0.2.8.dist-info}/entry_points.txt +0 -0
- {pearmut-0.2.6.dist-info → pearmut-0.2.8.dist-info}/top_level.txt +0 -0
pearmut/app.py
CHANGED
|
@@ -30,7 +30,8 @@ app.add_middleware(
|
|
|
30
30
|
|
|
31
31
|
tasks_data = {}
|
|
32
32
|
progress_data = load_progress_data(
|
|
33
|
-
warn="No progress.json found. Running, but no campaign will be available."
|
|
33
|
+
warn="No progress.json found. Running, but no campaign will be available."
|
|
34
|
+
)
|
|
34
35
|
|
|
35
36
|
# load all tasks into data_all
|
|
36
37
|
for campaign_id in progress_data.keys():
|
|
@@ -60,30 +61,31 @@ async def _log_response(request: LogResponseRequest):
|
|
|
60
61
|
|
|
61
62
|
# append response to the output log
|
|
62
63
|
save_db_payload(
|
|
63
|
-
campaign_id, request.payload | {"user_id": user_id, "item_i": item_i}
|
|
64
|
+
campaign_id, request.payload | {"user_id": user_id, "item_i": item_i}
|
|
65
|
+
)
|
|
64
66
|
|
|
65
67
|
# if actions were submitted, we can log time data
|
|
66
68
|
if "actions" in request.payload:
|
|
67
|
-
times = [
|
|
68
|
-
x["time"] for x in request.payload["actions"]
|
|
69
|
-
]
|
|
69
|
+
times = [x["time"] for x in request.payload["actions"]]
|
|
70
70
|
if progress_data[campaign_id][user_id]["time_start"] is None:
|
|
71
71
|
progress_data[campaign_id][user_id]["time_start"] = min(times)
|
|
72
72
|
progress_data[campaign_id][user_id]["time_end"] = max(times)
|
|
73
|
-
progress_data[campaign_id][user_id]["time"] += sum(
|
|
74
|
-
min(b - a, 60)
|
|
75
|
-
|
|
76
|
-
])
|
|
73
|
+
progress_data[campaign_id][user_id]["time"] += sum(
|
|
74
|
+
[min(b - a, 60) for a, b in zip(times, times[1:])]
|
|
75
|
+
)
|
|
77
76
|
|
|
78
77
|
# Initialize validation_checks if it doesn't exist
|
|
79
78
|
if "validations" in request.payload:
|
|
80
79
|
if "validations" not in progress_data[campaign_id][user_id]:
|
|
81
80
|
progress_data[campaign_id][user_id]["validations"] = {}
|
|
82
81
|
|
|
83
|
-
progress_data[campaign_id][user_id]["validations"][request.item_i] =
|
|
82
|
+
progress_data[campaign_id][user_id]["validations"][request.item_i] = (
|
|
83
|
+
request.payload["validations"]
|
|
84
|
+
)
|
|
84
85
|
|
|
85
|
-
update_progress(
|
|
86
|
-
|
|
86
|
+
update_progress(
|
|
87
|
+
campaign_id, user_id, tasks_data, progress_data, request.item_i, request.payload
|
|
88
|
+
)
|
|
87
89
|
save_progress_data(progress_data)
|
|
88
90
|
|
|
89
91
|
return JSONResponse(content="ok", status_code=200)
|
|
@@ -149,13 +151,15 @@ async def _dashboard_data(request: DashboardDataRequest):
|
|
|
149
151
|
|
|
150
152
|
if campaign_id not in progress_data:
|
|
151
153
|
return JSONResponse(content="Unknown campaign ID", status_code=400)
|
|
152
|
-
|
|
153
|
-
is_privileged =
|
|
154
|
+
|
|
155
|
+
is_privileged = request.token == tasks_data[campaign_id]["token"]
|
|
154
156
|
|
|
155
157
|
progress_new = {}
|
|
156
158
|
assignment = tasks_data[campaign_id]["info"]["assignment"]
|
|
157
159
|
if assignment not in ["task-based", "single-stream"]:
|
|
158
|
-
return JSONResponse(
|
|
160
|
+
return JSONResponse(
|
|
161
|
+
content="Unsupported campaign assignment type", status_code=400
|
|
162
|
+
)
|
|
159
163
|
|
|
160
164
|
# Get threshold info for the campaign
|
|
161
165
|
validation_threshold = tasks_data[campaign_id]["info"].get("validation_threshold")
|
|
@@ -164,10 +168,9 @@ async def _dashboard_data(request: DashboardDataRequest):
|
|
|
164
168
|
# shallow copy
|
|
165
169
|
entry = dict(user_val)
|
|
166
170
|
entry["validations"] = [
|
|
167
|
-
all(v)
|
|
168
|
-
for v in list(entry.get("validations", {}).values())
|
|
171
|
+
all(v) for v in list(entry.get("validations", {}).values())
|
|
169
172
|
]
|
|
170
|
-
|
|
173
|
+
|
|
171
174
|
# Add threshold pass/fail status (only when user is complete)
|
|
172
175
|
if all(entry["progress"]):
|
|
173
176
|
entry["threshold_passed"] = check_validation_threshold(
|
|
@@ -183,11 +186,8 @@ async def _dashboard_data(request: DashboardDataRequest):
|
|
|
183
186
|
progress_new[user_id] = entry
|
|
184
187
|
|
|
185
188
|
return JSONResponse(
|
|
186
|
-
content={
|
|
187
|
-
|
|
188
|
-
"validation_threshold": validation_threshold
|
|
189
|
-
},
|
|
190
|
-
status_code=200
|
|
189
|
+
content={"data": progress_new, "validation_threshold": validation_threshold},
|
|
190
|
+
status_code=200,
|
|
191
191
|
)
|
|
192
192
|
|
|
193
193
|
|
|
@@ -227,7 +227,9 @@ async def _download_annotations(
|
|
|
227
227
|
for campaign_id in campaign_id:
|
|
228
228
|
output_path = f"{ROOT}/data/outputs/{campaign_id}.jsonl"
|
|
229
229
|
if campaign_id not in progress_data:
|
|
230
|
-
return JSONResponse(
|
|
230
|
+
return JSONResponse(
|
|
231
|
+
content=f"Unknown campaign ID {campaign_id}", status_code=400
|
|
232
|
+
)
|
|
231
233
|
if not os.path.exists(output_path):
|
|
232
234
|
output[campaign_id] = []
|
|
233
235
|
else:
|
|
@@ -239,28 +241,33 @@ async def _download_annotations(
|
|
|
239
241
|
|
|
240
242
|
@app.get("/download-progress")
|
|
241
243
|
async def _download_progress(
|
|
242
|
-
campaign_id: list[str] = Query(),
|
|
243
|
-
token: list[str] = Query()
|
|
244
|
+
campaign_id: list[str] = Query(), token: list[str] = Query()
|
|
244
245
|
):
|
|
245
246
|
|
|
246
247
|
if len(campaign_id) != len(token):
|
|
247
|
-
return JSONResponse(
|
|
248
|
+
return JSONResponse(
|
|
249
|
+
content="Mismatched campaign_id and token count", status_code=400
|
|
250
|
+
)
|
|
248
251
|
|
|
249
252
|
output = {}
|
|
250
253
|
for i, cid in enumerate(campaign_id):
|
|
251
254
|
if cid not in progress_data:
|
|
252
255
|
return JSONResponse(content=f"Unknown campaign ID {cid}", status_code=400)
|
|
253
256
|
if token[i] != tasks_data[cid]["token"]:
|
|
254
|
-
return JSONResponse(
|
|
257
|
+
return JSONResponse(
|
|
258
|
+
content=f"Invalid token for campaign ID {cid}", status_code=400
|
|
259
|
+
)
|
|
255
260
|
|
|
256
261
|
output[cid] = progress_data[cid]
|
|
257
262
|
|
|
258
263
|
return JSONResponse(content=output, status_code=200)
|
|
259
264
|
|
|
265
|
+
|
|
260
266
|
static_dir = f"{os.path.dirname(os.path.abspath(__file__))}/static/"
|
|
261
267
|
if not os.path.exists(static_dir + "index.html"):
|
|
262
268
|
raise FileNotFoundError(
|
|
263
|
-
"Static directory not found. Please build the frontend first."
|
|
269
|
+
"Static directory not found. Please build the frontend first."
|
|
270
|
+
)
|
|
264
271
|
|
|
265
272
|
app.mount(
|
|
266
273
|
"/",
|
pearmut/cli.py
CHANGED
|
@@ -278,26 +278,24 @@ def _add_single_campaign(data_file, overwrite, server):
|
|
|
278
278
|
)
|
|
279
279
|
|
|
280
280
|
# Symlink path is based on the destination, stripping the 'assets/' prefix
|
|
281
|
-
symlink_path = f"{STATIC_DIR}/{assets_destination}"
|
|
281
|
+
symlink_path = f"{STATIC_DIR}/{assets_destination}".rstrip("/")
|
|
282
282
|
|
|
283
283
|
# Remove existing symlink if present and we are overriding the same campaign
|
|
284
284
|
if os.path.lexists(symlink_path):
|
|
285
285
|
# Check if any other campaign is using this destination
|
|
286
286
|
current_campaign_id = campaign_data['campaign_id']
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
f"Assets destination '{assets_destination}' is already used by campaign '{other_campaign_id}'."
|
|
300
|
-
)
|
|
287
|
+
|
|
288
|
+
for other_campaign_id in progress_data.keys():
|
|
289
|
+
if other_campaign_id == current_campaign_id:
|
|
290
|
+
continue
|
|
291
|
+
with open(f"{ROOT}/data/tasks/{other_campaign_id}.json", "r") as f:
|
|
292
|
+
other_campaign = json.load(f)
|
|
293
|
+
other_assets = other_campaign.get("info", {}).get("assets")
|
|
294
|
+
if other_assets:
|
|
295
|
+
if other_assets.get("destination") == assets_destination:
|
|
296
|
+
raise ValueError(
|
|
297
|
+
f"Assets destination '{assets_destination}' is already used by campaign '{other_campaign_id}'."
|
|
298
|
+
)
|
|
301
299
|
# Only allow overwrite if it's the same campaign
|
|
302
300
|
if overwrite:
|
|
303
301
|
os.remove(symlink_path)
|
|
@@ -305,7 +303,8 @@ def _add_single_campaign(data_file, overwrite, server):
|
|
|
305
303
|
raise ValueError(f"Assets destination '{assets_destination}' is already taken.")
|
|
306
304
|
|
|
307
305
|
# Ensure the assets directory exists
|
|
308
|
-
|
|
306
|
+
# get parent of symlink_path dir
|
|
307
|
+
os.makedirs(os.path.dirname(symlink_path), exist_ok=True)
|
|
309
308
|
|
|
310
309
|
os.symlink(assets_real_path, symlink_path, target_is_directory=True)
|
|
311
310
|
print(f"Assets symlinked: {symlink_path} -> {assets_real_path}")
|
|
@@ -391,7 +390,7 @@ def main():
|
|
|
391
390
|
campaign_data = json.load(f)
|
|
392
391
|
destination = campaign_data.get("info", {}).get("assets", {}).get("destination")
|
|
393
392
|
if destination:
|
|
394
|
-
symlink_path = f"{STATIC_DIR}/{destination}"
|
|
393
|
+
symlink_path = f"{STATIC_DIR}/{destination}".rstrip("/")
|
|
395
394
|
if os.path.islink(symlink_path):
|
|
396
395
|
os.remove(symlink_path)
|
|
397
396
|
print(f"Assets symlink removed: {symlink_path}")
|
|
@@ -436,12 +435,9 @@ def main():
|
|
|
436
435
|
)
|
|
437
436
|
if confirm.lower() == 'y':
|
|
438
437
|
# Unlink all assets first
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
if task_file.endswith('.json'):
|
|
443
|
-
campaign_id = task_file[:-5]
|
|
444
|
-
_unlink_assets(campaign_id)
|
|
438
|
+
progress_data = load_progress_data()
|
|
439
|
+
for campaign_id in progress_data.keys():
|
|
440
|
+
_unlink_assets(campaign_id)
|
|
445
441
|
shutil.rmtree(f"{ROOT}/data/tasks", ignore_errors=True)
|
|
446
442
|
shutil.rmtree(f"{ROOT}/data/outputs", ignore_errors=True)
|
|
447
443
|
if os.path.exists(f"{ROOT}/data/progress.json"):
|