working on presentation and content

This commit is contained in:
Khalim Conn-Kowlessar 2024-02-21 17:30:56 +00:00
parent c0b1acef98
commit 35a75bc4e5
6 changed files with 85 additions and 31 deletions

View file

@ -470,7 +470,7 @@ class Property:
to_update[k] = None to_update[k] = None
return to_update return to_update
def get_full_property_data(self): def get_full_property_data(self, current_valuation=None):
""" """
This method extracts the data which is pushed to the database, containing core information, from the EPC This method extracts the data which is pushed to the database, containing core information, from the EPC
about a property about a property
@ -492,6 +492,7 @@ class Property:
"tenure": self.data["tenure"], "tenure": self.data["tenure"],
"current_epc_rating": self.data["current-energy-rating"], "current_epc_rating": self.data["current-energy-rating"],
"current_sap_points": self.data["current-energy-efficiency"], "current_sap_points": self.data["current-energy-efficiency"],
"current_valuation": current_valuation
} }
property_data = self._clean_upload_data(property_data) property_data = self._clean_upload_data(property_data)

View file

@ -86,6 +86,7 @@ class PropertyModel(Base):
tenure = Column(Text) tenure = Column(Text)
current_epc_rating = Column(Enum(Epc)) current_epc_rating = Column(Enum(Epc))
current_sap_points = Column(Float) current_sap_points = Column(Float)
current_valuation = Column(Float)
class FeatureRating(enum.Enum): class FeatureRating(enum.Enum):

View file

@ -53,6 +53,9 @@ class Plan(Base):
property_id = Column(BigInteger, ForeignKey(PropertyModel.id), nullable=False) property_id = Column(BigInteger, ForeignKey(PropertyModel.id), nullable=False)
created_at = Column(TIMESTAMP, nullable=False, server_default=func.now()) created_at = Column(TIMESTAMP, nullable=False, server_default=func.now())
is_default = Column(Boolean, nullable=False) is_default = Column(Boolean, nullable=False)
valuation_increase_lower_bound = Column(Float)
valuation_increase_upper_bound = Column(Float)
valuation_increase_average = Column(Float)
class PlanRecommendations(Base): class PlanRecommendations(Base):

View file

@ -291,27 +291,43 @@ async def trigger_plan(body: PlanTriggerRequest):
batch_properties = input_properties[i:i + BATCH_SIZE] batch_properties = input_properties[i:i + BATCH_SIZE]
for p in batch_properties: for p in batch_properties:
recommendations_to_upload = recommendations.get(p.id, [])
default_recommendations = [r for r in recommendations_to_upload if r["default"]]
total_sap_points = sum([r["sap_points"] for r in default_recommendations])
new_sap_points = float(p.data["current-energy-efficiency"]) + total_sap_points
new_epc = sap_to_epc(new_sap_points)
valuations = PropertyValuation.estimate(property_instance=p, target_epc=new_epc)
# Your existing operations # Your existing operations
property_details_epc = p.get_property_details_epc( property_details_epc = p.get_property_details_epc(
portfolio_id=body.portfolio_id, rating_lookup=rating_lookup portfolio_id=body.portfolio_id, rating_lookup=rating_lookup,
) )
create_property_details_epc(session, property_details_epc) create_property_details_epc(session, property_details_epc)
update_or_create_property_spatial_details(session, p.uprn, p.spatial) update_or_create_property_spatial_details(session, p.uprn, p.spatial)
property_data = p.get_full_property_data() property_data = p.get_full_property_data(current_valuation=valuations["current_value"])
update_property_data( update_property_data(
session, property_id=p.id, portfolio_id=body.portfolio_id, property_data=property_data session, property_id=p.id, portfolio_id=body.portfolio_id, property_data=property_data
) )
recommendations_to_upload = recommendations.get(p.id, [])
if not recommendations_to_upload: if not recommendations_to_upload:
continue continue
new_plan_id = create_plan(session, { new_plan_id = create_plan(session, {
"portfolio_id": body.portfolio_id, "portfolio_id": body.portfolio_id,
"property_id": p.id, "property_id": p.id,
"is_default": True "is_default": True,
"valuation_increase_lower_bound": (
valuations["lower_bound_increased_value"] - valuations["current_value"]
),
"valuation_increase_upper_bound": (
valuations["upper_bound_increased_value"] - valuations["current_value"]
),
"valuation_increase_average": (
valuations["average_increased_value"] - valuations["current_value"]
),
}) })
uploaded_recommendation_ids = upload_recommendations(session, recommendations_to_upload, p.id) uploaded_recommendation_ids = upload_recommendations(session, recommendations_to_upload, p.id)
@ -320,14 +336,6 @@ async def trigger_plan(body: PlanTriggerRequest):
session, plan_id=new_plan_id, recommendation_ids=uploaded_recommendation_ids session, plan_id=new_plan_id, recommendation_ids=uploaded_recommendation_ids
) )
# Get defaults
default_recommendations = [r for r in recommendations_to_upload if r["default"]]
total_sap_points = sum([r["sap_points"] for r in default_recommendations])
new_sap_points = float(p.data["current-energy-efficiency"]) + total_sap_points
new_epc = sap_to_epc(new_sap_points)
valuations = PropertyValuation.estimate(property_instance=p, target_epc=new_epc)
property_valuation_increases.append( property_valuation_increases.append(
valuations["average_increased_value"] - valuations["current_value"] valuations["average_increased_value"] - valuations["current_value"]
) )

