|
|
""" |
|
|
House Specifications Display Component |
|
|
Displays house/building specifications with justifications |
|
|
""" |
|
|
|
|
|
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_house_specs_display(house_specs) -> str: |
|
|
""" |
|
|
Format house specifications for display with organized sections |
|
|
|
|
|
Args: |
|
|
house_specs: House specifications data (dict or HouseSpecifications object) |
|
|
|
|
|
Returns: |
|
|
Formatted HTML string |
|
|
""" |
|
|
import logging |
|
|
logger = logging.getLogger(__name__) |
|
|
|
|
|
|
|
|
logger.info(f"format_house_specs_display received type: {type(house_specs)}") |
|
|
|
|
|
if not house_specs: |
|
|
return """ |
|
|
<div style="padding: 20px;"> |
|
|
<p style="text-align: center; color: #6b7280;">β οΈ House specifications data unavailable</p> |
|
|
</div> |
|
|
""" |
|
|
|
|
|
html = """ |
|
|
<div style="padding: 20px;"> |
|
|
<h2 style="margin-top: 0; color: #ffffff !important; font-weight: 700;">ποΈ House Specifications</h2> |
|
|
|
|
|
<div style="background: white; padding: 20px; border-radius: 8px; margin-bottom: 20px; border-left: 5px solid #3b82f6; box-shadow: 0 2px 4px rgba(0,0,0,0.1); border: 1px solid #bfdbfe;"> |
|
|
<h3 style="color: #1e40af !important; margin-top: 0; font-weight: 600;">π Basic Specifications</h3> |
|
|
""" |
|
|
|
|
|
|
|
|
number_of_floors = _get_attr(house_specs, 'number_of_floors', 'N/A') |
|
|
primary_material = _get_attr(house_specs, 'primary_material', 'N/A') |
|
|
foundation_type = _get_attr(house_specs, 'foundation_type', 'N/A') |
|
|
foundation_depth = _get_attr(house_specs, 'foundation_depth_meters', 0) |
|
|
roof_type = _get_attr(house_specs, 'roof_type', 'N/A') |
|
|
wall_thickness = _get_attr(house_specs, 'wall_thickness_mm', 0) |
|
|
|
|
|
|
|
|
primary_material_display = str(primary_material).replace('_', ' ').title() |
|
|
foundation_type_display = str(foundation_type).replace('_', ' ').title() |
|
|
roof_type_display = str(roof_type).replace('_', ' ').title() |
|
|
|
|
|
html += f""" |
|
|
<table style="width: 100%; border-collapse: collapse;"> |
|
|
<tr style="border-bottom: 1px solid #e2e8f0;"> |
|
|
<td style="padding: 12px; color: #0f172a !important; font-weight: 600; width: 40%;">Number of Floors</td> |
|
|
<td style="padding: 12px; color: #0f172a !important;">{number_of_floors}</td> |
|
|
</tr> |
|
|
<tr style="border-bottom: 1px solid #e2e8f0;"> |
|
|
<td style="padding: 12px; color: #0f172a !important; font-weight: 600;">Primary Material</td> |
|
|
<td style="padding: 12px; color: #0f172a !important;">{primary_material_display}</td> |
|
|
</tr> |
|
|
<tr style="border-bottom: 1px solid #e2e8f0;"> |
|
|
<td style="padding: 12px; color: #0f172a !important; font-weight: 600;">Foundation Type</td> |
|
|
<td style="padding: 12px; color: #0f172a !important;">{foundation_type_display}</td> |
|
|
</tr> |
|
|
<tr style="border-bottom: 1px solid #e2e8f0;"> |
|
|
<td style="padding: 12px; color: #0f172a !important; font-weight: 600;">Foundation Depth</td> |
|
|
<td style="padding: 12px; color: #0f172a !important;">{foundation_depth:.2f} meters</td> |
|
|
</tr> |
|
|
<tr style="border-bottom: 1px solid #e2e8f0;"> |
|
|
<td style="padding: 12px; color: #0f172a !important; font-weight: 600;">Roof Type</td> |
|
|
<td style="padding: 12px; color: #0f172a !important;">{roof_type_display}</td> |
|
|
</tr> |
|
|
<tr> |
|
|
<td style="padding: 12px; color: #0f172a !important; font-weight: 600;">Wall Thickness</td> |
|
|
<td style="padding: 12px; color: #0f172a !important;">{wall_thickness} mm</td> |
|
|
</tr> |
|
|
</table> |
|
|
</div> |
|
|
""" |
|
|
|
|
|
|
|
|
reinforcement_details = _get_attr(house_specs, 'reinforcement_details', '') |
|
|
if reinforcement_details: |
|
|
html += f""" |
|
|
<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;">π© Reinforcement Details</h3> |
|
|
<p style="line-height: 1.8; color: #0f172a !important; margin: 0;">{reinforcement_details}</p> |
|
|
</div> |
|
|
""" |
|
|
|
|
|
|
|
|
structural_features = _get_attr(house_specs, 'structural_features', []) |
|
|
if structural_features: |
|
|
html += """ |
|
|
<div style="background: white; padding: 20px; border-radius: 8px; margin-bottom: 20px; border-left: 5px solid #10b981; box-shadow: 0 2px 4px rgba(0,0,0,0.1); border: 1px solid #a7f3d0;"> |
|
|
<h3 style="color: #059669 !important; margin-top: 0; font-weight: 600;">π‘οΈ Structural Features</h3> |
|
|
""" |
|
|
|
|
|
for feature in structural_features: |
|
|
feature_name = _get_attr(feature, 'feature_name', 'Unknown Feature') |
|
|
specification = _get_attr(feature, 'specification', 'No specification provided') |
|
|
justification = _get_attr(feature, 'justification', 'No justification provided') |
|
|
|
|
|
html += f""" |
|
|
<div style="margin-bottom: 15px; padding: 15px; background: #f0fdf4; border-radius: 6px; border: 1px solid #d1fae5;"> |
|
|
<h4 style="margin-top: 0; color: #0f172a !important; font-weight: 600;"> |
|
|
<span style="background: #059669; color: white !important; padding: 5px 10px; border-radius: 4px; font-size: 0.85em; margin-right: 8px;"> |
|
|
{feature_name} |
|
|
</span> |
|
|
</h4> |
|
|
<p style="margin: 10px 0; line-height: 1.6; color: #0f172a !important;"> |
|
|
<strong style="color: #0f172a !important;">Specification:</strong> {specification} |
|
|
</p> |
|
|
<p style="margin: 10px 0; line-height: 1.6; color: #0f172a !important;"> |
|
|
<strong style="color: #0f172a !important;">Justification:</strong> {justification} |
|
|
</p> |
|
|
</div> |
|
|
""" |
|
|
|
|
|
html += """ |
|
|
</div> |
|
|
""" |
|
|
|
|
|
|
|
|
compliance_codes = _get_attr(house_specs, 'compliance_codes', []) |
|
|
if compliance_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 #ddd6fe;"> |
|
|
<h3 style="color: #7c3aed !important; margin-top: 0; font-weight: 600;">π Compliance Codes</h3> |
|
|
<ul style="line-height: 1.8; color: #0f172a !important; margin: 0;"> |
|
|
""" |
|
|
|
|
|
for code in compliance_codes: |
|
|
html += f"<li style='color: #0f172a !important;'>{code}</li>" |
|
|
|
|
|
html += """ |
|
|
</ul> |
|
|
</div> |
|
|
""" |
|
|
|
|
|
|
|
|
decision_rationale = _get_attr(house_specs, 'decision_rationale', '') |
|
|
if decision_rationale: |
|
|
html += f""" |
|
|
<div style="background: white; padding: 20px; border-radius: 8px; margin-bottom: 20px; border-left: 5px solid #ec4899; box-shadow: 0 2px 4px rgba(0,0,0,0.1); border: 1px solid #fbcfe8;"> |
|
|
<h3 style="color: #db2777 !important; margin-top: 0; font-weight: 600;">π‘ Decision Rationale</h3> |
|
|
<p style="line-height: 1.8; color: #0f172a !important; margin: 0; white-space: pre-wrap;">{decision_rationale}</p> |
|
|
</div> |
|
|
""" |
|
|
|
|
|
|
|
|
html += """ |
|
|
<div style="background: white; padding: 15px; border-radius: 8px; margin-top: 20px; font-size: 0.9em; border: 1px solid #e2e8f0;"> |
|
|
<p style="margin: 0; color: #0f172a !important;"> |
|
|
<strong style="color: #0f172a !important;">Note:</strong> These specifications are AI-generated recommendations based on the risk assessment. |
|
|
Always consult with licensed structural engineers and architects for final design decisions. |
|
|
All specifications must be reviewed and approved by qualified professionals before construction. |
|
|
</p> |
|
|
</div> |
|
|
</div> |
|
|
""" |
|
|
|
|
|
return html |
|
|
|