Merge branch 'main' of https://github.com/Hestia-Homes/Model into bug/plan-with-budget-more-expensive

# Conflicts:
#	asset_list/app.py
This commit is contained in:
Khalim Conn-Kowlessar 2026-02-18 17:44:29 +00:00
commit 627d4c1c18
12 changed files with 1843 additions and 938 deletions

View file

@ -1,11 +1,6 @@
name: Run unit tests name: Run unit tests
on: on:
push:
branches:
- "main"
- "dev"
- "prod"
pull_request: pull_request:
branches: branches:
- "**" - "**"

File diff suppressed because it is too large Load diff

View file

@ -18,6 +18,7 @@ EPC_AUTH_TOKEN = os.getenv(
"EPC_AUTH_TOKEN", "EPC_AUTH_TOKEN",
) )
OPENAI_API_KEY = os.getenv( OPENAI_API_KEY = os.getenv(
"OPENAI_API_KEY", "OPENAI_API_KEY",
) )
@ -73,7 +74,7 @@ def app():
Property UPRN Property UPRN
""" """
data_folder = "/Users/khalimconn-kowlessar/Downloads" data_folder = "/workspaces/model/asset_list"
data_filename = "assests.xlsx" data_filename = "assests.xlsx"
sheet_name = "Sheet1" sheet_name = "Sheet1"
postcode_column = "Postcode" postcode_column = "Postcode"
@ -242,7 +243,7 @@ def app():
if skip is not None and not force_retrieve_data: if skip is not None and not force_retrieve_data:
if i <= skip: if i <= skip:
continue continue
chunk = asset_list.standardised_asset_list[i: i + chunk_size] chunk = asset_list.standardised_asset_list[i : i + chunk_size]
epc_data_chunk, errors_chunk, no_epc_chunk = get_data( epc_data_chunk, errors_chunk, no_epc_chunk = get_data(
df=chunk, df=chunk,
row_id_name=asset_list.DOMNA_PROPERTY_ID, row_id_name=asset_list.DOMNA_PROPERTY_ID,
@ -385,7 +386,7 @@ def app():
# Retrieve just the data we need # Retrieve just the data we need
epc_df = epc_df[ epc_df = epc_df[
[asset_list.DOMNA_PROPERTY_ID] + list(asset_list.EPC_API_DATA_NAMES.keys()) [asset_list.DOMNA_PROPERTY_ID] + list(asset_list.EPC_API_DATA_NAMES.keys())
].rename(columns=asset_list.EPC_API_DATA_NAMES) ].rename(columns=asset_list.EPC_API_DATA_NAMES)
# Look for columns not in the find my EPC data, which will have happened if we didn't # Look for columns not in the find my EPC data, which will have happened if we didn't
# retrieve it in the first place # retrieve it in the first place
@ -402,7 +403,7 @@ def app():
find_my_epc_data[ find_my_epc_data[
[asset_list.DOMNA_PROPERTY_ID, "epc_has_floor_recommendation"] [asset_list.DOMNA_PROPERTY_ID, "epc_has_floor_recommendation"]
+ list(asset_list.FIND_EPC_DATA_NAMES.keys()) + list(asset_list.FIND_EPC_DATA_NAMES.keys())
].rename(columns=asset_list.FIND_EPC_DATA_NAMES), ].rename(columns=asset_list.FIND_EPC_DATA_NAMES),
how="left", how="left",
on=asset_list.DOMNA_PROPERTY_ID, on=asset_list.DOMNA_PROPERTY_ID,
) )

View file

@ -5,7 +5,7 @@ epc-api-python==1.0.2
thefuzz thefuzz
boto3 boto3
openpyxl openpyxl
openai>=1.3.5 openai==1.93.0
tiktoken tiktoken
msgpack msgpack
beautifulsoup4 beautifulsoup4

View file

@ -33,6 +33,8 @@ module "lambda" {
image_uri = local.image_uri image_uri = local.image_uri
# Optional: Set maximum_concurrency to limit concurrent SQS-triggered invocations (2-1000)
maximum_concurrency = var.maximum_concurrency
environment = { environment = {
STAGE = var.stage STAGE = var.stage

View file

@ -17,6 +17,11 @@ variable "image_digest" {
description = "Image digest (sha256:...)" description = "Image digest (sha256:...)"
} }
variable "maximum_concurrency" {
type = number
default = null
description = "Maximum number of concurrent Lambda invocations from SQS (2-1000). null = no limit."
}
locals { locals {
image_uri = "${var.ecr_repo_url}@${var.image_digest}" image_uri = "${var.ecr_repo_url}@${var.image_digest}"

View file

@ -24,6 +24,9 @@ module "address2uprn" {
timeout = 900 timeout = 900
# Optional: Set maximum_concurrency to limit concurrent SQS-triggered invocations (2-1000)
maximum_concurrency = var.maximum_concurrency
environment = merge( environment = merge(
{ {
STAGE = var.stage STAGE = var.stage

View file

@ -17,6 +17,11 @@ variable "image_digest" {
description = "Image digest (sha256:...)" description = "Image digest (sha256:...)"
} }
variable "maximum_concurrency" {
type = number
default = 10 # null if you don't want to set it for this handler
description = "Maximum number of concurrent Lambda invocations from SQS (2-1000). null = no limit."
}
locals { locals {
image_uri = "${var.ecr_repo_url}@${var.image_digest}" image_uri = "${var.ecr_repo_url}@${var.image_digest}"

View file

@ -44,5 +44,6 @@ module "sqs_trigger" {
lambda_role_name = module.role.role_name lambda_role_name = module.role.role_name
queue_arn = module.queue.queue_arn queue_arn = module.queue.queue_arn
batch_size = var.batch_size batch_size = var.batch_size
maximum_concurrency = var.maximum_concurrency
} }

View file

@ -34,3 +34,9 @@ variable "batch_size" {
type = number type = number
default = 10 default = 10
} }
variable "maximum_concurrency" {
type = number
default = null
description = "Maximum number of concurrent Lambda invocations from SQS. null = no limit."
}

View file

@ -3,6 +3,13 @@ resource "aws_lambda_event_source_mapping" "this" {
function_name = var.lambda_arn function_name = var.lambda_arn
batch_size = var.batch_size batch_size = var.batch_size
enabled = true enabled = true
dynamic "scaling_config" {
for_each = var.maximum_concurrency != null ? [1] : []
content {
maximum_concurrency = var.maximum_concurrency
}
}
} }
resource "aws_iam_role_policy" "allow_sqs" { resource "aws_iam_role_policy" "allow_sqs" {

View file

@ -6,3 +6,9 @@ variable "batch_size" {
type = number type = number
default = 10 default = 10
} }
variable "maximum_concurrency" {
type = number
default = null
description = "Maximum number of concurrent Lambda invocations from SQS. null = no limit."
}