Spaces:
Running
Running
debugging intial loading issue
Browse files- components/review_dashboard_page.py +168 -53
components/review_dashboard_page.py
CHANGED
@@ -151,13 +151,37 @@ class ReviewDashboardPage:
|
|
151 |
# gr.Error(f"β Failed to load audio: {filename_to_load}. Error: {e}")
|
152 |
# return None, None, gr.update(value=None, autoplay=False)
|
153 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
154 |
def load_review_items_fn(session):
|
155 |
user_id = session.get("user_id")
|
156 |
username = session.get("username")
|
157 |
|
158 |
if not user_id or not username:
|
159 |
log.warning("load_review_items_fn: user not found in session")
|
160 |
-
# items, idx, review_info, tts_id, filename, sentence, ann_sentence, annotator_name_placeholder, annotated_at, validation_status, audio_update, rejection_reason_update, rejection_mode, btn_reject_update
|
161 |
return [], 0, "", "", "", "", "", "", "", "", gr.update(value=None, autoplay=False), gr.update(visible=False, value=""), False, gr.update(value="β Reject")
|
162 |
|
163 |
# Check if user is in Phase 2 (should be a reviewer)
|
@@ -176,9 +200,8 @@ class ReviewDashboardPage:
|
|
176 |
log.warning(f"No target annotator found for reviewer {username}")
|
177 |
return [], 0, "", "", "", "", "", "", "", "", gr.update(value=None, autoplay=False), gr.update(visible=False, value=""), False, gr.update(value="β Reject")
|
178 |
|
179 |
-
# Load annotations from target annotator
|
180 |
with get_db() as db:
|
181 |
-
# try:
|
182 |
# Get target annotator's ID
|
183 |
target_annotator_obj = db.query(Annotator).filter_by(name=target_annotator).first()
|
184 |
if not target_annotator_obj:
|
@@ -187,59 +210,47 @@ class ReviewDashboardPage:
|
|
187 |
|
188 |
log.info(f"Found target annotator with ID: {target_annotator_obj.id}")
|
189 |
|
190 |
-
#
|
191 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
192 |
Annotation.annotator_id == target_annotator_obj.id
|
193 |
-
).
|
194 |
-
orm.joinedload(Annotation.tts_data),
|
195 |
-
orm.joinedload(Annotation.annotator)
|
196 |
-
).order_by(Annotation.id).all() # Added order_by for consistency
|
197 |
|
198 |
-
log.info(f"
|
199 |
|
|
|
200 |
items = []
|
201 |
-
for annotation in
|
202 |
-
# Check if annotation is deleted (
|
203 |
is_deleted = not annotation.annotated_sentence or annotation.annotated_sentence.strip() == ""
|
204 |
-
|
205 |
-
# Check if this annotation has been reviewed by current user
|
206 |
-
existing_validation = db.query(Validation).filter_by(
|
207 |
-
annotation_id=annotation.id,
|
208 |
-
validator_id=user_id
|
209 |
-
).first()
|
210 |
-
|
211 |
-
validation_status = "Not Reviewed"
|
212 |
-
rejection_reason_val = "" # For the input box
|
213 |
-
rejection_visible_val = False # For the input box
|
214 |
-
|
215 |
-
if existing_validation:
|
216 |
-
if existing_validation.validated:
|
217 |
-
validation_status = "Approved"
|
218 |
-
else:
|
219 |
-
validation_status = f"Rejected"
|
220 |
-
if existing_validation.description:
|
221 |
-
validation_status += f" ({existing_validation.description})"
|
222 |
-
rejection_reason_val = existing_validation.description
|
223 |
-
rejection_visible_val = True
|
224 |
-
|
225 |
-
# For deleted annotations, show special status
|
226 |
-
if is_deleted:
|
227 |
-
annotated_sentence_display = "[DELETED ANNOTATION]"
|
228 |
-
if validation_status == "Not Reviewed":
|
229 |
-
validation_status = "Not Reviewed (Deleted)"
|
230 |
-
else:
|
231 |
-
annotated_sentence_display = annotation.annotated_sentence
|
232 |
|
233 |
items.append({
|
234 |
"annotation_id": annotation.id,
|
235 |
-
"tts_id": annotation.
|
236 |
-
"filename":
|
237 |
-
"sentence":
|
238 |
"annotated_sentence": annotated_sentence_display,
|
239 |
"is_deleted": is_deleted,
|
240 |
-
# "annotator_name": annotation.annotator.name, # Anonymized
|
241 |
"annotated_at": annotation.annotated_at.isoformat() if annotation.annotated_at else "",
|
242 |
-
"validation_status":
|
|
|
243 |
})
|
244 |
|
245 |
# Find the first item that is not reviewed (prioritize non-deleted annotations)
|
@@ -269,7 +280,7 @@ class ReviewDashboardPage:
|
|
269 |
# Set initial display
|
270 |
if items:
|
271 |
initial_item = items[initial_idx]
|
272 |
-
review_info_text = f"π **Phase 2 Review Mode** - Reviewing assigned annotations."
|
273 |
# Ensure correct order of return values for 12 outputs
|
274 |
# items, idx, review_info, tts_id, filename, sentence, ann_sentence, annotated_at, validation_status, annotator_placeholder, audio_update, rejection_reason_update
|
275 |
rejection_reason_val = ""
|
@@ -314,6 +325,30 @@ class ReviewDashboardPage:
|
|
314 |
return "", "", "", "", "", "", "", gr.update(value=None, autoplay=False), gr.update(visible=False, value=""), False, gr.update(value="β Reject")
|
315 |
|
316 |
current_item = items[idx]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
317 |
rejection_reason = ""
|
318 |
rejection_visible = False
|
319 |
|
@@ -346,7 +381,11 @@ class ReviewDashboardPage:
|
|
346 |
if not items:
|
347 |
return 0
|
348 |
if direction == "next":
|
349 |
-
|
|
|
|
|
|
|
|
|
350 |
else: # prev
|
351 |
return max(current_idx - 1, 0)
|
352 |
|
@@ -459,6 +498,86 @@ class ReviewDashboardPage:
|
|
459 |
# gr.Warning(f"Invalid Data ID format: {target_data_id}")
|
460 |
return current_idx
|
461 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
462 |
# Output definitions
|
463 |
review_display_outputs = [
|
464 |
self.tts_id, self.filename, self.sentence, self.ann_sentence,
|
@@ -487,12 +606,8 @@ class ReviewDashboardPage:
|
|
487 |
outputs=self.interactive_ui_elements
|
488 |
)
|
489 |
|
490 |
-
#
|
491 |
-
|
492 |
-
fn=download_voice_fn,
|
493 |
-
inputs=[self.filename],
|
494 |
-
outputs=[self.audio, self.original_audio_state, self.audio]
|
495 |
-
)
|
496 |
|
497 |
# Navigation buttons
|
498 |
for btn, direction in [(self.btn_prev, "prev"), (self.btn_next, "next")]:
|
|
|
151 |
# gr.Error(f"β Failed to load audio: {filename_to_load}. Error: {e}")
|
152 |
# return None, None, gr.update(value=None, autoplay=False)
|
153 |
|
154 |
+
def get_validation_status_for_item(db, annotation_id, user_id, annotation_obj):
|
155 |
+
"""Get validation status for a specific item - called on-demand"""
|
156 |
+
validation = db.query(Validation).filter_by(
|
157 |
+
annotation_id=annotation_id,
|
158 |
+
validator_id=user_id
|
159 |
+
).first()
|
160 |
+
|
161 |
+
# Check if annotation is deleted
|
162 |
+
is_deleted = not annotation_obj.annotated_sentence or annotation_obj.annotated_sentence.strip() == ""
|
163 |
+
|
164 |
+
validation_status = "Not Reviewed"
|
165 |
+
if validation:
|
166 |
+
if validation.validated:
|
167 |
+
validation_status = "Approved"
|
168 |
+
else:
|
169 |
+
validation_status = "Rejected"
|
170 |
+
if validation.description:
|
171 |
+
validation_status += f" ({validation.description})"
|
172 |
+
|
173 |
+
# For deleted annotations, show special status
|
174 |
+
if is_deleted and validation_status == "Not Reviewed":
|
175 |
+
validation_status = "Not Reviewed (Deleted)"
|
176 |
+
|
177 |
+
return validation_status, is_deleted
|
178 |
+
|
179 |
def load_review_items_fn(session):
|
180 |
user_id = session.get("user_id")
|
181 |
username = session.get("username")
|
182 |
|
183 |
if not user_id or not username:
|
184 |
log.warning("load_review_items_fn: user not found in session")
|
|
|
185 |
return [], 0, "", "", "", "", "", "", "", "", gr.update(value=None, autoplay=False), gr.update(visible=False, value=""), False, gr.update(value="β Reject")
|
186 |
|
187 |
# Check if user is in Phase 2 (should be a reviewer)
|
|
|
200 |
log.warning(f"No target annotator found for reviewer {username}")
|
201 |
return [], 0, "", "", "", "", "", "", "", "", gr.update(value=None, autoplay=False), gr.update(visible=False, value=""), False, gr.update(value="β Reject")
|
202 |
|
203 |
+
# Load annotations from target annotator with FAST INITIAL LOADING
|
204 |
with get_db() as db:
|
|
|
205 |
# Get target annotator's ID
|
206 |
target_annotator_obj = db.query(Annotator).filter_by(name=target_annotator).first()
|
207 |
if not target_annotator_obj:
|
|
|
210 |
|
211 |
log.info(f"Found target annotator with ID: {target_annotator_obj.id}")
|
212 |
|
213 |
+
# FAST INITIAL QUERY: Load only essential data without complex validation processing
|
214 |
+
# Reduced batch size for instant loading in HuggingFace spaces
|
215 |
+
INITIAL_BATCH_SIZE = 5 # Load only 5 items initially for instant response
|
216 |
+
|
217 |
+
# Simple query to get basic annotation data quickly
|
218 |
+
initial_query = db.query(
|
219 |
+
Annotation,
|
220 |
+
TTSData.filename,
|
221 |
+
TTSData.sentence
|
222 |
+
).join(
|
223 |
+
TTSData, Annotation.tts_data_id == TTSData.id
|
224 |
+
).filter(
|
225 |
+
Annotation.annotator_id == target_annotator_obj.id
|
226 |
+
).order_by(Annotation.id).limit(INITIAL_BATCH_SIZE)
|
227 |
+
|
228 |
+
initial_results = initial_query.all()
|
229 |
+
|
230 |
+
# Get total count for progress info (this is fast)
|
231 |
+
total_count = db.query(Annotation).filter(
|
232 |
Annotation.annotator_id == target_annotator_obj.id
|
233 |
+
).count()
|
|
|
|
|
|
|
234 |
|
235 |
+
log.info(f"Fast initial load: {len(initial_results)} annotations out of {total_count} total for target annotator ID {target_annotator_obj.id}")
|
236 |
|
237 |
+
# Process items with minimal data - validation status will be loaded on-demand
|
238 |
items = []
|
239 |
+
for annotation, filename, sentence in initial_results:
|
240 |
+
# Check if annotation is deleted (minimal processing)
|
241 |
is_deleted = not annotation.annotated_sentence or annotation.annotated_sentence.strip() == ""
|
242 |
+
annotated_sentence_display = "[DELETED ANNOTATION]" if is_deleted else annotation.annotated_sentence
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
243 |
|
244 |
items.append({
|
245 |
"annotation_id": annotation.id,
|
246 |
+
"tts_id": annotation.tts_data_id,
|
247 |
+
"filename": filename,
|
248 |
+
"sentence": sentence,
|
249 |
"annotated_sentence": annotated_sentence_display,
|
250 |
"is_deleted": is_deleted,
|
|
|
251 |
"annotated_at": annotation.annotated_at.isoformat() if annotation.annotated_at else "",
|
252 |
+
"validation_status": "Loading...", # Will be loaded on-demand
|
253 |
+
"validation_loaded": False # Track if validation status has been loaded
|
254 |
})
|
255 |
|
256 |
# Find the first item that is not reviewed (prioritize non-deleted annotations)
|
|
|
280 |
# Set initial display
|
281 |
if items:
|
282 |
initial_item = items[initial_idx]
|
283 |
+
review_info_text = f"π **Phase 2 Review Mode** - Reviewing assigned annotations. Loaded {len(items)} of {total_count} total items."
|
284 |
# Ensure correct order of return values for 12 outputs
|
285 |
# items, idx, review_info, tts_id, filename, sentence, ann_sentence, annotated_at, validation_status, annotator_placeholder, audio_update, rejection_reason_update
|
286 |
rejection_reason_val = ""
|
|
|
325 |
return "", "", "", "", "", "", "", gr.update(value=None, autoplay=False), gr.update(visible=False, value=""), False, gr.update(value="β Reject")
|
326 |
|
327 |
current_item = items[idx]
|
328 |
+
|
329 |
+
# Load validation status on-demand if not already loaded
|
330 |
+
if not current_item.get("validation_loaded", False):
|
331 |
+
user_id = session.get("user_id")
|
332 |
+
if user_id:
|
333 |
+
with get_db() as db:
|
334 |
+
try:
|
335 |
+
# Get the full annotation object for validation processing
|
336 |
+
annotation_obj = db.query(Annotation).filter_by(id=current_item["annotation_id"]).first()
|
337 |
+
if annotation_obj:
|
338 |
+
validation_status, is_deleted = get_validation_status_for_item(db, current_item["annotation_id"], user_id, annotation_obj)
|
339 |
+
current_item["validation_status"] = validation_status
|
340 |
+
current_item["is_deleted"] = is_deleted
|
341 |
+
current_item["validation_loaded"] = True
|
342 |
+
|
343 |
+
# Update displayed annotation if deleted
|
344 |
+
if is_deleted:
|
345 |
+
current_item["annotated_sentence"] = "[DELETED ANNOTATION]"
|
346 |
+
|
347 |
+
log.info(f"Loaded validation status for item {idx}: {validation_status}")
|
348 |
+
except Exception as e:
|
349 |
+
log.error(f"Error loading validation status for item {idx}: {e}")
|
350 |
+
current_item["validation_status"] = "Error loading status"
|
351 |
+
|
352 |
rejection_reason = ""
|
353 |
rejection_visible = False
|
354 |
|
|
|
381 |
if not items:
|
382 |
return 0
|
383 |
if direction == "next":
|
384 |
+
new_idx = min(current_idx + 1, len(items) - 1)
|
385 |
+
# Check if we're getting close to the end - load more items if needed
|
386 |
+
if new_idx >= len(items) - 2 and len(items) % 5 == 0: # Near end and items is a multiple of initial batch size
|
387 |
+
log.info(f"User is near end of loaded items ({new_idx}/{len(items)}), may need to load more items")
|
388 |
+
return new_idx
|
389 |
else: # prev
|
390 |
return max(current_idx - 1, 0)
|
391 |
|
|
|
498 |
# gr.Warning(f"Invalid Data ID format: {target_data_id}")
|
499 |
return current_idx
|
500 |
|
501 |
+
def load_more_items_fn(items, session, current_batch_size=100):
|
502 |
+
"""Load more items when user needs them (pagination support)"""
|
503 |
+
user_id = session.get("user_id")
|
504 |
+
username = session.get("username")
|
505 |
+
|
506 |
+
if not user_id or not username:
|
507 |
+
return items # Return existing items if no user session
|
508 |
+
|
509 |
+
# Find target annotator
|
510 |
+
target_annotator = None
|
511 |
+
for annotator_name, reviewer_name in conf.REVIEW_MAPPING.items():
|
512 |
+
if reviewer_name == username:
|
513 |
+
target_annotator = annotator_name
|
514 |
+
break
|
515 |
+
|
516 |
+
if not target_annotator:
|
517 |
+
return items
|
518 |
+
|
519 |
+
with get_db() as db:
|
520 |
+
target_annotator_obj = db.query(Annotator).filter_by(name=target_annotator).first()
|
521 |
+
if not target_annotator_obj:
|
522 |
+
return items
|
523 |
+
|
524 |
+
# Load next batch starting from where we left off
|
525 |
+
offset = len(items)
|
526 |
+
query = db.query(
|
527 |
+
Annotation,
|
528 |
+
TTSData.filename,
|
529 |
+
TTSData.sentence,
|
530 |
+
Validation.validated,
|
531 |
+
Validation.description
|
532 |
+
).join(
|
533 |
+
TTSData, Annotation.tts_data_id == TTSData.id
|
534 |
+
).outerjoin(
|
535 |
+
Validation,
|
536 |
+
(Validation.annotation_id == Annotation.id) &
|
537 |
+
(Validation.validator_id == user_id)
|
538 |
+
).filter(
|
539 |
+
Annotation.annotator_id == target_annotator_obj.id
|
540 |
+
).order_by(Annotation.id).offset(offset).limit(current_batch_size)
|
541 |
+
|
542 |
+
results = query.all()
|
543 |
+
|
544 |
+
# Process new items same as before
|
545 |
+
new_items = []
|
546 |
+
for annotation, filename, sentence, validated, validation_description in results:
|
547 |
+
is_deleted = not annotation.annotated_sentence or annotation.annotated_sentence.strip() == ""
|
548 |
+
|
549 |
+
validation_status = "Not Reviewed"
|
550 |
+
if validated is not None:
|
551 |
+
if validated:
|
552 |
+
validation_status = "Approved"
|
553 |
+
else:
|
554 |
+
validation_status = "Rejected"
|
555 |
+
if validation_description:
|
556 |
+
validation_status += f" ({validation_description})"
|
557 |
+
|
558 |
+
if is_deleted:
|
559 |
+
annotated_sentence_display = "[DELETED ANNOTATION]"
|
560 |
+
if validation_status == "Not Reviewed":
|
561 |
+
validation_status = "Not Reviewed (Deleted)"
|
562 |
+
else:
|
563 |
+
annotated_sentence_display = annotation.annotated_sentence
|
564 |
+
|
565 |
+
new_items.append({
|
566 |
+
"annotation_id": annotation.id,
|
567 |
+
"tts_id": annotation.tts_data_id,
|
568 |
+
"filename": filename,
|
569 |
+
"sentence": sentence,
|
570 |
+
"annotated_sentence": annotated_sentence_display,
|
571 |
+
"is_deleted": is_deleted,
|
572 |
+
"annotated_at": annotation.annotated_at.isoformat() if annotation.annotated_at else "",
|
573 |
+
"validation_status": validation_status
|
574 |
+
})
|
575 |
+
|
576 |
+
# Combine with existing items
|
577 |
+
all_items = items + new_items
|
578 |
+
log.info(f"Loaded {len(new_items)} more items, total now: {len(all_items)}")
|
579 |
+
return all_items
|
580 |
+
|
581 |
# Output definitions
|
582 |
review_display_outputs = [
|
583 |
self.tts_id, self.filename, self.sentence, self.ann_sentence,
|
|
|
606 |
outputs=self.interactive_ui_elements
|
607 |
)
|
608 |
|
609 |
+
# Audio loading is now manual only via the Load Audio button
|
610 |
+
# Removed automatic filename.change callback to prevent slow loading during initialization
|
|
|
|
|
|
|
|
|
611 |
|
612 |
# Navigation buttons
|
613 |
for btn, direction in [(self.btn_prev, "prev"), (self.btn_next, "next")]:
|