|
|
""" |
|
|
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__) |
|
|
|
|
|
|
|
|
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" |
|
|
|
|
|
|
|
|
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 = _get_attr(recommendations, 'general_guidelines', []) |
|
|
logger.info(f"general_guidelines type: {type(general_guidelines)}, value: {general_guidelines}") |
|
|
|
|
|
|
|
|
if general_guidelines: |
|
|
|
|
|
if isinstance(general_guidelines, dict): |
|
|
logger.warning("general_guidelines is a dict, not a list - attempting to extract") |
|
|
|
|
|
if 'general_guidelines' in general_guidelines: |
|
|
general_guidelines = general_guidelines['general_guidelines'] |
|
|
else: |
|
|
|
|
|
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: |
|
|
|
|
|
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 = _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 = _get_attr(recommendations, 'seismic_recommendations', []) |
|
|
if seismic_recommendations: |
|
|
html += _format_recommendation_category( |
|
|
"π Seismic Hazard Recommendations", |
|
|
seismic_recommendations, |
|
|
"#dc2626" |
|
|
) |
|
|
|
|
|
|
|
|
volcanic_recommendations = _get_attr(recommendations, 'volcanic_recommendations', []) |
|
|
if volcanic_recommendations: |
|
|
html += _format_recommendation_category( |
|
|
"π Volcanic Hazard Recommendations", |
|
|
volcanic_recommendations, |
|
|
"#ea580c" |
|
|
) |
|
|
|
|
|
|
|
|
hydrometeorological_recommendations = _get_attr(recommendations, 'hydrometeorological_recommendations', []) |
|
|
if hydrometeorological_recommendations: |
|
|
html += _format_recommendation_category( |
|
|
"π Hydrometeorological Hazard Recommendations", |
|
|
hydrometeorological_recommendations, |
|
|
"#0ea5e9" |
|
|
) |
|
|
|
|
|
|
|
|
has_content = bool( |
|
|
(general_guidelines and isinstance(general_guidelines, list)) or |
|
|
priority_actions or |
|
|
seismic_recommendations or |
|
|
volcanic_recommendations or |
|
|
hydrometeorological_recommendations |
|
|
) |
|
|
|
|
|
|
|
|
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_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: |
|
|
|
|
|
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: |
|
|
|
|
|
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 |
|
|
|