Spaces:
Sleeping
Sleeping
| # enhanced_verification_ui.py | |
| """ | |
| Enhanced Verification UI Components for Multi-Mode Verification. | |
| Provides interface components for mode selection, session resumption, | |
| and enhanced verification workflows across different modes. | |
| Requirements: 1.1, 1.2, 1.3, 1.4, 1.5 | |
| """ | |
| import gradio as gr | |
| from typing import List, Dict, Tuple, Optional, Any | |
| from dataclasses import dataclass | |
| from datetime import datetime | |
| import uuid | |
| from src.core.verification_models import ( | |
| EnhancedVerificationSession, | |
| VerificationRecord, | |
| TestMessage, | |
| TestDataset, | |
| ) | |
| from src.core.verification_store import JSONVerificationStore | |
| from src.core.test_datasets import TestDatasetManager | |
| from src.interface.enhanced_dataset_interface import EnhancedDatasetInterfaceController | |
| class ModeSelectionState: | |
| """State container for mode selection interface.""" | |
| current_mode: Optional[str] = None | |
| incomplete_sessions: List[EnhancedVerificationSession] = None | |
| selected_session: Optional[EnhancedVerificationSession] = None | |
| def __post_init__(self): | |
| if self.incomplete_sessions is None: | |
| self.incomplete_sessions = [] | |
| class EnhancedVerificationUIComponents: | |
| """Enhanced UI components for multi-mode verification.""" | |
| # Mode definitions with descriptions | |
| MODE_OPTIONS = { | |
| "enhanced_dataset": { | |
| "icon": "π", | |
| "title": "Enhanced Datasets", | |
| "description": "Use existing test datasets with editing capabilities. Add, modify, or delete test cases to customize datasets for specific testing scenarios.", | |
| "features": [ | |
| "Edit existing datasets", | |
| "Add new test cases", | |
| "Modify message text and classifications", | |
| "Delete test cases with confirmation", | |
| "Dataset versioning and backup" | |
| ] | |
| }, | |
| "manual_input": { | |
| "icon": "βοΈ", | |
| "title": "Manual Input", | |
| "description": "Manually enter individual messages for immediate testing. Perfect for exploring edge cases or testing specific scenarios in real-time.", | |
| "features": [ | |
| "Real-time message classification", | |
| "Immediate feedback collection", | |
| "Session results accumulation", | |
| "Quick testing of specific cases", | |
| "Export manual input results" | |
| ] | |
| }, | |
| "file_upload": { | |
| "icon": "π", | |
| "title": "File Upload", | |
| "description": "Upload CSV or XLSX files containing test messages for batch processing. Ideal for large-scale testing with pre-prepared datasets.", | |
| "features": [ | |
| "CSV and XLSX file support", | |
| "Batch processing with progress tracking", | |
| "Automated verification against expected results", | |
| "File format validation and error reporting", | |
| "Comprehensive export options" | |
| ] | |
| } | |
| } | |
| def create_mode_selection_interface() -> gr.Blocks: | |
| """ | |
| Create the main mode selection interface. | |
| Returns: | |
| Gradio Blocks component for mode selection | |
| """ | |
| with gr.Blocks() as mode_selection: | |
| # Header | |
| gr.Markdown("# π Enhanced Verification Modes") | |
| gr.Markdown("Choose your verification approach based on your testing needs and data source.") | |
| # Incomplete sessions section | |
| incomplete_sessions_section = gr.Row(visible=False) | |
| with incomplete_sessions_section: | |
| with gr.Column(): | |
| gr.Markdown("## π Resume Previous Sessions") | |
| gr.Markdown("You have incomplete verification sessions. You can resume where you left off or start a new session.") | |
| incomplete_sessions_display = gr.HTML( | |
| value="", | |
| label="Incomplete Sessions" | |
| ) | |
| with gr.Row(): | |
| resume_session_btn = gr.Button( | |
| "βΆοΈ Resume Selected Session", | |
| variant="primary", | |
| scale=2 | |
| ) | |
| clear_sessions_btn = gr.Button( | |
| "ποΈ Clear All Sessions", | |
| variant="secondary", | |
| scale=1 | |
| ) | |
| # Mode selection cards | |
| gr.Markdown("## π― Select Verification Mode") | |
| with gr.Row(): | |
| # Enhanced Dataset Mode | |
| with gr.Column(scale=1): | |
| mode_info = EnhancedVerificationUIComponents.MODE_OPTIONS["enhanced_dataset"] | |
| gr.Markdown(f"### {mode_info['icon']} {mode_info['title']}") | |
| gr.Markdown(mode_info["description"]) | |
| gr.Markdown("**Features:**") | |
| for feature in mode_info["features"]: | |
| gr.Markdown(f"β’ {feature}") | |
| enhanced_dataset_btn = gr.Button( | |
| f"{mode_info['icon']} Start Enhanced Dataset Mode", | |
| variant="primary", | |
| size="lg" | |
| ) | |
| # Manual Input Mode | |
| with gr.Column(scale=1): | |
| mode_info = EnhancedVerificationUIComponents.MODE_OPTIONS["manual_input"] | |
| gr.Markdown(f"### {mode_info['icon']} {mode_info['title']}") | |
| gr.Markdown(mode_info["description"]) | |
| gr.Markdown("**Features:**") | |
| for feature in mode_info["features"]: | |
| gr.Markdown(f"β’ {feature}") | |
| manual_input_btn = gr.Button( | |
| f"{mode_info['icon']} Start Manual Input Mode", | |
| variant="primary", | |
| size="lg" | |
| ) | |
| # File Upload Mode | |
| with gr.Column(scale=1): | |
| mode_info = EnhancedVerificationUIComponents.MODE_OPTIONS["file_upload"] | |
| gr.Markdown(f"### {mode_info['icon']} {mode_info['title']}") | |
| gr.Markdown(mode_info["description"]) | |
| gr.Markdown("**Features:**") | |
| for feature in mode_info["features"]: | |
| gr.Markdown(f"β’ {feature}") | |
| file_upload_btn = gr.Button( | |
| f"{mode_info['icon']} Start File Upload Mode", | |
| variant="primary", | |
| size="lg" | |
| ) | |
| # Progress preservation warning | |
| progress_warning = gr.Markdown( | |
| "", | |
| visible=False, | |
| label="Progress Warning" | |
| ) | |
| # Confirmation dialog for mode switching | |
| mode_switch_dialog = gr.Row(visible=False) | |
| with mode_switch_dialog: | |
| with gr.Column(): | |
| gr.Markdown("### β οΈ Switch Mode Confirmation") | |
| switch_warning_text = gr.Markdown( | |
| "You have unsaved progress in the current mode. What would you like to do?", | |
| label="Warning" | |
| ) | |
| with gr.Row(): | |
| save_and_switch_btn = gr.Button( | |
| "πΎ Save Progress & Switch", | |
| variant="primary", | |
| scale=2 | |
| ) | |
| discard_and_switch_btn = gr.Button( | |
| "ποΈ Discard & Switch", | |
| variant="secondary", | |
| scale=1 | |
| ) | |
| cancel_switch_btn = gr.Button( | |
| "β Cancel", | |
| scale=1 | |
| ) | |
| # Status message | |
| status_message = gr.Markdown( | |
| "", | |
| visible=True, | |
| label="Status" | |
| ) | |
| # Hidden state for tracking | |
| current_mode_state = gr.State(value=None) | |
| incomplete_sessions_state = gr.State(value=[]) | |
| selected_session_state = gr.State(value=None) | |
| pending_mode_switch = gr.State(value=None) | |
| return mode_selection | |
| def render_incomplete_sessions_display(sessions: List[EnhancedVerificationSession]) -> str: | |
| """ | |
| Render HTML display for incomplete sessions. | |
| Args: | |
| sessions: List of incomplete verification sessions | |
| Returns: | |
| HTML string for displaying incomplete sessions | |
| """ | |
| if not sessions: | |
| return "" | |
| html = """ | |
| <div style="font-family: system-ui; padding: 1em; background-color: #f9fafb; border-radius: 8px; border: 1px solid #e5e7eb;"> | |
| """ | |
| for session in sessions: | |
| mode_info = EnhancedVerificationUIComponents.MODE_OPTIONS.get( | |
| session.mode_type, | |
| {"icon": "β", "title": "Unknown Mode"} | |
| ) | |
| progress_pct = (session.verified_count / session.total_messages * 100) if session.total_messages > 0 else 0 | |
| accuracy = (session.correct_count / session.verified_count * 100) if session.verified_count > 0 else 0 | |
| # Format creation time | |
| time_ago = EnhancedVerificationUIComponents._format_time_ago(session.created_at) | |
| html += f""" | |
| <div style="margin-bottom: 1em; padding: 1em; background-color: white; border-radius: 6px; border: 1px solid #d1d5db; cursor: pointer;" | |
| onclick="this.style.backgroundColor='#eff6ff'; this.style.borderColor='#3b82f6';"> | |
| <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.5em;"> | |
| <h4 style="margin: 0; color: #1f2937;"> | |
| {mode_info['icon']} {mode_info['title']} - {session.dataset_name} | |
| </h4> | |
| <span style="font-size: 0.875em; color: #6b7280;">{time_ago}</span> | |
| </div> | |
| <div style="margin-bottom: 0.5em;"> | |
| <div style="display: flex; justify-content: space-between; margin-bottom: 0.25em;"> | |
| <span style="font-size: 0.875em; color: #374151;">Progress: {session.verified_count}/{session.total_messages}</span> | |
| <span style="font-size: 0.875em; color: #374151;">{progress_pct:.0f}%</span> | |
| </div> | |
| <div style="width: 100%; background-color: #e5e7eb; border-radius: 4px; height: 8px;"> | |
| <div style="width: {progress_pct}%; background-color: #3b82f6; border-radius: 4px; height: 8px;"></div> | |
| </div> | |
| </div> | |
| <div style="display: flex; gap: 1em; font-size: 0.875em; color: #6b7280;"> | |
| <span>β Correct: {session.correct_count}</span> | |
| <span>β Incorrect: {session.incorrect_count}</span> | |
| <span>π Accuracy: {accuracy:.1f}%</span> | |
| </div> | |
| <div style="margin-top: 0.5em; font-size: 0.75em; color: #9ca3af;"> | |
| Session ID: {session.session_id[:8]}... | |
| </div> | |
| </div> | |
| """ | |
| html += """ | |
| </div> | |
| <p style="font-size: 0.875em; color: #6b7280; margin-top: 0.5em;"> | |
| π‘ <strong>Tip:</strong> Click on a session above to select it, then click "Resume Selected Session" to continue where you left off. | |
| </p> | |
| """ | |
| return html | |
| def _format_time_ago(timestamp: datetime) -> str: | |
| """ | |
| Format timestamp as time ago string. | |
| Args: | |
| timestamp: Datetime to format | |
| Returns: | |
| Human-readable time ago string | |
| """ | |
| now = datetime.now() | |
| diff = now - timestamp | |
| if diff.days > 0: | |
| return f"{diff.days} day{'s' if diff.days != 1 else ''} ago" | |
| elif diff.seconds > 3600: | |
| hours = diff.seconds // 3600 | |
| return f"{hours} hour{'s' if hours != 1 else ''} ago" | |
| elif diff.seconds > 60: | |
| minutes = diff.seconds // 60 | |
| return f"{minutes} minute{'s' if minutes != 1 else ''} ago" | |
| else: | |
| return "Just now" | |
| def check_for_incomplete_sessions(store: JSONVerificationStore) -> Tuple[bool, List[EnhancedVerificationSession], str]: | |
| """ | |
| Check for incomplete sessions and return display information. | |
| Args: | |
| store: Verification data store | |
| Returns: | |
| Tuple of (has_incomplete, sessions_list, display_html) | |
| """ | |
| try: | |
| incomplete_sessions = store.get_incomplete_sessions() | |
| # Filter to only enhanced sessions for this interface | |
| enhanced_sessions = [ | |
| s for s in incomplete_sessions | |
| if isinstance(s, EnhancedVerificationSession) | |
| ] | |
| if enhanced_sessions: | |
| display_html = EnhancedVerificationUIComponents.render_incomplete_sessions_display(enhanced_sessions) | |
| return True, enhanced_sessions, display_html | |
| else: | |
| return False, [], "" | |
| except Exception as e: | |
| error_html = f""" | |
| <div style="padding: 1em; background-color: #fef2f2; border-left: 4px solid #dc2626; border-radius: 4px;"> | |
| <h4 style="color: #dc2626; margin-top: 0;">β Error Loading Sessions</h4> | |
| <p style="margin-bottom: 0;">Could not load incomplete sessions: {str(e)}</p> | |
| </div> | |
| """ | |
| return False, [], error_html | |
| def create_mode_switch_confirmation(current_mode: str, target_mode: str, has_progress: bool) -> Tuple[str, bool]: | |
| """ | |
| Create mode switch confirmation message. | |
| Args: | |
| current_mode: Current verification mode | |
| target_mode: Target verification mode | |
| has_progress: Whether there is unsaved progress | |
| Returns: | |
| Tuple of (warning_message, show_dialog) | |
| """ | |
| if not has_progress: | |
| return "", False | |
| current_info = EnhancedVerificationUIComponents.MODE_OPTIONS.get(current_mode, {"title": "Unknown"}) | |
| target_info = EnhancedVerificationUIComponents.MODE_OPTIONS.get(target_mode, {"title": "Unknown"}) | |
| warning_message = f""" | |
| You are currently in **{current_info['title']}** mode and have unsaved progress. | |
| Switching to **{target_info['title']}** mode will: | |
| - Save your current progress automatically | |
| - Switch to the new verification mode | |
| - Allow you to resume the current session later | |
| **What would you like to do?** | |
| """ | |
| return warning_message, True | |
| def create_enhanced_dataset_interface() -> gr.Blocks: | |
| """ | |
| Create enhanced dataset mode interface. | |
| Returns: | |
| Gradio Blocks component for enhanced dataset mode | |
| """ | |
| with gr.Blocks() as enhanced_dataset_interface: | |
| gr.Markdown("# π Enhanced Dataset Mode") | |
| gr.Markdown("Select and customize test datasets for verification. You can edit existing datasets or create new test cases.") | |
| # Back to mode selection | |
| back_to_modes_btn = gr.Button("β Back to Mode Selection", size="sm") | |
| # Application state | |
| current_dataset_state = gr.State(value=None) | |
| editing_mode_state = gr.State(value=False) | |
| selected_test_case_state = gr.State(value=None) | |
| dataset_manager_state = gr.State(value=None) | |
| # Dataset selection and editing interface | |
| with gr.Row(): | |
| with gr.Column(scale=2): | |
| gr.Markdown("## π Select Dataset") | |
| # Dataset selector | |
| dataset_selector = gr.Dropdown( | |
| choices=[], | |
| label="Available Datasets", | |
| info="Choose a dataset to verify or edit", | |
| interactive=True | |
| ) | |
| with gr.Row(): | |
| load_dataset_btn = gr.Button("π₯ Load Dataset", variant="primary", scale=2) | |
| edit_dataset_btn = gr.Button("βοΈ Edit Dataset", variant="secondary", scale=1) | |
| create_new_btn = gr.Button("β Create New", variant="secondary", scale=1) | |
| with gr.Column(scale=1): | |
| gr.Markdown("## π Dataset Information") | |
| dataset_info_display = gr.Markdown( | |
| "Select a dataset to view details", | |
| label="Dataset Details" | |
| ) | |
| # Dataset creation section (initially hidden) | |
| dataset_creation_section = gr.Row(visible=False) | |
| with dataset_creation_section: | |
| with gr.Column(): | |
| gr.Markdown("## β Create New Dataset") | |
| with gr.Row(): | |
| with gr.Column(scale=2): | |
| new_dataset_name = gr.Textbox( | |
| label="Dataset Name", | |
| placeholder="e.g., Custom Test Messages", | |
| interactive=True | |
| ) | |
| with gr.Column(scale=1): | |
| template_selector = gr.Dropdown( | |
| choices=[], | |
| label="Template (Optional)", | |
| info="Start with a template", | |
| interactive=True | |
| ) | |
| new_dataset_description = gr.Textbox( | |
| label="Dataset Description", | |
| placeholder="Describe the purpose and content of this dataset...", | |
| lines=2, | |
| interactive=True | |
| ) | |
| with gr.Row(): | |
| create_dataset_btn = gr.Button("β¨ Create Dataset", variant="primary", scale=2) | |
| cancel_create_btn = gr.Button("β Cancel", scale=1) | |
| # Dataset editing section (initially hidden) | |
| dataset_editing_section = gr.Row(visible=False) | |
| with dataset_editing_section: | |
| with gr.Column(): | |
| gr.Markdown("## βοΈ Edit Dataset") | |
| # Dataset metadata editing | |
| with gr.Row(): | |
| edit_dataset_name = gr.Textbox( | |
| label="Dataset Name", | |
| interactive=True | |
| ) | |
| edit_dataset_description = gr.Textbox( | |
| label="Dataset Description", | |
| lines=2, | |
| interactive=True | |
| ) | |
| # Test case list | |
| test_cases_display = gr.HTML( | |
| value="", | |
| label="Test Cases" | |
| ) | |
| # Add new test case | |
| gr.Markdown("### β Add New Test Case") | |
| with gr.Row(): | |
| with gr.Column(scale=3): | |
| new_message_text = gr.Textbox( | |
| label="Message Text", | |
| placeholder="Enter patient message...", | |
| lines=3, | |
| interactive=True | |
| ) | |
| with gr.Column(scale=1): | |
| new_classification = gr.Radio( | |
| choices=[ | |
| ("π’ GREEN - No Distress", "green"), | |
| ("π‘ YELLOW - Potential Distress", "yellow"), | |
| ("π΄ RED - Severe Distress", "red") | |
| ], | |
| label="Expected Classification", | |
| value="green", | |
| interactive=True | |
| ) | |
| with gr.Row(): | |
| add_test_case_btn = gr.Button("β Add Test Case", variant="primary", scale=2) | |
| save_dataset_btn = gr.Button("πΎ Save Dataset", variant="secondary", scale=1) | |
| cancel_edit_btn = gr.Button("β Cancel", scale=1) | |
| # Test case editing modal (initially hidden) | |
| test_case_edit_modal = gr.Row(visible=False) | |
| with test_case_edit_modal: | |
| with gr.Column(): | |
| gr.Markdown("### βοΈ Edit Test Case") | |
| edit_message_text = gr.Textbox( | |
| label="Message Text", | |
| lines=3, | |
| interactive=True | |
| ) | |
| edit_classification = gr.Radio( | |
| choices=[ | |
| ("π’ GREEN - No Distress", "green"), | |
| ("π‘ YELLOW - Potential Distress", "yellow"), | |
| ("π΄ RED - Severe Distress", "red") | |
| ], | |
| label="Expected Classification", | |
| interactive=True | |
| ) | |
| with gr.Row(): | |
| save_test_case_btn = gr.Button("πΎ Save Changes", variant="primary", scale=2) | |
| delete_test_case_btn = gr.Button("ποΈ Delete", variant="stop", scale=1) | |
| cancel_test_case_edit_btn = gr.Button("β Cancel", scale=1) | |
| # Verification interface (initially hidden) | |
| verification_section = gr.Row(visible=False) | |
| with verification_section: | |
| with gr.Column(): | |
| gr.Markdown("## π Dataset Verification") | |
| # Verification controls | |
| with gr.Row(): | |
| with gr.Column(scale=2): | |
| verifier_name_input = gr.Textbox( | |
| label="Verifier Name", | |
| placeholder="Enter your name...", | |
| interactive=True | |
| ) | |
| with gr.Column(scale=1): | |
| start_verification_btn = gr.Button( | |
| "π Start Verification", | |
| variant="primary", | |
| size="lg" | |
| ) | |
| # Progress display | |
| verification_progress = gr.Markdown( | |
| "Ready to start verification", | |
| label="Progress" | |
| ) | |
| # Message review area (initially hidden) | |
| message_review_area = gr.Row(visible=False) | |
| with message_review_area: | |
| with gr.Column(scale=2): | |
| # Current message display | |
| current_message_display = gr.Textbox( | |
| label="π Patient Message", | |
| interactive=False, | |
| lines=4 | |
| ) | |
| # Classification results | |
| classifier_decision_display = gr.Markdown( | |
| "π Loading...", | |
| label="π― Classifier Decision" | |
| ) | |
| classifier_confidence_display = gr.Markdown( | |
| "Loading...", | |
| label="π Confidence Level" | |
| ) | |
| classifier_indicators_display = gr.Markdown( | |
| "Loading...", | |
| label="π Detected Indicators" | |
| ) | |
| # Verification buttons | |
| with gr.Row(): | |
| correct_classification_btn = gr.Button( | |
| "β Correct", | |
| variant="primary", | |
| scale=1 | |
| ) | |
| incorrect_classification_btn = gr.Button( | |
| "β Incorrect", | |
| variant="stop", | |
| scale=1 | |
| ) | |
| # Correction section (initially hidden) | |
| correction_section = gr.Row(visible=False) | |
| with correction_section: | |
| correction_selector = gr.Radio( | |
| choices=[ | |
| ("π’ Should be GREEN - No Distress", "green"), | |
| ("π‘ Should be YELLOW - Potential Distress", "yellow"), | |
| ("π΄ Should be RED - Severe Distress", "red") | |
| ], | |
| label="Correct Classification", | |
| interactive=True | |
| ) | |
| correction_notes = gr.Textbox( | |
| label="Notes (Optional)", | |
| placeholder="Why is this incorrect?", | |
| lines=2, | |
| interactive=True | |
| ) | |
| submit_correction_btn = gr.Button("β Submit", variant="primary") | |
| with gr.Column(scale=1): | |
| # Session statistics | |
| gr.Markdown("### π Session Statistics") | |
| session_stats_display = gr.Markdown( | |
| """ | |
| **Messages Processed:** 0 | |
| **Correct Classifications:** 0 | |
| **Incorrect Classifications:** 0 | |
| **Accuracy:** 0% | |
| """, | |
| label="Statistics" | |
| ) | |
| # Export options | |
| gr.Markdown("### πΎ Export Options") | |
| with gr.Column(): | |
| export_csv_btn = gr.Button("π Export CSV", size="sm") | |
| export_json_btn = gr.Button("π Export JSON", size="sm") | |
| export_xlsx_btn = gr.Button("π Export XLSX", size="sm") | |
| # Status and error messages | |
| status_message = gr.Markdown("", visible=True) | |
| return enhanced_dataset_interface | |
| def create_manual_input_interface() -> gr.Blocks: | |
| """ | |
| Create manual input mode interface. | |
| Returns: | |
| Gradio Blocks component for manual input mode | |
| """ | |
| with gr.Blocks() as manual_input_interface: | |
| gr.Markdown("# βοΈ Manual Input Mode") | |
| gr.Markdown("Enter individual messages for immediate classification and verification. Perfect for testing specific scenarios.") | |
| # Back to mode selection | |
| back_to_modes_btn = gr.Button("β Back to Mode Selection", size="sm") | |
| with gr.Row(): | |
| with gr.Column(scale=2): | |
| # Message input area | |
| gr.Markdown("## π Enter Patient Message") | |
| message_input = gr.Textbox( | |
| label="Patient Message", | |
| placeholder="Type or paste a patient message here...", | |
| lines=6, | |
| max_lines=10 | |
| ) | |
| classify_btn = gr.Button( | |
| "π Classify Message", | |
| variant="primary", | |
| size="lg" | |
| ) | |
| # Classification results (initially hidden) | |
| classification_results = gr.Row(visible=False) | |
| with classification_results: | |
| with gr.Column(): | |
| gr.Markdown("### π― Classification Results") | |
| decision_display = gr.Markdown("", label="Decision") | |
| confidence_display = gr.Markdown("", label="Confidence") | |
| indicators_display = gr.Markdown("", label="Indicators") | |
| # Verification buttons | |
| with gr.Row(): | |
| correct_btn = gr.Button("β Correct", variant="primary", scale=1) | |
| incorrect_btn = gr.Button("β Incorrect", variant="stop", scale=1) | |
| # Correction selector (initially hidden) | |
| correction_section = gr.Row(visible=False) | |
| with correction_section: | |
| correction_selector = gr.Radio( | |
| choices=[ | |
| ("π’ Should be GREEN - No Distress", "green"), | |
| ("π‘ Should be YELLOW - Potential Distress", "yellow"), | |
| ("π΄ Should be RED - Severe Distress", "red") | |
| ], | |
| label="Correct Classification" | |
| ) | |
| notes_input = gr.Textbox( | |
| label="Notes (Optional)", | |
| placeholder="Why is this incorrect?", | |
| lines=2 | |
| ) | |
| submit_correction_btn = gr.Button("β Submit", variant="primary") | |
| with gr.Column(scale=1): | |
| # Session statistics | |
| gr.Markdown("## π Session Statistics") | |
| session_stats = gr.Markdown( | |
| """ | |
| **Messages Processed:** 0 | |
| **Correct Classifications:** 0 | |
| **Incorrect Classifications:** 0 | |
| **Accuracy:** 0% | |
| """, | |
| label="Statistics" | |
| ) | |
| # Recent results | |
| gr.Markdown("## π Recent Results") | |
| recent_results = gr.HTML( | |
| value="<p>No messages processed yet.</p>", | |
| label="Recent Results" | |
| ) | |
| # Export options | |
| gr.Markdown("## πΎ Export Results") | |
| with gr.Column(): | |
| export_csv_btn = gr.Button("π Export CSV", size="sm") | |
| export_json_btn = gr.Button("π Export JSON", size="sm") | |
| clear_session_btn = gr.Button("ποΈ Clear Session", size="sm") | |
| # Status messages | |
| status_message = gr.Markdown("", visible=True) | |
| return manual_input_interface | |
| def create_file_upload_interface() -> gr.Blocks: | |
| """ | |
| Create file upload mode interface. | |
| Returns: | |
| Gradio Blocks component for file upload mode | |
| """ | |
| with gr.Blocks() as file_upload_interface: | |
| gr.Markdown("# π File Upload Mode") | |
| gr.Markdown("Upload CSV or XLSX files containing test messages for batch processing and verification.") | |
| # Back to mode selection | |
| back_to_modes_btn = gr.Button("β Back to Mode Selection", size="sm") | |
| with gr.Row(): | |
| with gr.Column(scale=2): | |
| # File upload area | |
| gr.Markdown("## π€ Upload Test File") | |
| file_upload = gr.File( | |
| label="Select CSV or XLSX File", | |
| file_types=[".csv", ".xlsx"], | |
| file_count="single" | |
| ) | |
| # Format requirements | |
| gr.Markdown(""" | |
| **Required Columns:** | |
| - `message` or `text`: Patient message text | |
| - `expected_classification` or `classification`: Expected result (GREEN, YELLOW, RED) | |
| **Supported Formats:** | |
| - CSV files (comma, semicolon, or tab delimited) | |
| - XLSX files (first worksheet only) | |
| """) | |
| # Template download | |
| with gr.Row(): | |
| download_csv_template_btn = gr.Button("π Download CSV Template", size="sm") | |
| download_xlsx_template_btn = gr.Button("π Download XLSX Template", size="sm") | |
| # File validation results (initially hidden) | |
| validation_results = gr.Row(visible=False) | |
| with validation_results: | |
| with gr.Column(): | |
| gr.Markdown("### β File Validation Results") | |
| validation_summary = gr.Markdown("", label="Summary") | |
| file_preview = gr.HTML("", label="Preview") | |
| start_processing_btn = gr.Button( | |
| "π Start Batch Processing", | |
| variant="primary", | |
| size="lg" | |
| ) | |
| with gr.Column(scale=1): | |
| # Processing status | |
| gr.Markdown("## π Processing Status") | |
| processing_stats = gr.Markdown( | |
| """ | |
| **File:** Not uploaded | |
| **Total Messages:** 0 | |
| **Processed:** 0 | |
| **Accuracy:** 0% | |
| """, | |
| label="Status" | |
| ) | |
| # Progress bar | |
| progress_bar = gr.HTML( | |
| value="", | |
| label="Progress" | |
| ) | |
| # Batch results | |
| gr.Markdown("## π Batch Results") | |
| batch_results = gr.HTML( | |
| value="<p>No file processed yet.</p>", | |
| label="Results" | |
| ) | |
| # Export options | |
| gr.Markdown("## πΎ Export Results") | |
| with gr.Column(): | |
| export_detailed_csv_btn = gr.Button("π Export Detailed CSV", size="sm") | |
| export_summary_btn = gr.Button("π Export Summary", size="sm") | |
| export_errors_btn = gr.Button("β οΈ Export Errors", size="sm") | |
| # Status messages | |
| status_message = gr.Markdown("", visible=True) | |
| return file_upload_interface | |
| def create_enhanced_dataset_interface_with_handlers() -> gr.Blocks: | |
| """ | |
| Create enhanced dataset mode interface with complete event handlers. | |
| Returns: | |
| Gradio Blocks component for enhanced dataset mode with functionality | |
| """ | |
| # Initialize controller | |
| controller = EnhancedDatasetInterfaceController() | |
| with gr.Blocks() as enhanced_dataset_interface: | |
| gr.Markdown("# π Enhanced Dataset Mode") | |
| gr.Markdown("Select and customize test datasets for verification. You can edit existing datasets or create new test cases.") | |
| # Status and error messages | |
| status_message = gr.Markdown("", visible=True) | |
| return enhanced_dataset_interface | |
| def create_enhanced_verification_app() -> gr.Blocks: | |
| """ | |
| Create the complete enhanced verification application. | |
| Returns: | |
| Gradio Blocks application with mode selection and all verification modes | |
| """ | |
| # Initialize store | |
| store = JSONVerificationStore() | |
| with gr.Blocks(title="Enhanced Verification Modes") as app: | |
| # Application state | |
| current_mode = gr.State(value=None) | |
| current_session = gr.State(value=None) | |
| # Mode selection interface | |
| mode_selection = EnhancedVerificationUIComponents.create_mode_selection_interface() | |
| # Individual mode interfaces (initially hidden) | |
| enhanced_dataset_interface = gr.Row(visible=False) | |
| with enhanced_dataset_interface: | |
| enhanced_dataset_ui = EnhancedVerificationUIComponents.create_enhanced_dataset_interface() | |
| manual_input_interface = gr.Row(visible=False) | |
| with manual_input_interface: | |
| manual_input_ui = EnhancedVerificationUIComponents.create_manual_input_interface() | |
| file_upload_interface = gr.Row(visible=False) | |
| with file_upload_interface: | |
| file_upload_ui = EnhancedVerificationUIComponents.create_file_upload_interface() | |
| # Event handlers for mode selection | |
| def initialize_app(): | |
| """Initialize the application and check for incomplete sessions.""" | |
| has_incomplete, sessions, display_html = EnhancedVerificationUIComponents.check_for_incomplete_sessions(store) | |
| if has_incomplete: | |
| return ( | |
| gr.Row(visible=True), # Show incomplete sessions section | |
| display_html, # Display sessions | |
| sessions, # Store sessions in state | |
| "β¨ Welcome back! You have incomplete sessions." | |
| ) | |
| else: | |
| return ( | |
| gr.Row(visible=False), # Hide incomplete sessions section | |
| "", # Empty display | |
| [], # Empty sessions list | |
| "β¨ Welcome to Enhanced Verification Modes! Choose a mode to get started." | |
| ) | |
| def switch_to_mode(mode_type: str, current_mode_val: str, current_session_val: EnhancedVerificationSession): | |
| """Switch to a specific verification mode.""" | |
| # Check if we need to show progress preservation warning | |
| has_progress = (current_session_val is not None and | |
| not current_session_val.is_complete and | |
| current_session_val.verified_count > 0) | |
| if has_progress and current_mode_val != mode_type: | |
| warning_msg, show_dialog = EnhancedVerificationUIComponents.create_mode_switch_confirmation( | |
| current_mode_val, mode_type, has_progress | |
| ) | |
| return ( | |
| gr.Row(visible=True), # Show confirmation dialog | |
| warning_msg, # Warning message | |
| mode_type, # Store pending mode switch | |
| current_mode_val, # Keep current mode | |
| current_session_val, # Keep current session | |
| f"β οΈ Confirm mode switch to {EnhancedVerificationUIComponents.MODE_OPTIONS[mode_type]['title']}" | |
| ) | |
| else: | |
| # Direct switch | |
| return perform_mode_switch(mode_type, current_session_val) | |
| def perform_mode_switch(mode_type: str, session_to_save: EnhancedVerificationSession = None): | |
| """Perform the actual mode switch.""" | |
| # Save current session if exists | |
| if session_to_save and not session_to_save.is_complete: | |
| store.save_session(session_to_save) | |
| # Hide all interfaces | |
| interfaces_visibility = [gr.Row(visible=False)] * 4 # mode_selection, enhanced_dataset, manual_input, file_upload | |
| # Show selected interface | |
| if mode_type == "enhanced_dataset": | |
| interfaces_visibility[1] = gr.Row(visible=True) | |
| elif mode_type == "manual_input": | |
| interfaces_visibility[2] = gr.Row(visible=True) | |
| elif mode_type == "file_upload": | |
| interfaces_visibility[3] = gr.Row(visible=True) | |
| else: | |
| interfaces_visibility[0] = gr.Row(visible=True) # Default to mode selection | |
| return ( | |
| *interfaces_visibility, | |
| gr.Row(visible=False), # Hide confirmation dialog | |
| "", # Clear warning message | |
| None, # Clear pending mode switch | |
| mode_type, # Set current mode | |
| None, # Clear current session (will be set by mode interface) | |
| f"β Switched to {EnhancedVerificationUIComponents.MODE_OPTIONS.get(mode_type, {}).get('title', 'Unknown')} mode" | |
| ) | |
| # Initialize app on load | |
| app.load( | |
| initialize_app, | |
| outputs=[ | |
| # These would be bound to actual components in the full implementation | |
| # For now, returning placeholder values | |
| ] | |
| ) | |
| return app | |
| with gr.Blocks() as enhanced_dataset_interface: | |
| gr.Markdown("# π Enhanced Dataset Mode") | |
| gr.Markdown("Select and customize test datasets for verification. You can edit existing datasets or create new test cases.") | |
| # Back to mode selection | |
| back_to_modes_btn = gr.Button("β Back to Mode Selection", size="sm") | |
| # Application state | |
| current_dataset_state = gr.State(value=None) | |
| editing_mode_state = gr.State(value=False) | |
| selected_test_case_state = gr.State(value=None) | |
| verification_session_state = gr.State(value=None) | |
| # Dataset selection and editing interface | |
| with gr.Row(): | |
| with gr.Column(scale=2): | |
| gr.Markdown("## π Select Dataset") | |
| # Dataset selector | |
| dataset_selector = gr.Dropdown( | |
| choices=[], | |
| label="Available Datasets", | |
| info="Choose a dataset to verify or edit", | |
| interactive=True | |
| ) | |
| with gr.Row(): | |
| load_dataset_btn = gr.Button("π₯ Load Dataset", variant="primary", scale=2) | |
| edit_dataset_btn = gr.Button("βοΈ Edit Dataset", variant="secondary", scale=1) | |
| create_new_btn = gr.Button("β Create New", variant="secondary", scale=1) | |
| with gr.Column(scale=1): | |
| gr.Markdown("## π Dataset Information") | |
| dataset_info_display = gr.Markdown( | |
| "Select a dataset to view details", | |
| label="Dataset Details" | |
| ) | |
| # Dataset creation section (initially hidden) | |
| dataset_creation_section = gr.Row(visible=False) | |
| with dataset_creation_section: | |
| with gr.Column(): | |
| gr.Markdown("## β Create New Dataset") | |
| with gr.Row(): | |
| with gr.Column(scale=2): | |
| new_dataset_name = gr.Textbox( | |
| label="Dataset Name", | |
| placeholder="e.g., Custom Test Messages", | |
| interactive=True | |
| ) | |
| with gr.Column(scale=1): | |
| template_selector = gr.Dropdown( | |
| choices=[], | |
| label="Template (Optional)", | |
| info="Start with a template", | |
| interactive=True | |
| ) | |
| new_dataset_description = gr.Textbox( | |
| label="Dataset Description", | |
| placeholder="Describe the purpose and content of this dataset...", | |
| lines=2, | |
| interactive=True | |
| ) | |
| with gr.Row(): | |
| create_dataset_btn = gr.Button("β¨ Create Dataset", variant="primary", scale=2) | |
| cancel_create_btn = gr.Button("β Cancel", scale=1) | |
| # Dataset editing section (initially hidden) | |
| dataset_editing_section = gr.Row(visible=False) | |
| with dataset_editing_section: | |
| with gr.Column(): | |
| gr.Markdown("## βοΈ Edit Dataset") | |
| # Dataset metadata editing | |
| with gr.Row(): | |
| edit_dataset_name = gr.Textbox( | |
| label="Dataset Name", | |
| interactive=True | |
| ) | |
| edit_dataset_description = gr.Textbox( | |
| label="Dataset Description", | |
| lines=2, | |
| interactive=True | |
| ) | |
| # Test case list | |
| test_cases_display = gr.HTML( | |
| value="", | |
| label="Test Cases" | |
| ) | |
| # Add new test case | |
| gr.Markdown("### β Add New Test Case") | |
| with gr.Row(): | |
| with gr.Column(scale=3): | |
| new_message_text = gr.Textbox( | |
| label="Message Text", | |
| placeholder="Enter patient message...", | |
| lines=3, | |
| interactive=True | |
| ) | |
| with gr.Column(scale=1): | |
| new_classification = gr.Radio( | |
| choices=[ | |
| ("π’ GREEN - No Distress", "green"), | |
| ("π‘ YELLOW - Potential Distress", "yellow"), | |
| ("π΄ RED - Severe Distress", "red") | |
| ], | |
| label="Expected Classification", | |
| value="green", | |
| interactive=True | |
| ) | |
| with gr.Row(): | |
| add_test_case_btn = gr.Button("β Add Test Case", variant="primary", scale=2) | |
| save_dataset_btn = gr.Button("πΎ Save Dataset", variant="secondary", scale=1) | |
| cancel_edit_btn = gr.Button("β Cancel", scale=1) | |
| # Verification interface (initially hidden) | |
| verification_section = gr.Row(visible=False) | |
| with verification_section: | |
| with gr.Column(): | |
| gr.Markdown("## π Dataset Verification") | |
| # Verification controls | |
| with gr.Row(): | |
| with gr.Column(scale=2): | |
| verifier_name_input = gr.Textbox( | |
| label="Verifier Name", | |
| placeholder="Enter your name...", | |
| interactive=True | |
| ) | |
| with gr.Column(scale=1): | |
| start_verification_btn = gr.Button( | |
| "π Start Verification", | |
| variant="primary", | |
| size="lg" | |
| ) | |
| # Progress display | |
| verification_progress = gr.Markdown( | |
| "Ready to start verification", | |
| label="Progress" | |
| ) | |
| # Message review area (initially hidden) | |
| message_review_area = gr.Row(visible=False) | |
| with message_review_area: | |
| with gr.Column(scale=2): | |
| # Current message display | |
| current_message_display = gr.Textbox( | |
| label="π Patient Message", | |
| interactive=False, | |
| lines=4 | |
| ) | |
| # Classification results | |
| classifier_decision_display = gr.Markdown( | |
| "π Loading...", | |
| label="π― Classifier Decision" | |
| ) | |
| classifier_confidence_display = gr.Markdown( | |
| "Loading...", | |
| label="π Confidence Level" | |
| ) | |
| classifier_indicators_display = gr.Markdown( | |
| "Loading...", | |
| label="π Detected Indicators" | |
| ) | |
| # Verification buttons | |
| with gr.Row(): | |
| correct_classification_btn = gr.Button( | |
| "β Correct", | |
| variant="primary", | |
| scale=1 | |
| ) | |
| incorrect_classification_btn = gr.Button( | |
| "β Incorrect", | |
| variant="stop", | |
| scale=1 | |
| ) | |
| # Correction section (initially hidden) | |
| correction_section = gr.Row(visible=False) | |
| with correction_section: | |
| correction_selector = gr.Radio( | |
| choices=[ | |
| ("π’ Should be GREEN - No Distress", "green"), | |
| ("π‘ Should be YELLOW - Potential Distress", "yellow"), | |
| ("π΄ Should be RED - Severe Distress", "red") | |
| ], | |
| label="Correct Classification", | |
| interactive=True | |
| ) | |
| correction_notes = gr.Textbox( | |
| label="Notes (Optional)", | |
| placeholder="Why is this incorrect?", | |
| lines=2, | |
| interactive=True | |
| ) | |
| submit_correction_btn = gr.Button("β Submit", variant="primary") | |
| with gr.Column(scale=1): | |
| # Session statistics | |
| gr.Markdown("### π Session Statistics") | |
| session_stats_display = gr.Markdown( | |
| """ | |
| **Messages Processed:** 0 | |
| **Correct Classifications:** 0 | |
| **Incorrect Classifications:** 0 | |
| **Accuracy:** 0% | |
| """, | |
| label="Statistics" | |
| ) | |
| # Export options | |
| gr.Markdown("### πΎ Export Options") | |
| with gr.Column(): | |
| export_csv_btn = gr.Button("π Export CSV", size="sm") | |
| export_json_btn = gr.Button("π Export JSON", size="sm") | |
| export_xlsx_btn = gr.Button("π Export XLSX", size="sm") | |
| # Status and error messages | |
| status_message = gr.Markdown("", visible=True) | |
| # Event handlers | |
| def initialize_interface(): | |
| """Initialize the interface with datasets and templates.""" | |
| dataset_choices, dataset_info, status_msg, templates = controller.initialize_interface() | |
| template_choices = [ | |
| f"{t['name']} - {t['description']}" | |
| for t in templates | |
| ] | |
| return ( | |
| dataset_choices, # dataset_selector choices | |
| dataset_info, # dataset_info_display | |
| status_msg, # status_message | |
| template_choices # template_selector choices | |
| ) | |
| def on_dataset_selection_change(dataset_selection): | |
| """Handle dataset selection change.""" | |
| dataset_info, dataset_obj = controller.get_dataset_info(dataset_selection) | |
| return ( | |
| dataset_info, # dataset_info_display | |
| dataset_obj # current_dataset_state | |
| ) | |
| def on_load_dataset(current_dataset): | |
| """Handle load dataset for verification.""" | |
| if not current_dataset: | |
| return ( | |
| gr.Row(visible=False), # verification_section | |
| "β No dataset selected" # status_message | |
| ) | |
| return ( | |
| gr.Row(visible=True), # verification_section | |
| f"β Dataset '{current_dataset.name}' loaded for verification" # status_message | |
| ) | |
| def on_edit_dataset(current_dataset): | |
| """Handle edit dataset.""" | |
| if not current_dataset: | |
| return ( | |
| gr.Row(visible=False), # dataset_editing_section | |
| "", # edit_dataset_name | |
| "", # edit_dataset_description | |
| "", # test_cases_display | |
| "β No dataset selected" # status_message | |
| ) | |
| test_cases_html = controller.render_test_cases_display(current_dataset) | |
| return ( | |
| gr.Row(visible=True), # dataset_editing_section | |
| current_dataset.name, # edit_dataset_name | |
| current_dataset.description, # edit_dataset_description | |
| test_cases_html, # test_cases_display | |
| f"β Editing dataset '{current_dataset.name}'" # status_message | |
| ) | |
| def on_create_new(): | |
| """Handle create new dataset.""" | |
| return ( | |
| gr.Row(visible=True), # dataset_creation_section | |
| "β¨ Create a new dataset" # status_message | |
| ) | |
| def on_create_dataset(name, description, template_selection): | |
| """Handle dataset creation.""" | |
| # Parse template type from selection | |
| template_type = None | |
| if template_selection: | |
| # Extract template type from selection string | |
| template_mapping = { | |
| "π Empty Dataset": "empty", | |
| "π― Sample Mixed Dataset": "sample_mixed", | |
| "π’ Custom Green Messages": "custom_green", | |
| "π‘ Custom Yellow Messages": "custom_yellow", | |
| "π΄ Custom Red Messages": "custom_red" | |
| } | |
| for key, value in template_mapping.items(): | |
| if template_selection.startswith(key): | |
| template_type = value | |
| break | |
| success, message, dataset = controller.create_new_dataset(name, description, template_type) | |
| if success: | |
| # Refresh dataset list | |
| dataset_choices, _, _, _ = controller.initialize_interface() | |
| return ( | |
| gr.Row(visible=False), # dataset_creation_section | |
| dataset_choices, # dataset_selector choices | |
| dataset, # current_dataset_state | |
| message # status_message | |
| ) | |
| else: | |
| return ( | |
| gr.Row(visible=True), # dataset_creation_section (keep visible) | |
| gr.Dropdown(choices=[]), # dataset_selector (no change) | |
| None, # current_dataset_state | |
| message # status_message | |
| ) | |
| def on_add_test_case(current_dataset, message_text, classification): | |
| """Handle adding new test case.""" | |
| if not current_dataset: | |
| return ( | |
| None, # current_dataset_state | |
| "", # test_cases_display | |
| "", # new_message_text (clear) | |
| "β No dataset selected" # status_message | |
| ) | |
| success, message, updated_dataset = controller.add_test_case( | |
| current_dataset, message_text, classification | |
| ) | |
| if success: | |
| test_cases_html = controller.render_test_cases_display(updated_dataset) | |
| return ( | |
| updated_dataset, # current_dataset_state | |
| test_cases_html, # test_cases_display | |
| "", # new_message_text (clear) | |
| message # status_message | |
| ) | |
| else: | |
| return ( | |
| current_dataset, # current_dataset_state (no change) | |
| gr.HTML(value=""), # test_cases_display (no change) | |
| message_text, # new_message_text (keep) | |
| message # status_message | |
| ) | |
| def on_save_dataset(current_dataset): | |
| """Handle saving dataset.""" | |
| if not current_dataset: | |
| return "β No dataset to save" | |
| success, message = controller.save_dataset(current_dataset) | |
| return message | |
| def on_start_verification(current_dataset, verifier_name): | |
| """Handle starting verification session.""" | |
| if not current_dataset: | |
| return ( | |
| None, # verification_session_state | |
| gr.Row(visible=False), # message_review_area | |
| "β No dataset selected" # status_message | |
| ) | |
| success, message, session = controller.start_verification_session( | |
| current_dataset, verifier_name | |
| ) | |
| if success: | |
| # Load first message | |
| current_message, classification_result = controller.get_current_message_for_verification() | |
| if current_message: | |
| # Format classification results | |
| decision_badge = f"π― {classification_result.get('decision', 'Unknown').upper()}" | |
| confidence_text = f"π {classification_result.get('confidence', 0) * 100:.1f}% confident" | |
| indicators_text = "π " + ", ".join(classification_result.get('indicators', ['No indicators'])) | |
| return ( | |
| session, # verification_session_state | |
| gr.Row(visible=True), # message_review_area | |
| current_message.text, # current_message_display | |
| decision_badge, # classifier_decision_display | |
| confidence_text, # classifier_confidence_display | |
| indicators_text, # classifier_indicators_display | |
| f"Progress: 1 of {len(current_dataset.messages)} messages", # verification_progress | |
| message # status_message | |
| ) | |
| else: | |
| return ( | |
| session, # verification_session_state | |
| gr.Row(visible=False), # message_review_area | |
| "", # current_message_display | |
| "", # classifier_decision_display | |
| "", # classifier_confidence_display | |
| "", # classifier_indicators_display | |
| "No messages to verify", # verification_progress | |
| "β No messages in dataset" # status_message | |
| ) | |
| else: | |
| return ( | |
| None, # verification_session_state | |
| gr.Row(visible=False), # message_review_area | |
| "", # current_message_display | |
| "", # classifier_decision_display | |
| "", # classifier_confidence_display | |
| "", # classifier_indicators_display | |
| "", # verification_progress | |
| message # status_message | |
| ) | |
| def on_correct_classification(): | |
| """Handle correct classification feedback.""" | |
| success, message, stats = controller.submit_verification_feedback(True) | |
| if success and not stats.get('is_complete', False): | |
| # Load next message | |
| current_message, classification_result = controller.get_current_message_for_verification() | |
| if current_message: | |
| decision_badge = f"π― {classification_result.get('decision', 'Unknown').upper()}" | |
| confidence_text = f"π {classification_result.get('confidence', 0) * 100:.1f}% confident" | |
| indicators_text = "π " + ", ".join(classification_result.get('indicators', ['No indicators'])) | |
| stats_text = f""" | |
| **Messages Processed:** {stats['processed']} | |
| **Correct Classifications:** {stats['correct']} | |
| **Incorrect Classifications:** {stats['incorrect']} | |
| **Accuracy:** {stats['accuracy']:.1f}% | |
| """ | |
| return ( | |
| current_message.text, # current_message_display | |
| decision_badge, # classifier_decision_display | |
| confidence_text, # classifier_confidence_display | |
| indicators_text, # classifier_indicators_display | |
| f"Progress: {stats['processed'] + 1} of {stats['total']} messages", # verification_progress | |
| stats_text, # session_stats_display | |
| gr.Row(visible=False), # correction_section | |
| message # status_message | |
| ) | |
| else: | |
| # Session complete | |
| stats_text = f""" | |
| **Session Complete!** | |
| **Messages Processed:** {stats['processed']} | |
| **Correct Classifications:** {stats['correct']} | |
| **Incorrect Classifications:** {stats['incorrect']} | |
| **Final Accuracy:** {stats['accuracy']:.1f}% | |
| """ | |
| return ( | |
| "Session completed!", # current_message_display | |
| "β All messages verified", # classifier_decision_display | |
| "", # classifier_confidence_display | |
| "", # classifier_indicators_display | |
| "β Verification complete", # verification_progress | |
| stats_text, # session_stats_display | |
| gr.Row(visible=False), # correction_section | |
| message # status_message | |
| ) | |
| else: | |
| return ( | |
| gr.Textbox(value=""), # current_message_display (no change) | |
| gr.Markdown(value=""), # classifier_decision_display (no change) | |
| gr.Markdown(value=""), # classifier_confidence_display (no change) | |
| gr.Markdown(value=""), # classifier_indicators_display (no change) | |
| gr.Markdown(value=""), # verification_progress (no change) | |
| gr.Markdown(value=""), # session_stats_display (no change) | |
| gr.Row(visible=False), # correction_section | |
| message # status_message | |
| ) | |
| def on_incorrect_classification(): | |
| """Handle incorrect classification - show correction options.""" | |
| return ( | |
| gr.Row(visible=True), # correction_section | |
| "Please select the correct classification" # status_message | |
| ) | |
| def on_submit_correction(correction, notes): | |
| """Handle correction submission.""" | |
| success, message, stats = controller.submit_verification_feedback( | |
| False, correction, notes | |
| ) | |
| if success and not stats.get('is_complete', False): | |
| # Load next message | |
| current_message, classification_result = controller.get_current_message_for_verification() | |
| if current_message: | |
| decision_badge = f"π― {classification_result.get('decision', 'Unknown').upper()}" | |
| confidence_text = f"π {classification_result.get('confidence', 0) * 100:.1f}% confident" | |
| indicators_text = "π " + ", ".join(classification_result.get('indicators', ['No indicators'])) | |
| stats_text = f""" | |
| **Messages Processed:** {stats['processed']} | |
| **Correct Classifications:** {stats['correct']} | |
| **Incorrect Classifications:** {stats['incorrect']} | |
| **Accuracy:** {stats['accuracy']:.1f}% | |
| """ | |
| return ( | |
| current_message.text, # current_message_display | |
| decision_badge, # classifier_decision_display | |
| confidence_text, # classifier_confidence_display | |
| indicators_text, # classifier_indicators_display | |
| f"Progress: {stats['processed'] + 1} of {stats['total']} messages", # verification_progress | |
| stats_text, # session_stats_display | |
| gr.Row(visible=False), # correction_section | |
| "", # correction_notes (clear) | |
| message # status_message | |
| ) | |
| else: | |
| # Session complete | |
| stats_text = f""" | |
| **Session Complete!** | |
| **Messages Processed:** {stats['processed']} | |
| **Correct Classifications:** {stats['correct']} | |
| **Incorrect Classifications:** {stats['incorrect']} | |
| **Final Accuracy:** {stats['accuracy']:.1f}% | |
| """ | |
| return ( | |
| "Session completed!", # current_message_display | |
| "β All messages verified", # classifier_decision_display | |
| "", # classifier_confidence_display | |
| "", # classifier_indicators_display | |
| "β Verification complete", # verification_progress | |
| stats_text, # session_stats_display | |
| gr.Row(visible=False), # correction_section | |
| "", # correction_notes (clear) | |
| message # status_message | |
| ) | |
| else: | |
| return ( | |
| gr.Textbox(value=""), # current_message_display (no change) | |
| gr.Markdown(value=""), # classifier_decision_display (no change) | |
| gr.Markdown(value=""), # classifier_confidence_display (no change) | |
| gr.Markdown(value=""), # classifier_indicators_display (no change) | |
| gr.Markdown(value=""), # verification_progress (no change) | |
| gr.Markdown(value=""), # session_stats_display (no change) | |
| gr.Row(visible=True), # correction_section (keep visible) | |
| notes, # correction_notes (keep) | |
| message # status_message | |
| ) | |
| def on_export_results(format_type): | |
| """Handle results export.""" | |
| success, message, file_path = controller.export_session_results(format_type) | |
| return message | |
| # Bind event handlers | |
| enhanced_dataset_interface.load( | |
| initialize_interface, | |
| outputs=[ | |
| dataset_selector, | |
| dataset_info_display, | |
| status_message, | |
| template_selector | |
| ] | |
| ) | |
| dataset_selector.change( | |
| on_dataset_selection_change, | |
| inputs=[dataset_selector], | |
| outputs=[dataset_info_display, current_dataset_state] | |
| ) | |
| load_dataset_btn.click( | |
| on_load_dataset, | |
| inputs=[current_dataset_state], | |
| outputs=[verification_section, status_message] | |
| ) | |
| edit_dataset_btn.click( | |
| on_edit_dataset, | |
| inputs=[current_dataset_state], | |
| outputs=[ | |
| dataset_editing_section, | |
| edit_dataset_name, | |
| edit_dataset_description, | |
| test_cases_display, | |
| status_message | |
| ] | |
| ) | |
| create_new_btn.click( | |
| on_create_new, | |
| outputs=[dataset_creation_section, status_message] | |
| ) | |
| create_dataset_btn.click( | |
| on_create_dataset, | |
| inputs=[new_dataset_name, new_dataset_description, template_selector], | |
| outputs=[ | |
| dataset_creation_section, | |
| dataset_selector, | |
| current_dataset_state, | |
| status_message | |
| ] | |
| ) | |
| cancel_create_btn.click( | |
| lambda: (gr.Row(visible=False), "β Dataset creation cancelled"), | |
| outputs=[dataset_creation_section, status_message] | |
| ) | |
| add_test_case_btn.click( | |
| on_add_test_case, | |
| inputs=[current_dataset_state, new_message_text, new_classification], | |
| outputs=[ | |
| current_dataset_state, | |
| test_cases_display, | |
| new_message_text, | |
| status_message | |
| ] | |
| ) | |
| save_dataset_btn.click( | |
| on_save_dataset, | |
| inputs=[current_dataset_state], | |
| outputs=[status_message] | |
| ) | |
| cancel_edit_btn.click( | |
| lambda: (gr.Row(visible=False), "β Dataset editing cancelled"), | |
| outputs=[dataset_editing_section, status_message] | |
| ) | |
| start_verification_btn.click( | |
| on_start_verification, | |
| inputs=[current_dataset_state, verifier_name_input], | |
| outputs=[ | |
| verification_session_state, | |
| message_review_area, | |
| current_message_display, | |
| classifier_decision_display, | |
| classifier_confidence_display, | |
| classifier_indicators_display, | |
| verification_progress, | |
| status_message | |
| ] | |
| ) | |
| correct_classification_btn.click( | |
| on_correct_classification, | |
| outputs=[ | |
| current_message_display, | |
| classifier_decision_display, | |
| classifier_confidence_display, | |
| classifier_indicators_display, | |
| verification_progress, | |
| session_stats_display, | |
| correction_section, | |
| status_message | |
| ] | |
| ) | |
| incorrect_classification_btn.click( | |
| on_incorrect_classification, | |
| outputs=[correction_section, status_message] | |
| ) | |
| submit_correction_btn.click( | |
| on_submit_correction, | |
| inputs=[correction_selector, correction_notes], | |
| outputs=[ | |
| current_message_display, | |
| classifier_decision_display, | |
| classifier_confidence_display, | |
| classifier_indicators_display, | |
| verification_progress, | |
| session_stats_display, | |
| correction_section, | |
| correction_notes, | |
| status_message | |
| ] | |
| ) | |
| export_csv_btn.click( | |
| lambda: on_export_results("csv"), | |
| outputs=[status_message] | |
| ) | |
| export_json_btn.click( | |
| lambda: on_export_results("json"), | |
| outputs=[status_message] | |
| ) | |
| export_xlsx_btn.click( | |
| lambda: on_export_results("xlsx"), | |
| outputs=[status_message] | |
| ) | |
| return enhanced_dataset_interface |