Files
AR-House/location_agent/report/report_generator.py
T
2026-07-03 12:24:58 -04:00

168 lines
6.4 KiB
Python

"""Generador del reporte de texto completo."""
from __future__ import annotations
from datetime import datetime
def build_report(
geo: dict,
sub_results: dict,
scores: dict,
overall_score: int,
narratives: dict,
exec_summary: dict,
) -> dict:
"""Construye el dict completo del reporte con todas las secciones."""
now = datetime.now()
report = {
"address": geo.get("address", ""),
"lat": geo.get("lat"),
"lon": geo.get("lon"),
"analysis_date": now.strftime("%Y-%m-%d %H:%M"),
"overall_score": overall_score,
"scores": scores,
"sections": {},
"exec_summary": exec_summary,
}
# Sección 1: Resumen ejecutivo (construido arriba)
report["sections"]["executive"] = {
"title": "Resumen Ejecutivo",
"score": overall_score,
"summary": exec_summary.get("summary", ""),
"strengths": exec_summary.get("strengths", []),
"weaknesses": exec_summary.get("weaknesses", []),
}
# Sección 2: Criminalidad
crime_data = sub_results.get("crime", {})
report["sections"]["crime"] = {
"title": "Criminalidad",
"score": scores.get("crime", 0),
"total_crimes_30d": crime_data.get("score_input", {}).get("total_crimes_30d", "N/A"),
"crime_types": crime_data.get("crime_types", {}),
"has_violent": crime_data.get("score_input", {}).get("has_violent", False),
"sources": crime_data.get("sources", []),
"errors": crime_data.get("errors", []),
"narrative": narratives.get("crime", ""),
}
# Sección 3: Valoración inmobiliaria
prop_data = sub_results.get("property", {})
report["sections"]["property"] = {
"title": "Valoración y Mercado Inmobiliario",
"score": scores.get("property", 0),
"estimated_value": prop_data.get("estimated_value"),
"price_per_sqft": prop_data.get("price_per_sqft"),
"appreciation_1y": prop_data.get("appreciation_1y"),
"appreciation_3y": prop_data.get("appreciation_3y"),
"days_on_market": prop_data.get("days_on_market"),
"median_list_price": prop_data.get("median_list_price"),
"inventory": prop_data.get("inventory"),
"county_assessed_value": prop_data.get("county_assessed_value"),
"sources": prop_data.get("sources", []),
"errors": prop_data.get("errors", []),
"narrative": narratives.get("property", ""),
}
# Sección 4: Escuelas
school_data = sub_results.get("schools", {})
report["sections"]["schools"] = {
"title": "Escuelas",
"score": scores.get("schools", 0),
"avg_rating": school_data.get("avg_rating"),
"schools": school_data.get("schools", []),
"best_elementary": school_data.get("best_elementary"),
"best_middle": school_data.get("best_middle"),
"best_high": school_data.get("best_high"),
"sources": school_data.get("sources", []),
"errors": school_data.get("errors", []),
"narrative": narratives.get("schools", ""),
}
# Sección 5: Amenities
amenity_data = sub_results.get("amenities", {})
report["sections"]["amenities"] = {
"title": "Amenities y Walkability",
"score": scores.get("amenities", 0),
"walk_score": amenity_data.get("walk_score_estimate"),
"total_amenities": amenity_data.get("total_amenities", 0),
"categories": amenity_data.get("categories", {}),
"nearest": amenity_data.get("nearest", {}),
"sources": amenity_data.get("sources", []),
"errors": amenity_data.get("errors", []),
"narrative": narratives.get("amenities", ""),
}
# Sección 6: Demografía
demo_data = sub_results.get("demographics", {})
report["sections"]["demographics"] = {
"title": "Demografía",
"score": scores.get("demographics", 0),
"median_household_income": demo_data.get("median_household_income"),
"median_age": demo_data.get("median_age"),
"unemployment_rate": demo_data.get("unemployment_rate"),
"education_bachelors_pct": demo_data.get("education_bachelors_pct"),
"ethnicity": demo_data.get("ethnicity", {}),
"total_population": demo_data.get("total_population"),
"sources": demo_data.get("sources", []),
"errors": demo_data.get("errors", []),
"narrative": narratives.get("demographics", ""),
}
# Sección 7: Mercado marítimo
maritime_data = sub_results.get("maritime", {})
report["sections"]["maritime"] = {
"title": "Mercado Laboral Marítimo",
"score": scores.get("maritime", 0),
"shipyards": maritime_data.get("shipyards", []),
"marinas_with_jobs": maritime_data.get("marinas_with_jobs", []),
"maritime_employers": maritime_data.get("maritime_employers", []),
"bls_employment": maritime_data.get("bls_employment", {}),
"sources": maritime_data.get("sources", []),
"errors": maritime_data.get("errors", []),
"narrative": narratives.get("maritime", ""),
}
# Sección 8: Lifestyle náutico
life_data = sub_results.get("lifestyle", {})
report["sections"]["lifestyle"] = {
"title": "Estilo de Vida Náutico",
"score": scores.get("lifestyle", 0),
"marinas": life_data.get("marinas", []),
"boat_ramps": life_data.get("boat_ramps", []),
"beaches": life_data.get("beaches", []),
"nearest_marina": life_data.get("nearest_marina"),
"nearest_beach": life_data.get("nearest_beach"),
"ocean_access": life_data.get("ocean_access", False),
"waterway_nearby": life_data.get("waterway_nearby", False),
"sources": life_data.get("sources", []),
"errors": life_data.get("errors", []),
"narrative": narratives.get("lifestyle", ""),
}
# Texto plano del reporte para guardar en BD
report["report_text"] = _build_text(report)
return report
def _build_text(report: dict) -> str:
lines = [
f"AR-HOUSE LOCATION INTELLIGENCE REPORT",
f"Dirección: {report['address']}",
f"Fecha: {report['analysis_date']}",
f"Score General: {report['overall_score']}/100",
"",
]
for key, sec in report["sections"].items():
lines.append(f"=== {sec['title'].upper()} ===")
if sec.get("score") is not None:
lines.append(f"Score: {sec['score']}/100")
if sec.get("narrative"):
lines.append(sec["narrative"])
lines.append("")
return "\n".join(lines)