View file

@ -1,4 +1,5 @@
import os import os
from pptx.enum.text import PP_ALIGN
from pptx import Presentation from pptx import Presentation
from pptx.util import Inches, Pt from pptx.util import Inches, Pt
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
@ -148,26 +149,64 @@ def save_figure_as_image(figure, filename='temp_plot.png'):
plt.close(figure) # Close the figure to prevent it from displaying in notebooks or Python environments plt.close(figure) # Close the figure to prevent it from displaying in notebooks or Python environments
def add_commentary_with_bullets(slide, commentary, top_inches, left_inches=Inches(1), width_inches=Inches(8),
height_inches=Inches(2)):
"""
Adds commentary with bullet points to a slide.
:param slide: The slide object to add the commentary to.
:param commentary: The commentary text, with sections separated by newlines for bullet points.
:param top_inches: The top position of the commentary text box.
:param left_inches: The left position of the commentary text box.
:param width_inches: The width of the commentary text box.
:param height_inches: The height of the commentary text box.
"""
txBox = slide.shapes.add_textbox(left_inches, top_inches, width_inches, height_inches)
tf = txBox.text_frame
# Configure text frame
tf.word_wrap = True
tf.auto_size = True
tf.paragraphs[0].alignment = PP_ALIGN.LEFT
# Split the commentary into sections for bullet points
sections = commentary.split("\n")
for i, section in enumerate(sections):
if i > 0:
p = tf.add_paragraph() # Add a new paragraph for each section after the first
else:
p = tf.paragraphs[0] # Use the first paragraph for the first section
p.text = section
p.space_after = Pt(14) # Adjust space after each bullet point as needed
p.font.size = Pt(14) # Adjust font size as needed
p.level = 0 # Bullet level, can be adjusted for nested bullets
p.space_before = Pt(0)
def add_slide_with_image(prs, title, img_path=None, commentary=None): def add_slide_with_image(prs, title, img_path=None, commentary=None):
""" """
Adds a slide with an image and optional commentary. Adds a slide with an image (if provided) and optional commentary. If no image is provided,
places the commentary text in the middle of the slide.
""" """
slide_layout = prs.slide_layouts[5] # Title and Content layout slide_layout = prs.slide_layouts[5] # Title and Content layout
slide = prs.slides.add_slide(slide_layout) slide = prs.slides.add_slide(slide_layout)
title_placeholder = slide.shapes.title title_placeholder = slide.shapes.title
title_placeholder.text = title title_placeholder.text = title
# Add the image # Determine the position of the commentary text box based on whether an image is included
if img_path: if img_path:
# Add the image
slide.shapes.add_picture(img_path, Inches(1), Inches(1.5), Inches(8), Inches(4.5)) slide.shapes.add_picture(img_path, Inches(1), Inches(1.5), Inches(8), Inches(4.5))
# Position for commentary when image is present
commentary_top = Inches(6)
else:
# Position for commentary when image is not present (centered vertically)
commentary_top = Inches(3)
# Add commentary if provided # Add commentary if provided
if commentary: if commentary:
txBox = slide.shapes.add_textbox(Inches(1), Inches(6), Inches(8), Inches(1)) add_commentary_with_bullets(slide, commentary, commentary_top)
tf = txBox.text_frame
p = tf.add_paragraph()
p.text = commentary
p.font.size = Pt(14) # Adjust font size as needed
def create_powerpoint(data, save_location): def create_powerpoint(data, save_location):

