Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -440,46 +440,6 @@ def create_reranking_interface(task_data):
|
|
440 |
|
441 |
return status, progress
|
442 |
|
443 |
-
def load_sample(sample_id):
|
444 |
-
"""Load a specific sample into the interface."""
|
445 |
-
sample = next((s for s in samples if s["id"] == sample_id), None)
|
446 |
-
if not sample:
|
447 |
-
return [query_text.value] + [d.value for d in doc_containers] + [""] * len(ranking_inputs) + [""] * len(validation_indicators) + [sample_id, progress_text.value, status_box.value]
|
448 |
-
|
449 |
-
# Update query
|
450 |
-
new_query = sample["query"]
|
451 |
-
|
452 |
-
# Update documents
|
453 |
-
new_docs = []
|
454 |
-
for i, doc in enumerate(sample["candidates"]):
|
455 |
-
if i < len(doc_containers):
|
456 |
-
new_docs.append(doc)
|
457 |
-
|
458 |
-
# Initialize rankings
|
459 |
-
new_rankings = [""] * len(ranking_inputs)
|
460 |
-
|
461 |
-
# Check if this sample has already been annotated
|
462 |
-
existing_annotation = next((a for a in results["annotations"] if a["sample_id"] == sample_id), None)
|
463 |
-
if existing_annotation:
|
464 |
-
# Restore previous rankings
|
465 |
-
for i, rank in enumerate(existing_annotation["rankings"]):
|
466 |
-
if i < len(new_rankings) and rank is not None:
|
467 |
-
new_rankings[i] = str(rank)
|
468 |
-
|
469 |
-
# Update progress
|
470 |
-
current_idx = samples.index(sample)
|
471 |
-
new_progress = f"Progress: {sum(completed_samples.values())}/{len(samples)}"
|
472 |
-
|
473 |
-
new_status = f"Viewing query {current_idx + 1} of {len(samples)}"
|
474 |
-
if completed_samples[sample_id]:
|
475 |
-
new_status += " (already completed)"
|
476 |
-
|
477 |
-
# Initialize validation indicators
|
478 |
-
validation_results = validate_rankings(*new_rankings)
|
479 |
-
validation_indicators_values = validation_results[:-1] # Remove validity flag
|
480 |
-
|
481 |
-
return [new_query] + new_docs + new_rankings + validation_indicators_values + [sample_id, new_progress, new_status]
|
482 |
-
|
483 |
def auto_save_and_navigate(direction, current_id, auto_save, *rankings):
|
484 |
"""Save rankings if auto-save is enabled, then navigate."""
|
485 |
# Extract rankings (remove validation indicators)
|
@@ -539,113 +499,143 @@ def create_reranking_interface(task_data):
|
|
539 |
except Exception as e:
|
540 |
return f"Error saving results: {str(e)}"
|
541 |
|
542 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
543 |
def assign_sequential_ranks():
|
544 |
"""Assign sequential rankings (1,2,3...) to all documents."""
|
545 |
sequential_ranks = [str(i+1) for i in range(len(samples[0]["candidates"]))]
|
546 |
-
# Return ranks
|
547 |
-
return sequential_ranks
|
548 |
|
549 |
def assign_reverse_ranks():
|
550 |
"""Assign reverse rankings (n,n-1...) to all documents."""
|
551 |
n = len(samples[0]["candidates"])
|
552 |
reverse_ranks = [str(n-i) for i in range(n)]
|
553 |
-
# Return ranks
|
554 |
-
return reverse_ranks
|
555 |
|
556 |
def clear_rankings():
|
557 |
"""Clear all rankings."""
|
558 |
empty_ranks = [""] * len(samples[0]["candidates"])
|
559 |
-
# Return empty ranks
|
560 |
-
return empty_ranks
|
561 |
-
|
562 |
-
#
|
|
|
|
|
|
|
|
|
|
|
563 |
sequential_btn.click(
|
564 |
fn=assign_sequential_ranks,
|
565 |
inputs=None,
|
566 |
-
outputs=ranking_inputs
|
|
|
|
|
|
|
|
|
567 |
)
|
568 |
|
569 |
reverse_btn.click(
|
570 |
fn=assign_reverse_ranks,
|
571 |
inputs=None,
|
572 |
-
outputs=ranking_inputs
|
|
|
|
|
|
|
|
|
573 |
)
|
574 |
|
575 |
clear_btn.click(
|
576 |
fn=clear_rankings,
|
577 |
inputs=None,
|
578 |
-
outputs=ranking_inputs
|
579 |
-
)
|
580 |
-
|
581 |
-
|
582 |
-
|
583 |
-
# add a "Validate Rankings" button that runs validation on demand
|
584 |
-
|
585 |
-
with gr.Row():
|
586 |
-
validate_btn = gr.Button("Validate Rankings", variant="secondary")
|
587 |
-
|
588 |
-
# Connect validate button to the right function
|
589 |
-
validate_btn.click(
|
590 |
-
fn=lambda *rankings: validate_rankings(*rankings)[:-1] + ["Validation complete"],
|
591 |
-
inputs=ranking_inputs,
|
592 |
-
outputs=validation_indicators + [status_box]
|
593 |
-
)
|
594 |
-
|
595 |
-
# Add a simpler validation for individual inputs that doesn't cascade to all inputs
|
596 |
-
def validate_single_input(rank, index):
|
597 |
-
"""Lightweight validation for a single input."""
|
598 |
-
if rank is None or rank == "":
|
599 |
-
return '<span style="color: #dc3545;">⚠️</span>'
|
600 |
-
else:
|
601 |
-
return f'<span style="color: #28a745;">✓ {rank}</span>'
|
602 |
-
|
603 |
-
# Connect simpler validation to each input
|
604 |
-
for i, ranking in enumerate(ranking_inputs):
|
605 |
-
ranking.change(
|
606 |
-
fn=lambda r, idx=i: validate_single_input(r, idx),
|
607 |
-
inputs=[ranking],
|
608 |
-
outputs=[validation_indicators[i]]
|
609 |
-
)
|
610 |
-
|
611 |
-
# Wire up events (Gradio 3.x syntax)
|
612 |
-
submit_btn.click(
|
613 |
-
fn=submit_rankings,
|
614 |
-
inputs=ranking_inputs + [current_sample_id],
|
615 |
-
outputs=[status_box, progress_text]
|
616 |
)
|
617 |
|
618 |
-
#
|
619 |
-
def handle_next(current_id, auto_save, *rankings):
|
620 |
-
# First, handle auto-save
|
621 |
-
new_id, status, progress = auto_save_and_navigate("next", current_id, auto_save, *rankings)
|
622 |
-
# Then, load the new sample
|
623 |
-
outputs = load_sample(new_id)
|
624 |
-
# Add the status and progress
|
625 |
-
outputs[-2] = progress if status else outputs[-2]
|
626 |
-
outputs[-1] = status if status else outputs[-1]
|
627 |
-
return outputs
|
628 |
-
|
629 |
-
def handle_prev(current_id, auto_save, *rankings):
|
630 |
-
# First, handle auto-save
|
631 |
-
new_id, status, progress = auto_save_and_navigate("prev", current_id, auto_save, *rankings)
|
632 |
-
# Then, load the new sample
|
633 |
-
outputs = load_sample(new_id)
|
634 |
-
# Add the status and progress
|
635 |
-
outputs[-2] = progress if status else outputs[-2]
|
636 |
-
outputs[-1] = status if status else outputs[-1]
|
637 |
-
return outputs
|
638 |
-
|
639 |
-
# Connect navigation with Gradio 3.x syntax
|
640 |
next_btn.click(
|
641 |
fn=handle_next,
|
642 |
inputs=[current_sample_id, auto_save_toggle] + ranking_inputs,
|
|
|
|
|
|
|
|
|
643 |
outputs=[query_text] + doc_containers + ranking_inputs + validation_indicators + [current_sample_id, progress_text, status_box]
|
644 |
)
|
645 |
|
646 |
prev_btn.click(
|
647 |
fn=handle_prev,
|
648 |
inputs=[current_sample_id, auto_save_toggle] + ranking_inputs,
|
|
|
|
|
|
|
|
|
649 |
outputs=[query_text] + doc_containers + ranking_inputs + validation_indicators + [current_sample_id, progress_text, status_box]
|
650 |
)
|
651 |
|
|
|
440 |
|
441 |
return status, progress
|
442 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
443 |
def auto_save_and_navigate(direction, current_id, auto_save, *rankings):
|
444 |
"""Save rankings if auto-save is enabled, then navigate."""
|
445 |
# Extract rankings (remove validation indicators)
|
|
|
499 |
except Exception as e:
|
500 |
return f"Error saving results: {str(e)}"
|
501 |
|
502 |
+
# Optimize the navigation functions to reduce unnecessary updates
|
503 |
+
def handle_next(current_id, auto_save, *rankings):
|
504 |
+
"""Optimized handler for next query navigation."""
|
505 |
+
# First, handle auto-save (only if needed)
|
506 |
+
new_id, status, progress = auto_save_and_navigate("next", current_id, auto_save, *rankings)
|
507 |
+
|
508 |
+
# Return the new sample ID for a more efficient update
|
509 |
+
# The load_sample function will handle all UI updates in one batch
|
510 |
+
return new_id
|
511 |
+
|
512 |
+
def handle_prev(current_id, auto_save, *rankings):
|
513 |
+
"""Optimized handler for previous query navigation."""
|
514 |
+
# First, handle auto-save (only if needed)
|
515 |
+
new_id, status, progress = auto_save_and_navigate("prev", current_id, auto_save, *rankings)
|
516 |
+
|
517 |
+
# Return the new sample ID for a more efficient update
|
518 |
+
# The load_sample function will handle all UI updates in one batch
|
519 |
+
return new_id
|
520 |
+
|
521 |
+
# Optimize the load_sample function to handle all UI updates efficiently
|
522 |
+
def load_sample(sample_id):
|
523 |
+
"""Load a specific sample into the interface."""
|
524 |
+
# Clear all validation indicators first for a cleaner transition
|
525 |
+
blank_validations = [""] * len(validation_indicators)
|
526 |
+
|
527 |
+
# Find the sample data
|
528 |
+
sample = next((s for s in samples if s["id"] == sample_id), None)
|
529 |
+
if not sample:
|
530 |
+
return [query_text.value] + [d.value for d in doc_containers] + [""] * len(ranking_inputs) + blank_validations + [sample_id, progress_text.value, status_box.value]
|
531 |
+
|
532 |
+
# Update query
|
533 |
+
new_query = sample["query"]
|
534 |
+
|
535 |
+
# Update documents
|
536 |
+
new_docs = []
|
537 |
+
for i, doc in enumerate(sample["candidates"]):
|
538 |
+
if i < len(doc_containers):
|
539 |
+
new_docs.append(doc)
|
540 |
+
|
541 |
+
# Initialize rankings
|
542 |
+
new_rankings = [""] * len(ranking_inputs)
|
543 |
+
|
544 |
+
# Check if this sample has already been annotated
|
545 |
+
existing_annotation = next((a for a in results["annotations"] if a["sample_id"] == sample_id), None)
|
546 |
+
if existing_annotation:
|
547 |
+
# Restore previous rankings
|
548 |
+
for i, rank in enumerate(existing_annotation["rankings"]):
|
549 |
+
if i < len(new_rankings) and rank is not None:
|
550 |
+
new_rankings[i] = str(rank)
|
551 |
+
|
552 |
+
# Update progress
|
553 |
+
current_idx = samples.index(sample)
|
554 |
+
new_progress = f"Progress: {sum(completed_samples.values())}/{len(samples)}"
|
555 |
+
|
556 |
+
new_status = f"Viewing query {current_idx + 1} of {len(samples)}"
|
557 |
+
if completed_samples[sample_id]:
|
558 |
+
new_status += " (already completed)"
|
559 |
+
|
560 |
+
# Initialize validation indicators (but don't run validation until needed)
|
561 |
+
# This improves load time
|
562 |
+
|
563 |
+
return [new_query] + new_docs + new_rankings + blank_validations + [sample_id, new_progress, new_status]
|
564 |
+
|
565 |
+
# Optimize the quick ranking functions for better performance
|
566 |
def assign_sequential_ranks():
|
567 |
"""Assign sequential rankings (1,2,3...) to all documents."""
|
568 |
sequential_ranks = [str(i+1) for i in range(len(samples[0]["candidates"]))]
|
569 |
+
# Return ranks only - validation will be done separately for better performance
|
570 |
+
return sequential_ranks
|
571 |
|
572 |
def assign_reverse_ranks():
|
573 |
"""Assign reverse rankings (n,n-1...) to all documents."""
|
574 |
n = len(samples[0]["candidates"])
|
575 |
reverse_ranks = [str(n-i) for i in range(n)]
|
576 |
+
# Return ranks only - validation will be done separately for better performance
|
577 |
+
return reverse_ranks
|
578 |
|
579 |
def clear_rankings():
|
580 |
"""Clear all rankings."""
|
581 |
empty_ranks = [""] * len(samples[0]["candidates"])
|
582 |
+
# Return empty ranks only - validation will be done separately for better performance
|
583 |
+
return empty_ranks
|
584 |
+
|
585 |
+
# Add a function to update status after quick ranking operations
|
586 |
+
def update_status_after_ranking(operation_name):
|
587 |
+
"""Update status box after a ranking operation."""
|
588 |
+
return f"✅ {operation_name} applied successfully"
|
589 |
+
|
590 |
+
# Connect quick ranking buttons with more efficient handling
|
591 |
sequential_btn.click(
|
592 |
fn=assign_sequential_ranks,
|
593 |
inputs=None,
|
594 |
+
outputs=ranking_inputs
|
595 |
+
).then(
|
596 |
+
fn=lambda: update_status_after_ranking("Sequential ranking"),
|
597 |
+
inputs=None,
|
598 |
+
outputs=[status_box]
|
599 |
)
|
600 |
|
601 |
reverse_btn.click(
|
602 |
fn=assign_reverse_ranks,
|
603 |
inputs=None,
|
604 |
+
outputs=ranking_inputs
|
605 |
+
).then(
|
606 |
+
fn=lambda: update_status_after_ranking("Reverse ranking"),
|
607 |
+
inputs=None,
|
608 |
+
outputs=[status_box]
|
609 |
)
|
610 |
|
611 |
clear_btn.click(
|
612 |
fn=clear_rankings,
|
613 |
inputs=None,
|
614 |
+
outputs=ranking_inputs
|
615 |
+
).then(
|
616 |
+
fn=lambda: update_status_after_ranking("Rankings cleared"),
|
617 |
+
inputs=None,
|
618 |
+
outputs=[status_box]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
619 |
)
|
620 |
|
621 |
+
# Connect navigation with more efficient data handling
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
622 |
next_btn.click(
|
623 |
fn=handle_next,
|
624 |
inputs=[current_sample_id, auto_save_toggle] + ranking_inputs,
|
625 |
+
outputs=[current_sample_id] # Only update the sample ID
|
626 |
+
).then(
|
627 |
+
fn=load_sample, # Then load the sample with all UI updates in one batch
|
628 |
+
inputs=[current_sample_id],
|
629 |
outputs=[query_text] + doc_containers + ranking_inputs + validation_indicators + [current_sample_id, progress_text, status_box]
|
630 |
)
|
631 |
|
632 |
prev_btn.click(
|
633 |
fn=handle_prev,
|
634 |
inputs=[current_sample_id, auto_save_toggle] + ranking_inputs,
|
635 |
+
outputs=[current_sample_id] # Only update the sample ID
|
636 |
+
).then(
|
637 |
+
fn=load_sample, # Then load the sample with all UI updates in one batch
|
638 |
+
inputs=[current_sample_id],
|
639 |
outputs=[query_text] + doc_containers + ranking_inputs + validation_indicators + [current_sample_id, progress_text, status_box]
|
640 |
)
|
641 |
|