mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-30 13:10:47 +00:00
started work on peabody
This commit is contained in:
parent
fd2d893499
commit
caeb776428
7 changed files with 37 additions and 17 deletions
|
|
@ -2,7 +2,6 @@ import time
|
||||||
import random
|
import random
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
|
|
||||||
from adhoc.investigation import newest_epc
|
|
||||||
from backend.SearchEpc import SearchEpc
|
from backend.SearchEpc import SearchEpc
|
||||||
from etl.find_my_epc.RetrieveFindMyEpc import RetrieveFindMyEpc
|
from etl.find_my_epc.RetrieveFindMyEpc import RetrieveFindMyEpc
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ from pydantic_settings import BaseSettings
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Settings(BaseSettings):
|
class Settings(BaseSettings):
|
||||||
API_KEY: str
|
API_KEY: str
|
||||||
API_KEY_NAME: str = "X-API-KEY"
|
API_KEY_NAME: str = "X-API-KEY"
|
||||||
|
|
@ -43,7 +42,8 @@ class Settings(BaseSettings):
|
||||||
AWS_DEFAULT_REGION: Optional[str] = None
|
AWS_DEFAULT_REGION: Optional[str] = None
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
env_file = "backend.env"
|
env_file = "backend/.env"
|
||||||
|
|
||||||
|
|
||||||
@lru_cache()
|
@lru_cache()
|
||||||
def get_settings():
|
def get_settings():
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ db_string = connection_string.format(
|
||||||
|
|
||||||
db_engine = create_engine(db_string, pool_size=5, max_overflow=5)
|
db_engine = create_engine(db_string, pool_size=5, max_overflow=5)
|
||||||
|
|
||||||
|
|
||||||
def get_db_session():
|
def get_db_session():
|
||||||
if db_engine is None:
|
if db_engine is None:
|
||||||
raise RuntimeError("Database is not configured. Set DATABASE_URL in environment variables.")
|
raise RuntimeError("Database is not configured. Set DATABASE_URL in environment variables.")
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ def extract_property_request_data(
|
||||||
x for x in already_installed if
|
x for x in already_installed if
|
||||||
(x["address"] == config["address"]) and (x["postcode"] == config["postcode"])
|
(x["address"] == config["address"]) and (x["postcode"] == config["postcode"])
|
||||||
), [])
|
), [])
|
||||||
|
|
||||||
# Because we have some non-invasive recommendations that match on address and postcode, but not UPRN
|
# Because we have some non-invasive recommendations that match on address and postcode, but not UPRN
|
||||||
# we need to check existence of uprn
|
# we need to check existence of uprn
|
||||||
has_uprn = "uprn" in non_invasive_recommendations[0] if non_invasive_recommendations else False
|
has_uprn = "uprn" in non_invasive_recommendations[0] if non_invasive_recommendations else False
|
||||||
|
|
|
||||||
|
|
@ -392,6 +392,26 @@ def parse_heating_system(config):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def check_duplicate_uprns(plan_input):
|
||||||
|
"""
|
||||||
|
Simple function to check if the input data contains duplicated UPRNS.
|
||||||
|
If there are duplicates, an exception will be rasied
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
# Check for duplicate UPRNS
|
||||||
|
input_uprns = [x.get("uprn") for x in plan_input if "uprn" in x and x.get("uprn")]
|
||||||
|
|
||||||
|
if input_uprns:
|
||||||
|
# Check for dupes
|
||||||
|
if len(input_uprns) != len(set(input_uprns)):
|
||||||
|
# Find the duplicate UPRNs
|
||||||
|
duplicates = set([x for x in input_uprns if input_uprns.count(x) > 1])
|
||||||
|
# de-dupe input_uprns
|
||||||
|
raise ValueError(f"Duplicate UPRNs in the input data: {duplicates}")
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
async def model_engine(body: PlanTriggerRequest):
|
async def model_engine(body: PlanTriggerRequest):
|
||||||
logger.info("Model Engine triggered with body: %s", json.loads(body.model_dump_json()))
|
logger.info("Model Engine triggered with body: %s", json.loads(body.model_dump_json()))
|
||||||
|
|
||||||
|
|
@ -480,16 +500,8 @@ async def model_engine(body: PlanTriggerRequest):
|
||||||
if body.index_start is not None and body.index_end is not None:
|
if body.index_start is not None and body.index_end is not None:
|
||||||
plan_input = plan_input[body.index_start:body.index_end]
|
plan_input = plan_input[body.index_start:body.index_end]
|
||||||
|
|
||||||
# Check for duplicate UPRNS
|
# Confirm no duplicate UPRNS
|
||||||
input_uprns = [x.get("uprn") for x in plan_input if "uprn" in x and x.get("uprn")]
|
check_duplicate_uprns(plan_input)
|
||||||
|
|
||||||
if input_uprns:
|
|
||||||
# Check for dupes
|
|
||||||
if len(input_uprns) != len(set(input_uprns)):
|
|
||||||
# Find the duplicate UPRNs
|
|
||||||
duplicates = set([x for x in input_uprns if input_uprns.count(x) > 1])
|
|
||||||
# de-dupe input_uprns
|
|
||||||
raise ValueError(f"Duplicate UPRNs in the input data: {duplicates}")
|
|
||||||
|
|
||||||
# If we have patches or overrides, we should read them in here
|
# If we have patches or overrides, we should read them in here
|
||||||
patches, already_installed, non_invasive_recommendations, valuation_data = get_request_property_data(body)
|
patches, already_installed, non_invasive_recommendations, valuation_data = get_request_property_data(body)
|
||||||
|
|
@ -528,9 +540,7 @@ async def model_engine(body: PlanTriggerRequest):
|
||||||
if (body.event_type == "remote_assessment") and config.get("property_type") == "Flat":
|
if (body.event_type == "remote_assessment") and config.get("property_type") == "Flat":
|
||||||
# We're running a remote assessment for a flat - we go and grab the associated
|
# We're running a remote assessment for a flat - we go and grab the associated
|
||||||
# UPRNS for other units in the same building
|
# UPRNS for other units in the same building
|
||||||
associated_uprns = get_associated_uprns(
|
associated_uprns = get_associated_uprns(session, postcode=config["postcode"], uprn=uprn)
|
||||||
session, postcode=config["postcode"], uprn=uprn
|
|
||||||
)
|
|
||||||
|
|
||||||
epc_searcher = SearchEpc(
|
epc_searcher = SearchEpc(
|
||||||
address1=address1,
|
address1=address1,
|
||||||
|
|
@ -1140,6 +1150,7 @@ async def model_engine(body: PlanTriggerRequest):
|
||||||
)
|
)
|
||||||
property_value_increase_ranges[p.id] = valuations
|
property_value_increase_ranges[p.id] = valuations
|
||||||
|
|
||||||
|
# TODO - this is not right, especially if the existing run failed
|
||||||
if p.is_new:
|
if p.is_new:
|
||||||
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,
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,14 @@ archetypes = sustainability_data[
|
||||||
"Floor Area Band"]
|
"Floor Area Band"]
|
||||||
].drop_duplicates()
|
].drop_duplicates()
|
||||||
|
|
||||||
|
# Potential reductions:
|
||||||
|
# 1) Split roof insulation into > 100mm loft and <= 100mm loft
|
||||||
|
# 2) Group all of the glazed together (e.g. double glazed, secondary glazed, triple glazed)
|
||||||
|
# 3) Group up boiler efficiency A-C, D - F, G? or someting like this
|
||||||
|
# 4) Group up main fuel into gas, electric, oil, other?
|
||||||
|
# 5) Wall Construction - group up Sandstone and Granite into one category
|
||||||
|
# 6) Reduce or remove floor construction
|
||||||
|
|
||||||
# Maps the property types to the format recognised by the EPC api
|
# Maps the property types to the format recognised by the EPC api
|
||||||
property_type_map = {}
|
property_type_map = {}
|
||||||
# Maps the build form to the format recognised by the OS api
|
# Maps the build form to the format recognised by the OS api
|
||||||
|
|
|
||||||
|
|
@ -398,6 +398,7 @@ class RetrieveFindMyEpc:
|
||||||
extracted_address_cleaned = (
|
extracted_address_cleaned = (
|
||||||
extracted_address.replace(",", "").replace(" ", "").lower()
|
extracted_address.replace(",", "").replace(" ", "").lower()
|
||||||
)
|
)
|
||||||
|
|
||||||
if not extracted_address_cleaned.startswith(self.address_cleaned):
|
if not extracted_address_cleaned.startswith(self.address_cleaned):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue