Spaces:
Sleeping
Sleeping
v5 (launch): save-before-complete ordering, retry guidance on save failure
Browse files
app.py
CHANGED
|
@@ -111,10 +111,8 @@ def _save(rater: str, item_id: str, answers: dict, assigned_at: str, assigned_ts
|
|
| 111 |
"assigned_at": assigned_at, "submitted_at": _now_iso(),
|
| 112 |
"elapsed_s": round(time.time() - assigned_ts, 1) if assigned_ts else None,
|
| 113 |
"id": uuid.uuid4().hex[:8]}
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
_reserved.pop(item_id, None)
|
| 117 |
-
_rater_counts[rater] = _rater_counts.get(rater, 0) + 1
|
| 118 |
if api and RESULTS_REPO:
|
| 119 |
num = item_id.split("_")[1]
|
| 120 |
api.upload_file(path_or_fileobj=json.dumps(rec, ensure_ascii=False).encode(),
|
|
@@ -124,6 +122,10 @@ def _save(rater: str, item_id: str, answers: dict, assigned_at: str, assigned_ts
|
|
| 124 |
else:
|
| 125 |
with (ROOT/"local_results.jsonl").open("a") as f:
|
| 126 |
f.write(json.dumps(rec, ensure_ascii=False)+"\n")
|
|
|
|
|
|
|
|
|
|
|
|
|
| 127 |
|
| 128 |
def _progress(my_count: int) -> str:
|
| 129 |
return f"전체 진행 **{len(_completed)} / {len(ITEMS)}** · 내가 평가한 수 **{my_count}**"
|
|
@@ -167,7 +169,14 @@ def submit(rater, item_id, assigned_at, assigned_ts, my_count, c1, c2, c3, c4, r
|
|
| 167 |
if missing:
|
| 168 |
gr.Warning("모든 항목을 선택해주세요. 미선택: " + ", ".join(missing))
|
| 169 |
return tuple(gr.skip() for _ in range(n_out))
|
| 170 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 171 |
my_count = (my_count or 0) + 1
|
| 172 |
nxt = _pick_item()
|
| 173 |
if nxt is None:
|
|
|
|
| 111 |
"assigned_at": assigned_at, "submitted_at": _now_iso(),
|
| 112 |
"elapsed_s": round(time.time() - assigned_ts, 1) if assigned_ts else None,
|
| 113 |
"id": uuid.uuid4().hex[:8]}
|
| 114 |
+
# 저장이 성공한 뒤에만 완료 처리한다: 업로드 실패 시 예외를 올려 사용자에게
|
| 115 |
+
# 재제출을 안내하고, 아이템은 미완료로 남는다 (응답 유실 방지).
|
|
|
|
|
|
|
| 116 |
if api and RESULTS_REPO:
|
| 117 |
num = item_id.split("_")[1]
|
| 118 |
api.upload_file(path_or_fileobj=json.dumps(rec, ensure_ascii=False).encode(),
|
|
|
|
| 122 |
else:
|
| 123 |
with (ROOT/"local_results.jsonl").open("a") as f:
|
| 124 |
f.write(json.dumps(rec, ensure_ascii=False)+"\n")
|
| 125 |
+
with _lock:
|
| 126 |
+
_completed.add(item_id)
|
| 127 |
+
_reserved.pop(item_id, None)
|
| 128 |
+
_rater_counts[rater] = _rater_counts.get(rater, 0) + 1
|
| 129 |
|
| 130 |
def _progress(my_count: int) -> str:
|
| 131 |
return f"전체 진행 **{len(_completed)} / {len(ITEMS)}** · 내가 평가한 수 **{my_count}**"
|
|
|
|
| 169 |
if missing:
|
| 170 |
gr.Warning("모든 항목을 선택해주세요. 미선택: " + ", ".join(missing))
|
| 171 |
return tuple(gr.skip() for _ in range(n_out))
|
| 172 |
+
try:
|
| 173 |
+
_save(rater, item_id, {k: c for (k, _), c in zip(AXES, choices)}, assigned_at, assigned_ts)
|
| 174 |
+
except Exception as e:
|
| 175 |
+
print("save failed:", type(e).__name__, e)
|
| 176 |
+
gr.Warning("저장에 실패했습니다 (네트워크 문제일 수 있습니다). 잠시 후 '제출하고 다음'을 다시 눌러주세요 — 선택은 유지됩니다.")
|
| 177 |
+
with _lock:
|
| 178 |
+
_reserved[item_id] = time.time() # 이 사용자 몫으로 예약 연장
|
| 179 |
+
return tuple(gr.skip() for _ in range(n_out))
|
| 180 |
my_count = (my_count or 0) + 1
|
| 181 |
nxt = _pick_item()
|
| 182 |
if nxt is None:
|