building-planner-with-drm / gradio-ui /components /recommendations_display.py
dexteredep's picture
update look
fc82def
"""
Recommendations Display Component
Displays construction recommendations
"""
from typing import List
def _get_attr(obj, attr, default=None):
"""Safely get attribute from dict or object"""
if isinstance(obj, dict):
return obj.get(attr, default)
return getattr(obj, attr, default)
def format_recommendations_display(recommendations) -> str:
"""
Format recommendations for display with clear sections and bullet points
Args:
recommendations: Construction recommendations (dict or object)
Returns:
Formatted HTML/Markdown string
"""
import logging
logger = logging.getLogger(__name__)
# Debug logging
logger.info(f"format_recommendations_display received type: {type(recommendations)}")
logger.info(f"recommendations content: {str(recommendations)[:500]}")
if not recommendations:
return "⚠️ Recommendations data unavailable"
# Handle success field
success = _get_attr(recommendations, 'success', True)
if not success:
return "⚠️ Recommendations data unavailable"
html = """
<div style="padding: 20px;">
<h2 style="margin-top: 0; color: #ffffff !important; font-weight: 700;">πŸ“‹ Construction Recommendations</h2>
"""
# General Guidelines
general_guidelines = _get_attr(recommendations, 'general_guidelines', [])
logger.info(f"general_guidelines type: {type(general_guidelines)}, value: {general_guidelines}")
# Handle case where general_guidelines might be a dict instead of a list
if general_guidelines:
# If it's a dict, it might be the entire recommendations object mistakenly
if isinstance(general_guidelines, dict):
logger.warning("general_guidelines is a dict, not a list - attempting to extract")
# Try to get the actual guidelines from the dict
if 'general_guidelines' in general_guidelines:
general_guidelines = general_guidelines['general_guidelines']
else:
# Display the dict content as a fallback
general_guidelines = []
if general_guidelines and isinstance(general_guidelines, list):
html += """
<div style="background: white; padding: 20px; border-radius: 8px; margin-bottom: 20px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); border: 1px solid #e2e8f0;">
<h3 style="color: #1e40af !important; margin-top: 0; font-weight: 600;">πŸ—οΈ General Guidelines</h3>
<ul style="line-height: 1.8; color: #0f172a !important;">
"""
for guideline in general_guidelines:
# Ensure guideline is a string
guideline_str = str(guideline) if not isinstance(guideline, str) else guideline
html += f"<li style='color: #0f172a !important;'>{guideline_str}</li>"
html += """
</ul>
</div>
"""
# Priority Actions - handle both dict and object
priority_actions = _get_attr(recommendations, 'priority_actions', [])
if priority_actions:
html += """
<div style="background: white; padding: 20px; border-radius: 8px; margin-bottom: 20px; border-left: 5px solid #f59e0b; box-shadow: 0 2px 4px rgba(0,0,0,0.1); border: 1px solid #fde68a;">
<h3 style="color: #d97706 !important; margin-top: 0; font-weight: 600;">⚑ Priority Actions</h3>
<ol style="line-height: 1.8; font-weight: 500; color: #0f172a !important;">
"""
for action in priority_actions:
html += f"<li style='color: #0f172a !important;'>{action}</li>"
html += """
</ol>
</div>
"""
# Seismic Recommendations - handle both dict and object
seismic_recommendations = _get_attr(recommendations, 'seismic_recommendations', [])
if seismic_recommendations:
html += _format_recommendation_category(
"🌍 Seismic Hazard Recommendations",
seismic_recommendations,
"#dc2626"
)
# Volcanic Recommendations - handle both dict and object
volcanic_recommendations = _get_attr(recommendations, 'volcanic_recommendations', [])
if volcanic_recommendations:
html += _format_recommendation_category(
"πŸŒ‹ Volcanic Hazard Recommendations",
volcanic_recommendations,
"#ea580c"
)
# Hydrometeorological Recommendations - handle both dict and object
hydrometeorological_recommendations = _get_attr(recommendations, 'hydrometeorological_recommendations', [])
if hydrometeorological_recommendations:
html += _format_recommendation_category(
"🌊 Hydrometeorological Hazard Recommendations",
hydrometeorological_recommendations,
"#0ea5e9"
)
# Check if any content was rendered
has_content = bool(
(general_guidelines and isinstance(general_guidelines, list)) or
priority_actions or
seismic_recommendations or
volcanic_recommendations or
hydrometeorological_recommendations
)
# If no sections were rendered, show a debug view
if not has_content:
html += """
<div style="background: white; padding: 20px; border-radius: 8px; margin-bottom: 20px; border-left: 5px solid #d97706; border: 1px solid #fde68a;">
<h3 style="color: #b45309 !important; margin-top: 0;">⚠️ Raw Recommendations Data</h3>
<p style="color: #0f172a !important;">The recommendations data structure is unexpected. Here's the raw content:</p>
<pre style="background: #f8fafc; padding: 15px; border-radius: 4px; overflow-x: auto; color: #0f172a !important; font-size: 0.9em; border: 1px solid #e2e8f0;">
"""
import json
try:
html += json.dumps(recommendations, indent=2, default=str)
except:
html += str(recommendations)
html += """
</pre>
</div>
"""
# Building Code References - handle both dict and object
building_codes = _get_attr(recommendations, 'building_codes', [])
if building_codes:
html += """
<div style="background: white; padding: 20px; border-radius: 8px; margin-bottom: 20px; border-left: 5px solid #7c3aed; box-shadow: 0 2px 4px rgba(0,0,0,0.1); border: 1px solid #e2e8f0;">
<h3 style="color: #7c3aed !important; margin-top: 0; font-weight: 600;">πŸ“– Building Code References</h3>
<table style="width: 100%; border-collapse: collapse;">
<thead>
<tr style="background: #f3f4f6;">
<th style="padding: 10px; text-align: left; border-bottom: 2px solid #e5e7eb; color: #0f172a !important; font-weight: 600;">Code</th>
<th style="padding: 10px; text-align: left; border-bottom: 2px solid #e5e7eb; color: #0f172a !important; font-weight: 600;">Section</th>
<th style="padding: 10px; text-align: left; border-bottom: 2px solid #e5e7eb; color: #0f172a !important; font-weight: 600;">Requirement</th>
</tr>
</thead>
<tbody>
"""
for code in building_codes:
# Extract code properties - handle both dict and object
code_name = _get_attr(code, 'code_name', 'Unknown')
section = _get_attr(code, 'section', 'N/A')
requirement = _get_attr(code, 'requirement', 'No requirement specified')
html += f"""
<tr style="border-bottom: 1px solid #e5e7eb;">
<td style="padding: 10px; color: #0f172a !important;"><strong style="color: #0f172a !important;">{code_name}</strong></td>
<td style="padding: 10px; color: #0f172a !important;">{section}</td>
<td style="padding: 10px; color: #0f172a !important;">{requirement}</td>
</tr>
"""
html += """
</tbody>
</table>
</div>
"""
html += """
</div>
"""
return html
def _format_recommendation_category(
title: str,
recommendations: List,
color: str
) -> str:
"""Format a category of recommendations (handles both dict and object formats)"""
html = f"""
<div style="background: white; padding: 20px; border-radius: 8px; margin-bottom: 20px; border-left: 5px solid {color}; box-shadow: 0 2px 4px rgba(0,0,0,0.1); border: 1px solid #e2e8f0;">
<h3 style="color: {color} !important; margin-top: 0; font-weight: 600;">{title}</h3>
"""
for rec in recommendations:
# Extract properties - handle both dict and object
hazard_type = _get_attr(rec, 'hazard_type', 'Unknown')
recommendation = _get_attr(rec, 'recommendation', 'No recommendation available')
rationale = _get_attr(rec, 'rationale', 'No rationale provided')
source_url = _get_attr(rec, 'source_url')
html += f"""
<div style="margin-bottom: 15px; padding: 15px; background: #f8fafc; border-radius: 6px; border: 1px solid #e2e8f0;">
<h4 style="margin-top: 0; color: #0f172a !important;">
<span style="background: {color}; color: white !important; padding: 5px 10px; border-radius: 4px; font-size: 0.85em; margin-right: 8px; font-weight: 600;">
{hazard_type}
</span>
</h4>
<p style="margin: 10px 0; line-height: 1.6; color: #0f172a !important;"><strong style="color: #0f172a !important;">Recommendation:</strong> {recommendation}</p>
<p style="margin: 10px 0; line-height: 1.6; color: #0f172a !important;"><strong style="color: #0f172a !important;">Rationale:</strong> {rationale}</p>
"""
if source_url:
html += f"""
<p style="margin: 10px 0; font-size: 0.9em;">
<a href="{source_url}" target="_blank" style="color: #2563eb; text-decoration: none;">
πŸ”— Source
</a>
</p>
"""
html += """
</div>
"""
html += """
</div>
"""
return html