Files
goodgo-platform/libs/ai-services/app/models/avm_industrial.py
Ho Ngoc Hai 13bd76ac5d feat(ai-services): add building_coverage, loading_docks, zoning to industrial AVM
Completes the industrial-specific feature set required for AVM industrial
valuation. Adds heuristic adjustments for all three new features and
4 new tests covering zoning premiums, loading docks, and coverage ratio.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-16 17:06:27 +07:00

115 lines
4.1 KiB
Python

from pydantic import BaseModel, Field
class IndustrialAVMRequest(BaseModel):
"""Request schema for industrial property rent estimation."""
province: str = Field(..., min_length=1, description="Province name (e.g. Bình Dương)")
region: str = Field(
..., min_length=1, description="Region: south, north, central, mekong_delta"
)
park_occupancy_rate: float = Field(
..., ge=0, le=1, description="Industrial park occupancy rate (0-1)"
)
park_area_ha: float = Field(..., gt=0, description="Total park area in hectares")
park_age_years: int = Field(..., ge=0, description="Industrial park age in years")
distance_to_port_km: float = Field(
..., ge=0, description="Distance to nearest seaport in km"
)
distance_to_airport_km: float = Field(
..., ge=0, description="Distance to nearest airport in km"
)
distance_to_highway_km: float = Field(
..., ge=0, description="Distance to nearest highway in km"
)
property_type: str = Field(
...,
description="Industrial property type: warehouse, factory, ready_built_factory, "
"ready_built_warehouse, open_yard, office_in_park",
)
area_m2: float = Field(..., gt=0, description="Leasable area in m²")
ceiling_height_m: float = Field(
0.0, ge=0, description="Ceiling/clear height in meters"
)
floor_load_ton_m2: float = Field(
0.0, ge=0, description="Floor load capacity in tons/m²"
)
power_capacity_kva: float = Field(
0.0, ge=0, description="Allocated power capacity in kVA"
)
building_coverage: float = Field(
0.0,
ge=0,
le=1,
description="Building coverage ratio — footprint area / lot area (0-1)",
)
loading_docks: int = Field(
0, ge=0, description="Number of loading docks / bays"
)
zoning: str = Field(
"general_industrial",
description="Industrial zoning category: general_industrial, heavy_industrial, "
"light_industrial, logistics, free_trade_zone, high_tech",
)
industry_demand_index: float = Field(
0.5, ge=0, le=1, description="Local industry demand index (0-1)"
)
fdi_province_musd: float = Field(
0.0, ge=0, description="Province FDI inflow in million USD (trailing 12 months)"
)
labor_cost_province_vnd: float = Field(
0.0, ge=0, description="Average province labor cost in VND/month"
)
logistics_connectivity_score: float = Field(
0.5, ge=0, le=1, description="Logistics connectivity score (0-1)"
)
class IndustrialComparable(BaseModel):
"""A comparable industrial property used for the estimation."""
park_name: str
province: str
property_type: str
area_m2: float
rent_usd_m2: float
similarity_score: float = Field(..., ge=0, le=1)
class FeatureImportance(BaseModel):
"""Feature importance from the model prediction."""
feature: str
importance: float = Field(..., ge=0, le=1)
class IndustrialAVMResponse(BaseModel):
"""Response schema for industrial property rent estimation."""
estimated_rent_usd_m2: float = Field(
..., description="Estimated monthly rent in USD per m²"
)
confidence: float = Field(
..., ge=0, le=1, description="Prediction confidence score"
)
rent_range_low_usd_m2: float = Field(
..., description="Lower bound rent estimate in USD/m²"
)
rent_range_high_usd_m2: float = Field(
..., description="Upper bound rent estimate in USD/m²"
)
annual_rent_usd_m2: float = Field(
..., description="Estimated annual rent in USD/m²"
)
total_monthly_rent_usd: float = Field(
..., description="Total monthly rent for the requested area in USD"
)
comparables: list[IndustrialComparable] = Field(
default_factory=list, description="Similar industrial properties for reference"
)
drivers: list[FeatureImportance] = Field(
default_factory=list,
description="Top feature drivers for this prediction",
)
model_version: str = Field("heuristic-v1", description="Model version used")