# enhanced_results_display_manager.py
"""
Enhanced Results Display Manager for UI Classification Improvements.
This module provides enhanced display formatting for chat results with clear
visual separation between AI analysis, patient messages, and provider summaries.
Requirements: 1.1, 1.2, 7.1, 7.2
"""
import html
from typing import Dict, List, Optional, Any
from dataclasses import dataclass
from enum import Enum
from src.core.provider_summary_generator import ProviderSummary
from src.core.spiritual_state import SpiritualAssessment, SpiritualState
from src.config.enhanced_display_config import (
EnhancedDisplayConfig,
get_enhanced_display_config,
EnhancedDisplayConfigManager
)
class SectionType(Enum):
"""Types of content sections for display."""
AI_ANALYSIS = "ai_analysis"
PATIENT_MESSAGE = "patient_message"
PROVIDER_SUMMARY = "provider_summary"
@dataclass
class ContentSection:
"""Represents a content section with styling information."""
section_type: SectionType
content: str
styling: Dict[str, str]
icon: Optional[str] = None
priority: int = 0
@dataclass
class ContentSection:
"""Represents a content section with styling information."""
section_type: SectionType
content: str
styling: Dict[str, str]
icon: Optional[str] = None
priority: int = 0
class EnhancedResultsDisplayManager:
"""
Enhanced Results Display Manager for improved UI formatting.
Provides methods to format different types of content with clear visual
separation and consistent styling according to requirements 1.1, 1.2, 7.1, 7.2.
"""
def __init__(self, config: Optional[EnhancedDisplayConfig] = None, config_manager: Optional[EnhancedDisplayConfigManager] = None):
"""
Initialize the display manager.
Args:
config: Optional configuration for display formatting
config_manager: Optional configuration manager for dynamic updates
"""
self.config_manager = config_manager
if config is not None:
self.config = config
elif self.config_manager is not None:
self.config = self.config_manager.get_config()
else:
self.config = get_enhanced_display_config()
# Initialize error handler for validation and recovery (lazy loaded)
self._error_handler = None
@property
def error_handler(self):
"""Lazy load error handler to avoid circular imports."""
if self._error_handler is None:
from src.core.ui_error_handler import UIErrorHandler
self._error_handler = UIErrorHandler()
return self._error_handler
def format_ai_analysis_section(
self,
classification: str,
indicators: List[str],
reasoning: str,
confidence: Optional[float] = None
) -> str:
"""
Format AI analysis section with clear labeling and visual styling.
Args:
classification: The classification result (RED/YELLOW/GREEN)
indicators: List of distress indicators
reasoning: AI reasoning for the classification
confidence: Optional confidence score
Returns:
Formatted HTML string for AI analysis section
Requirements: 1.1, 7.1
"""
try:
# Validate inputs
if not classification:
classification = "UNKNOWN"
if not indicators:
indicators = ["No indicators available"]
if not reasoning:
reasoning = "No reasoning provided"
# Check if enhancements are enabled
if not self.config.enabled:
return self._format_basic_ai_analysis(classification, indicators, reasoning, confidence)
# Get classification color
color = self.config.get_classification_color(classification)
section_config = self.config.get_section_config("ai_analysis")
# Build confidence display
confidence_text = ""
if confidence is not None:
confidence_percent = int(confidence * 100)
confidence_text = f"
Confidence: {confidence_percent}%
"
# Build indicators list
indicators_html = ""
if indicators:
indicators_list = "".join([f"{html.escape(indicator)}" for indicator in indicators])
indicators_html = f"""
"""
# Build reasoning section
reasoning_html = f"""
Reasoning:
{html.escape(reasoning)}
"""
# Build icon display
icon_html = ""
if self.config.use_icons:
icon_html = f"{section_config.icon}"
# Combine all elements with enhanced styling
content = f"""
{icon_html}
AI Analysis - {classification} FLAG
{confidence_text}
{indicators_html}
{reasoning_html}
"""
return content
except Exception as e:
# Handle formatting errors with degraded display
error_context = f"AI analysis formatting failed: {str(e)}"
fallback_content = self._format_basic_ai_analysis(classification, indicators, reasoning, confidence)
return self.error_handler.create_degraded_display(error_context, fallback_content)
def format_patient_message_section(self, message: str) -> str:
"""
Format patient message section with appropriate styling.
Args:
message: The patient's message content
Returns:
Formatted HTML string for patient message section
Requirements: 1.2, 7.2
"""
try:
# Validate input
if not message:
message = "No message content available"
# Check if enhancements are enabled
if not self.config.enabled:
return self._format_basic_patient_message(message)
section_config = self.config.get_section_config("patient_message")
# Build icon display
icon_html = ""
if self.config.use_icons:
icon_html = f"{section_config.icon}"
content = f"""
{icon_html}
Patient Message
{html.escape(message)}
"""
return content
except Exception as e:
# Handle formatting errors with degraded display
error_context = f"Patient message formatting failed: {str(e)}"
fallback_content = self._format_basic_patient_message(message)
return self.error_handler.create_degraded_display(error_context, fallback_content)
def format_provider_summary_section(self, summary_data: ProviderSummary) -> str:
"""
Format provider summary section with enhanced styling.
Args:
summary_data: Provider summary data to format
Returns:
Formatted HTML string for provider summary section
Requirements: 1.1, 1.2, 7.1, 7.2
"""
try:
# Validate and fix summary data if needed
validation_result = self.error_handler.validate_provider_summary_structure(summary_data)
if validation_result.has_critical_errors():
# Apply fallback template for critical errors
summary_data = self.error_handler.apply_fallback_template(summary_data, "general")
# Check if enhancements are enabled
if not self.config.enabled:
return self._format_basic_provider_summary(summary_data)
section_config = self.config.get_section_config("provider_summary")
# Get urgency color
urgency_colors = {
'IMMEDIATE': self.config.classification_colors.red,
'URGENT': self.config.classification_colors.yellow,
'STANDARD': self.config.classification_colors.green
}
urgency_color = urgency_colors.get(summary_data.urgency_level, self.config.classification_colors.red)
# Build patient info section
patient_info = f"""
Patient Information:
Name: {html.escape(summary_data.patient_name)}
Phone: {html.escape(summary_data.patient_phone)}
"""
# Build indicators section
indicators_html = ""
if summary_data.indicators:
indicators_list = "".join([f"{html.escape(indicator)}" for indicator in summary_data.indicators])
indicators_html = f"""
"""
# Build situation description
situation_html = f"""
Situation Overview:
{html.escape(summary_data.situation_description)}
"""
# Build urgency information
urgency_html = f"""
Urgency Level:
{summary_data.urgency_level}
Follow-up Timeline: {summary_data.follow_up_timeline}
"""
# Build icon display
icon_html = ""
if self.config.use_icons:
icon_html = f"{section_config.icon}"
# Add validation warnings if any
warnings_html = ""
if validation_result.warnings:
warnings_list = "".join([f"{warning.message}" for warning in validation_result.warnings])
warnings_html = f"""
"""
# Combine all elements with enhanced styling
content = f"""
{icon_html}
Provider Summary
For Spiritual Care Team
{patient_info}
{urgency_html}
{situation_html}
{indicators_html}
{warnings_html}
"""
return content
except Exception as e:
# Handle formatting errors with degraded display
error_context = f"Provider summary formatting failed: {str(e)}"
fallback_content = self._format_basic_provider_summary(summary_data)
return self.error_handler.create_degraded_display(error_context, fallback_content)
def create_visual_separators(self) -> Dict[str, str]:
"""
Create visual separators for different content types.
Returns:
Dictionary mapping section types to separator HTML
Requirements: 7.1, 7.2
"""
# Check if separators are enabled
if not self.config.use_visual_separators:
return {
"section_break": "",
"content_divider": "",
"major_break": ""
}
separators = {
"section_break": f"""
{self.config.separators.section_separator}
""",
"content_divider": f"""
""",
"major_break": f"""
{self.config.separators.major_break_symbol}
"""
}
return separators
def apply_section_styling(self, content: str, section_type: SectionType) -> str:
"""
Apply consistent styling to a content section.
Args:
content: The content to style
section_type: The type of section for appropriate styling
Returns:
Styled HTML content
Requirements: 7.1, 7.2
"""
# Base styling for all sections
base_style = "margin: 15px 0; padding: 10px; border-radius: 6px;"
# Section-specific styling
section_styles = {
SectionType.AI_ANALYSIS: base_style + "background-color: #f8f9fa; border-left: 4px solid #6c757d;",
SectionType.PATIENT_MESSAGE: base_style + "background-color: #f0f7ff; border-left: 4px solid #4a90e2;",
SectionType.PROVIDER_SUMMARY: base_style + "background-color: #fff8f0; border-left: 4px solid #dc3545;"
}
style = section_styles.get(section_type, base_style)
return f"""
{content}
"""
def format_combined_results(
self,
ai_analysis: Optional[Dict[str, Any]] = None,
patient_message: Optional[str] = None,
provider_summary: Optional[ProviderSummary] = None
) -> str:
"""
Format combined results with all sections and proper separation.
Args:
ai_analysis: Optional AI analysis data
patient_message: Optional patient message
provider_summary: Optional provider summary data
Returns:
Complete formatted HTML with all sections
Requirements: 1.1, 1.2, 7.1, 7.2
"""
sections = []
separators = self.create_visual_separators()
# Add AI analysis section if provided
if ai_analysis:
ai_section = self.format_ai_analysis_section(
classification=ai_analysis.get('classification', 'UNKNOWN'),
indicators=ai_analysis.get('indicators', []),
reasoning=ai_analysis.get('reasoning', ''),
confidence=ai_analysis.get('confidence')
)
sections.append(ai_section)
# Add patient message section if provided
if patient_message:
patient_section = self.format_patient_message_section(patient_message)
sections.append(patient_section)
# Add provider summary section if provided
if provider_summary:
summary_section = self.format_provider_summary_section(provider_summary)
sections.append(summary_section)
# Join sections with separators
if len(sections) > 1:
content = separators["section_break"].join(sections)
elif sections:
content = sections[0]
else:
content = "No content to display
"
return content
def _format_basic_ai_analysis(self, classification: str, indicators: List[str], reasoning: str, confidence: Optional[float] = None) -> str:
"""Fallback basic formatting for AI analysis when enhancements are disabled."""
confidence_text = f" (Confidence: {int(confidence * 100)}%)" if confidence else ""
indicators_text = f"Indicators: {', '.join(indicators)}" if indicators else "No indicators"
return f"""
AI Analysis - {classification} FLAG{confidence_text}
{indicators_text}
Reasoning: {reasoning}
"""
def _format_basic_patient_message(self, message: str) -> str:
"""Fallback basic formatting for patient message when enhancements are disabled."""
return f"""
Patient Message
{html.escape(message)}
"""
def _format_basic_provider_summary(self, summary_data: ProviderSummary) -> str:
"""Fallback basic formatting for provider summary when enhancements are disabled."""
return f"""
Provider Summary
Patient: {summary_data.patient_name}
Phone: {summary_data.patient_phone}
Urgency: {summary_data.urgency_level}
Situation: {summary_data.situation_description}
"""
def update_config(self, new_config: EnhancedDisplayConfig) -> None:
"""
Update the configuration for this display manager.
Args:
new_config: New configuration to use
"""
self.config = new_config
def reload_config(self) -> None:
"""Reload configuration from the config manager if available."""
if self.config_manager is not None:
self.config = self.config_manager.get_config()
else:
self.config = get_enhanced_display_config()
def is_enhanced_mode_enabled(self) -> bool:
"""Check if enhanced display mode is enabled."""
return self.config.enabled
def get_css_styles(self) -> str:
"""
Get CSS styles for enhanced display.
Returns:
CSS string for enhanced display styling
"""
return self.config.generate_base_css()