Spaces:
Running
Running
Commit ·
fee90dc
1
Parent(s): d21edc9
Implement document index persistence and streamline evaluation actions
Browse filesRefactor the evaluation process to load and save the current document index from a file, enhancing user experience by maintaining progress across sessions. Simplify handling of jump, skip, and submit actions, while improving feedback messages for document navigation. Update logging for better traceability of user actions during evaluations.
- app.py +68 -208
- templates/evaluate.html +13 -3
app.py
CHANGED
|
@@ -418,225 +418,59 @@ def evaluate():
|
|
| 418 |
# Create sessions directory if it doesn't exist
|
| 419 |
os.makedirs(os.path.join(DATA_DIR, 'sessions'), exist_ok=True)
|
| 420 |
|
| 421 |
-
# Initialize current document index
|
| 422 |
-
|
| 423 |
-
session['current_document_index'] = 1
|
| 424 |
|
| 425 |
-
#
|
| 426 |
jump_to = request.args.get('jump_to', type=int)
|
| 427 |
if jump_to is not None:
|
| 428 |
-
# Ensure jump_to is within valid range
|
| 429 |
documents = load_documents()
|
| 430 |
-
if
|
| 431 |
-
|
| 432 |
-
|
| 433 |
-
log_error(f"JUMP: Setting document index to {jump_to}")
|
| 434 |
-
else:
|
| 435 |
-
flash(f"Invalid document number. Please enter a number between 1 and {len(documents)}.")
|
| 436 |
-
log_error(f"Invalid jump_to value: {jump_to}")
|
| 437 |
-
else:
|
| 438 |
-
# Log current position when not jumping
|
| 439 |
-
current_idx = session.get('current_document_index', 1)
|
| 440 |
-
print(f"DEBUG CONTINUE: Current document index is {current_idx}")
|
| 441 |
-
log_error(f"CONTINUE: Current document index is {current_idx}")
|
| 442 |
-
|
| 443 |
-
|
| 444 |
|
| 445 |
-
#
|
| 446 |
if request.method == 'POST':
|
| 447 |
-
|
| 448 |
-
# Debug session state at start of POST
|
| 449 |
-
current_session_index = session.get('current_document_index', 1)
|
| 450 |
-
print(f"DEBUG POST START: action={request.form.get('action')}, session_index={current_session_index}")
|
| 451 |
-
|
| 452 |
-
# Handle different button actions
|
| 453 |
-
action = request.form.get('action', 'submit')
|
| 454 |
-
|
| 455 |
-
# Handle "Stop and Save" action
|
| 456 |
-
if action == 'stop_save':
|
| 457 |
-
# First save the current evaluation if form data is provided
|
| 458 |
-
try:
|
| 459 |
-
# Check if we have evaluation data to save
|
| 460 |
-
has_criteria_data = any(f"criteria_{i}" in request.form for i in range(len(CRITERIA)))
|
| 461 |
-
has_note_origin = 'note_origin' in request.form
|
| 462 |
-
|
| 463 |
-
if has_criteria_data and has_note_origin:
|
| 464 |
-
# Get all documents
|
| 465 |
-
all_documents = load_documents()
|
| 466 |
-
current_index = session.get('current_document_index', 1)
|
| 467 |
-
|
| 468 |
-
if current_index <= len(all_documents):
|
| 469 |
-
document = all_documents[current_index - 1] # Convert to 0-based for array access
|
| 470 |
-
|
| 471 |
-
# Prepare evaluation data
|
| 472 |
-
evaluation_data = {
|
| 473 |
-
'document_title': document.get('filename', 'Unknown'),
|
| 474 |
-
'description': document.get('description', ''),
|
| 475 |
-
'mrn': document.get('mrn', ''),
|
| 476 |
-
'investigator_name': evaluator_name,
|
| 477 |
-
}
|
| 478 |
-
|
| 479 |
-
# Get criteria scores
|
| 480 |
-
for i, criterion in enumerate(CRITERIA):
|
| 481 |
-
score_key = f"criteria_{i}"
|
| 482 |
-
if score_key in request.form:
|
| 483 |
-
evaluation_data[criterion] = request.form[score_key]
|
| 484 |
-
|
| 485 |
-
# Get note origin assessment
|
| 486 |
-
if 'note_origin' in request.form:
|
| 487 |
-
evaluation_data['note_origin'] = request.form['note_origin']
|
| 488 |
-
|
| 489 |
-
# Save evaluation data
|
| 490 |
-
save_result = save_evaluation(evaluation_data)
|
| 491 |
-
|
| 492 |
-
if save_result:
|
| 493 |
-
log_error("Current evaluation saved before stopping")
|
| 494 |
-
flash("Current evaluation saved. You can resume later from where you left off.")
|
| 495 |
-
else:
|
| 496 |
-
flash("Session progress saved (current evaluation could not be saved).")
|
| 497 |
-
else:
|
| 498 |
-
flash("Session progress saved. You can resume later from where you left off.")
|
| 499 |
-
else:
|
| 500 |
-
flash("Session progress saved. You can resume later from where you left off.")
|
| 501 |
-
except Exception as e:
|
| 502 |
-
log_error(f"Error saving current evaluation on stop: {str(e)}")
|
| 503 |
-
flash("Session progress saved. You can resume later from where you left off.")
|
| 504 |
-
|
| 505 |
-
return redirect(url_for('results'))
|
| 506 |
-
|
| 507 |
-
# Handle "Skip" action
|
| 508 |
-
if action == 'skip':
|
| 509 |
-
current_index = session.get('current_document_index', 1)
|
| 510 |
-
new_index = current_index + 1
|
| 511 |
-
session['current_document_index'] = new_index
|
| 512 |
-
print(f"DEBUG SKIP: Moved from document {current_index} to {new_index}")
|
| 513 |
-
log_error(f"SKIP: Moved from document {current_index} to {new_index}")
|
| 514 |
-
|
| 515 |
-
# Debug session state before redirect
|
| 516 |
-
final_session_index = session.get('current_document_index', 1)
|
| 517 |
-
print(f"DEBUG SKIP REDIRECT: final_session_index={final_session_index}")
|
| 518 |
-
|
| 519 |
-
flash("Document skipped.")
|
| 520 |
-
return redirect(url_for('evaluate'))
|
| 521 |
-
|
| 522 |
-
# Handle regular evaluation submission
|
| 523 |
-
# Get all documents
|
| 524 |
-
all_documents = load_documents()
|
| 525 |
-
log_error(f"Loaded {len(all_documents)} total documents for POST")
|
| 526 |
-
|
| 527 |
-
if not all_documents:
|
| 528 |
-
flash("No documents available for evaluation.")
|
| 529 |
-
return redirect(url_for('index'))
|
| 530 |
-
|
| 531 |
-
current_index = session.get('current_document_index', 1)
|
| 532 |
-
if current_index > len(all_documents):
|
| 533 |
-
flash("All documents have been processed.")
|
| 534 |
-
return redirect(url_for('results'))
|
| 535 |
-
|
| 536 |
-
document = all_documents[current_index - 1] # Convert to 0-based for array access
|
| 537 |
-
log_error(f"Processing evaluation for document: {document.get('filename')}")
|
| 538 |
-
|
| 539 |
-
# Prepare evaluation data
|
| 540 |
-
evaluation_data = {
|
| 541 |
-
'document_title': document.get('filename', 'Unknown'),
|
| 542 |
-
'description': document.get('description', ''),
|
| 543 |
-
'mrn': document.get('mrn', ''),
|
| 544 |
-
'investigator_name': evaluator_name,
|
| 545 |
-
}
|
| 546 |
-
|
| 547 |
-
# Get criteria scores
|
| 548 |
-
for i, criterion in enumerate(CRITERIA):
|
| 549 |
-
score_key = f"criteria_{i}"
|
| 550 |
-
if score_key in request.form:
|
| 551 |
-
evaluation_data[criterion] = request.form[score_key]
|
| 552 |
-
|
| 553 |
-
# Get note origin assessment
|
| 554 |
-
if 'note_origin' in request.form:
|
| 555 |
-
evaluation_data['note_origin'] = request.form['note_origin']
|
| 556 |
-
log_error(f"Note origin: {evaluation_data['note_origin']}")
|
| 557 |
-
|
| 558 |
-
# Save evaluation data
|
| 559 |
-
save_result = save_evaluation(evaluation_data)
|
| 560 |
-
|
| 561 |
-
if save_result:
|
| 562 |
-
flash("Evaluation saved successfully!")
|
| 563 |
-
|
| 564 |
-
# Move to next document
|
| 565 |
-
new_index = current_index + 1
|
| 566 |
-
session['current_document_index'] = new_index
|
| 567 |
-
print(f"DEBUG SUBMIT: Moved from document {current_index} to {new_index}")
|
| 568 |
-
log_error(f"SUBMIT: Moved from document {current_index} to {new_index}")
|
| 569 |
-
|
| 570 |
-
# Check if all documents have been processed
|
| 571 |
-
if session['current_document_index'] > len(all_documents):
|
| 572 |
-
flash("All documents have been evaluated. Thank you!")
|
| 573 |
-
return redirect(url_for('results'))
|
| 574 |
-
|
| 575 |
-
# Debug session state before redirect
|
| 576 |
-
final_session_index = session.get('current_document_index', 1)
|
| 577 |
-
print(f"DEBUG SUBMIT REDIRECT: final_session_index={final_session_index}")
|
| 578 |
-
|
| 579 |
-
# Redirect to next document
|
| 580 |
-
return redirect(url_for('evaluate'))
|
| 581 |
-
else:
|
| 582 |
-
flash("Error saving evaluation. Please try again.")
|
| 583 |
-
|
| 584 |
-
except Exception as e:
|
| 585 |
-
error_msg = f"Error processing evaluation: {str(e)}"
|
| 586 |
-
log_error(error_msg)
|
| 587 |
-
log_error(traceback.format_exc())
|
| 588 |
-
flash(error_msg)
|
| 589 |
-
|
| 590 |
-
# Handle GET request (display evaluation form)
|
| 591 |
-
try:
|
| 592 |
-
# Load all documents
|
| 593 |
-
all_documents = load_documents()
|
| 594 |
-
log_error(f"Loaded {len(all_documents)} total documents for GET")
|
| 595 |
|
| 596 |
-
|
| 597 |
-
|
| 598 |
-
|
| 599 |
-
|
|
|
|
| 600 |
|
| 601 |
-
|
| 602 |
-
|
| 603 |
-
|
| 604 |
-
# Check if we've reached the end
|
| 605 |
-
if current_index > len(all_documents):
|
| 606 |
-
flash("All documents have been processed in this session.")
|
| 607 |
return redirect(url_for('results'))
|
| 608 |
|
| 609 |
-
|
| 610 |
-
|
| 611 |
-
|
| 612 |
-
|
| 613 |
-
|
| 614 |
-
total_docs = len(all_documents)
|
| 615 |
-
current_progress = current_index - 1 # Convert to 0-based for progress calculation
|
| 616 |
-
progress = int((current_progress / total_docs) * 100) if total_docs > 0 else 0
|
| 617 |
-
|
| 618 |
-
log_error(f"Session Progress: {current_progress}/{total_docs} documents ({progress}%)")
|
| 619 |
-
|
| 620 |
-
# Render evaluation template
|
| 621 |
-
return render_template('evaluate.html',
|
| 622 |
-
evaluator_name=evaluator_name,
|
| 623 |
-
note=document.get('note', ''),
|
| 624 |
-
description=document.get('description', ''),
|
| 625 |
-
mrn=document.get('mrn', ''),
|
| 626 |
-
criteria=CRITERIA,
|
| 627 |
-
descriptions=CRITERIA_DESCRIPTIONS,
|
| 628 |
-
score_range=range(1, 6),
|
| 629 |
-
note_origins=NOTE_ORIGINS,
|
| 630 |
-
total_docs=total_docs,
|
| 631 |
-
evaluated_docs=current_progress,
|
| 632 |
-
progress=progress,
|
| 633 |
-
current_note_number=current_index)
|
| 634 |
|
| 635 |
-
|
| 636 |
-
|
| 637 |
-
|
| 638 |
-
flash(
|
| 639 |
-
return redirect(url_for('
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 640 |
|
| 641 |
@app.route('/jump', methods=['POST'])
|
| 642 |
def jump_to_document():
|
|
@@ -948,6 +782,32 @@ def get_stored_evaluator_name():
|
|
| 948 |
log_error(f"Error retrieving evaluator name: {str(e)}")
|
| 949 |
return None
|
| 950 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 951 |
if __name__ == '__main__':
|
| 952 |
print("\n===== Application Startup at", datetime.now().strftime('%Y-%m-%d %H:%M:%S'), "=====\n")
|
| 953 |
|
|
|
|
| 418 |
# Create sessions directory if it doesn't exist
|
| 419 |
os.makedirs(os.path.join(DATA_DIR, 'sessions'), exist_ok=True)
|
| 420 |
|
| 421 |
+
# Initialize current document index from file
|
| 422 |
+
current_index = load_current_index(evaluator_name)
|
|
|
|
| 423 |
|
| 424 |
+
# Handle jump requests
|
| 425 |
jump_to = request.args.get('jump_to', type=int)
|
| 426 |
if jump_to is not None:
|
|
|
|
| 427 |
documents = load_documents()
|
| 428 |
+
if 1 <= jump_to <= len(documents):
|
| 429 |
+
current_index = jump_to
|
| 430 |
+
save_current_index(evaluator_name, current_index)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 431 |
|
| 432 |
+
# Handle form submissions
|
| 433 |
if request.method == 'POST':
|
| 434 |
+
action = request.form.get('action', 'submit')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 435 |
|
| 436 |
+
if action == 'skip':
|
| 437 |
+
current_index += 1
|
| 438 |
+
save_current_index(evaluator_name, current_index)
|
| 439 |
+
flash("Document skipped.")
|
| 440 |
+
return redirect(url_for('evaluate'))
|
| 441 |
|
| 442 |
+
elif action == 'stop_save':
|
| 443 |
+
# Handle save logic
|
|
|
|
|
|
|
|
|
|
|
|
|
| 444 |
return redirect(url_for('results'))
|
| 445 |
|
| 446 |
+
elif action == 'submit':
|
| 447 |
+
# Save evaluation logic
|
| 448 |
+
current_index += 1
|
| 449 |
+
save_current_index(evaluator_name, current_index)
|
| 450 |
+
flash("Evaluation saved successfully!")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 451 |
|
| 452 |
+
# Load current document
|
| 453 |
+
documents = load_documents()
|
| 454 |
+
if current_index > len(documents):
|
| 455 |
+
flash("All documents have been evaluated.")
|
| 456 |
+
return redirect(url_for('results'))
|
| 457 |
+
|
| 458 |
+
document = documents[current_index - 1]
|
| 459 |
+
|
| 460 |
+
# Render template with current_index
|
| 461 |
+
return render_template('evaluate.html',
|
| 462 |
+
current_note_number=current_index,
|
| 463 |
+
evaluator_name=evaluator_name,
|
| 464 |
+
note=document.get('note', ''),
|
| 465 |
+
description=document.get('description', ''),
|
| 466 |
+
mrn=document.get('mrn', ''),
|
| 467 |
+
criteria=CRITERIA,
|
| 468 |
+
descriptions=CRITERIA_DESCRIPTIONS,
|
| 469 |
+
score_range=range(1, 6),
|
| 470 |
+
note_origins=NOTE_ORIGINS,
|
| 471 |
+
total_docs=len(documents),
|
| 472 |
+
evaluated_docs=current_index - 1,
|
| 473 |
+
progress=int((current_index - 1) / len(documents) * 100) if len(documents) > 0 else 0)
|
| 474 |
|
| 475 |
@app.route('/jump', methods=['POST'])
|
| 476 |
def jump_to_document():
|
|
|
|
| 782 |
log_error(f"Error retrieving evaluator name: {str(e)}")
|
| 783 |
return None
|
| 784 |
|
| 785 |
+
# Add these new functions for progress tracking
|
| 786 |
+
def get_progress_file(evaluator_name):
|
| 787 |
+
"""Get path to progress file for an evaluator"""
|
| 788 |
+
return os.path.join(DATA_DIR, f'{evaluator_name}_progress.txt')
|
| 789 |
+
|
| 790 |
+
def save_current_index(evaluator_name, index):
|
| 791 |
+
"""Save current document index to file"""
|
| 792 |
+
try:
|
| 793 |
+
with open(get_progress_file(evaluator_name), 'w') as f:
|
| 794 |
+
f.write(str(index))
|
| 795 |
+
return True
|
| 796 |
+
except Exception as e:
|
| 797 |
+
log_error(f"Error saving progress: {str(e)}")
|
| 798 |
+
return False
|
| 799 |
+
|
| 800 |
+
def load_current_index(evaluator_name):
|
| 801 |
+
"""Load current document index from file"""
|
| 802 |
+
try:
|
| 803 |
+
if os.path.exists(get_progress_file(evaluator_name)):
|
| 804 |
+
with open(get_progress_file(evaluator_name), 'r') as f:
|
| 805 |
+
return int(f.read().strip())
|
| 806 |
+
return 1 # Start at 1 if no progress file
|
| 807 |
+
except Exception as e:
|
| 808 |
+
log_error(f"Error loading progress: {str(e)}")
|
| 809 |
+
return 1
|
| 810 |
+
|
| 811 |
if __name__ == '__main__':
|
| 812 |
print("\n===== Application Startup at", datetime.now().strftime('%Y-%m-%d %H:%M:%S'), "=====\n")
|
| 813 |
|
templates/evaluate.html
CHANGED
|
@@ -112,9 +112,19 @@
|
|
| 112 |
</div>
|
| 113 |
|
| 114 |
<div class="form-buttons">
|
| 115 |
-
<
|
| 116 |
-
|
| 117 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 118 |
</div>
|
| 119 |
</form>
|
| 120 |
|
|
|
|
| 112 |
</div>
|
| 113 |
|
| 114 |
<div class="form-buttons">
|
| 115 |
+
<form method="POST" action="{{ url_for('evaluate') }}">
|
| 116 |
+
<button type="submit" name="action" value="submit" class="submit-btn">Submit Evaluation</button>
|
| 117 |
+
</form>
|
| 118 |
+
|
| 119 |
+
<div class="action-buttons">
|
| 120 |
+
<form method="POST" action="{{ url_for('evaluate') }}" onsubmit="return confirm('Are you sure you want to skip this document?');">
|
| 121 |
+
<button type="submit" name="action" value="skip" class="skip-btn">Skip Document</button>
|
| 122 |
+
</form>
|
| 123 |
+
|
| 124 |
+
<form method="POST" action="{{ url_for('evaluate') }}">
|
| 125 |
+
<button type="submit" name="action" value="stop_save" class="stop-save-btn">Stop and Save Progress</button>
|
| 126 |
+
</form>
|
| 127 |
+
</div>
|
| 128 |
</div>
|
| 129 |
</form>
|
| 130 |
|