feat: AR-House initial commit
This commit is contained in:
@@ -0,0 +1,167 @@
|
||||
"""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)
|
||||
Reference in New Issue
Block a user