Spiritual_Health_Project / src /interface /enhanced_verification_ui_backup.py
DocUA's picture
βœ… Enhanced Verification Modes - Production Ready
7bbd836
# 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
@dataclass
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"
]
}
}
@staticmethod
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
@staticmethod
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
@staticmethod
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"
@staticmethod
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
@staticmethod
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
@staticmethod
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
@staticmethod
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
@staticmethod
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
@staticmethod
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