feat(api): add POST /avm/industrial endpoint for industrial rent estimation
Wire NestJS controller to Python AI service's industrial AVM. Adds CQRS query/handler, Swagger-annotated DTOs, AI client method, and 7 unit tests covering parameter mapping, response camelCase conversion, and error handling. Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
@@ -23,6 +23,55 @@ export interface AiPredictResponse {
|
||||
price_range_high: number;
|
||||
}
|
||||
|
||||
export interface AiIndustrialPredictRequest {
|
||||
province: string;
|
||||
region: string;
|
||||
park_occupancy_rate: number;
|
||||
park_area_ha: number;
|
||||
park_age_years: number;
|
||||
distance_to_port_km: number;
|
||||
distance_to_airport_km: number;
|
||||
distance_to_highway_km: number;
|
||||
property_type: string;
|
||||
area_m2: number;
|
||||
ceiling_height_m?: number;
|
||||
floor_load_ton_m2?: number;
|
||||
power_capacity_kva?: number;
|
||||
building_coverage?: number;
|
||||
loading_docks?: number;
|
||||
zoning?: string;
|
||||
industry_demand_index?: number;
|
||||
fdi_province_musd?: number;
|
||||
labor_cost_province_vnd?: number;
|
||||
logistics_connectivity_score?: number;
|
||||
}
|
||||
|
||||
export interface AiIndustrialComparable {
|
||||
park_name: string;
|
||||
province: string;
|
||||
property_type: string;
|
||||
area_m2: number;
|
||||
rent_usd_m2: number;
|
||||
similarity_score: number;
|
||||
}
|
||||
|
||||
export interface AiIndustrialFeatureImportance {
|
||||
feature: string;
|
||||
importance: number;
|
||||
}
|
||||
|
||||
export interface AiIndustrialPredictResponse {
|
||||
estimated_rent_usd_m2: number;
|
||||
confidence: number;
|
||||
rent_range_low_usd_m2: number;
|
||||
rent_range_high_usd_m2: number;
|
||||
annual_rent_usd_m2: number;
|
||||
total_monthly_rent_usd: number;
|
||||
comparables: AiIndustrialComparable[];
|
||||
drivers: AiIndustrialFeatureImportance[];
|
||||
model_version: string;
|
||||
}
|
||||
|
||||
export interface AiModerationRequest {
|
||||
text: string;
|
||||
context?: string;
|
||||
@@ -46,6 +95,7 @@ export const AI_SERVICE_CLIENT = Symbol('AI_SERVICE_CLIENT');
|
||||
|
||||
export interface IAiServiceClient {
|
||||
predict(req: AiPredictRequest): Promise<AiPredictResponse>;
|
||||
predictIndustrial(req: AiIndustrialPredictRequest): Promise<AiIndustrialPredictResponse>;
|
||||
moderate(req: AiModerationRequest): Promise<AiModerationResponse>;
|
||||
isAvailable(): Promise<boolean>;
|
||||
}
|
||||
@@ -66,6 +116,10 @@ export class AiServiceClient implements IAiServiceClient {
|
||||
return this.post<AiPredictResponse>('/avm/predict', req);
|
||||
}
|
||||
|
||||
async predictIndustrial(req: AiIndustrialPredictRequest): Promise<AiIndustrialPredictResponse> {
|
||||
return this.post<AiIndustrialPredictResponse>('/avm/industrial/predict', req);
|
||||
}
|
||||
|
||||
async moderate(req: AiModerationRequest): Promise<AiModerationResponse> {
|
||||
return this.post<AiModerationResponse>('/moderation/check', req);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user