View file

@ -104,16 +104,18 @@ def app():
) )
# Valuation: upper and lower bounds - TODO! # Valuation: upper and lower bounds - TODO!
min_valuation, max_valuation, average_valuation = 0, 0, 0 min_valuation, max_valuation, average_valuation = (0, 0, 0)
recommendations_df.keys()
slide_1_commentary = ( slide_1_commentary = (
f"Floor areas range from {min_area} to {max_area} square meters, with an average of {average_area} square " f"Floor areas range from {min_area} to {max_area} square meters, with an average of {average_area} square "
f"meters. " f"meters. \n"
f"Annual energy consumption ranges from {min_energy_consumption} to {max_energy_consumption} kWh, with an " f"Annual energy consumption ranges from {min_energy_consumption} to {max_energy_consumption} kWh, with an "
f"average of {average_consumption} kWh. " f"average of {average_consumption} kWh. \n"
f"CO2 emissions range from {min_co2} to {max_co2} tonnes, with an average of {average_co2} tonnes. " f"CO2 emissions range from {min_co2} to {max_co2} tonnes, with an average of {average_co2} tonnes. \n"
f"Valuations range from £{min_valuation} to £{max_valuation} £, with an average of £" f"Valuations range from £{min_valuation} to £{max_valuation} £, with an average of £"
f"{average_valuation}." f"{average_valuation}.\n"
) )
############ ############
@ -154,13 +156,13 @@ def app():
) )
slide_2_commentary = ( slide_2_commentary = (
f"{n_units_to_target} expected to achieve EPC {EPC_TARGET} " f"{n_units_to_target} units expected to achieve EPC {EPC_TARGET} \n"
f"Measures include: {measures}" f"Measures include: {measures}\n"
f"Valuation increase per property: £{min_valuation_impact}-{max_valuation_impact}, average: £" f"Valuation increase per property: £{min_valuation_impact}-{max_valuation_impact}, average: £"
f"{average_valuation_impact}" f"{average_valuation_impact}\n"
f"Bill savings per property: £{min_bill_savings}-{max_bill_savings}, average: £{average_bill_savings}" f"Bill savings per property: £{min_bill_savings}-{max_bill_savings}, average: £{average_bill_savings}\n"
f"Total CO2 reduction: {min_co2_reduction}-{max_co2_reduction} tonnes, average: {average_co2_reduction}" f"Total CO2 reduction: {min_co2_reduction}-{max_co2_reduction} tonnes, average: {average_co2_reduction}\n"
f"tonnes, total for the {n_units_to_target} properties: {total_co2_reduction} tonnes" f"tonnes, total for the {n_units_to_target} properties: {total_co2_reduction} tonnes\n"
) )
############ ############