diff --git a/packages/network/src/api/image/mappers.ts b/packages/network/src/api/image/mappers.ts index 44d757e0c..be4414853 100644 --- a/packages/network/src/api/image/mappers.ts +++ b/packages/network/src/api/image/mappers.ts @@ -217,5 +217,7 @@ export function mapApiImage( additionalData: image.additional_data, renderedOutputs: [], views: [], + odometer: image.odometer?.value, + warningLights: image.warning_lights?.activated_warning_lights, }; } diff --git a/packages/network/src/api/image/requests.ts b/packages/network/src/api/image/requests.ts index 699693341..4d3cdb2ee 100644 --- a/packages/network/src/api/image/requests.ts +++ b/packages/network/src/api/image/requests.ts @@ -285,7 +285,13 @@ function createBeautyShotImageData( const filename = `${options.sightId}-${options.inspectionId}-${Date.now()}.${filetype}`; const tasks = options.tasks.filter( (task) => - ![TaskName.COMPLIANCES, TaskName.HUMAN_IN_THE_LOOP, TaskName.IMAGES_OCR].includes(task), + ![ + TaskName.COMPLIANCES, + TaskName.HUMAN_IN_THE_LOOP, + TaskName.IMAGES_OCR, + TaskName.ODOMETER, + TaskName.WARNING_LIGHTS, + ].includes(task), ) as ApiImagePostTask[]; tasks.push({ name: TaskName.COMPLIANCES, @@ -305,6 +311,18 @@ function createBeautyShotImageData( image_details: { image_type: 'VIN' }, }); } + if (options.tasks.includes(TaskName.ODOMETER)) { + tasks.push({ + name: TaskName.ODOMETER, + wait_for_result: true, + }); + } + if (options.tasks.includes(TaskName.WARNING_LIGHTS)) { + tasks.push({ + name: TaskName.WARNING_LIGHTS, + wait_for_result: true, + }); + } const body: ApiImagePost = { acquisition: { diff --git a/packages/network/src/api/inspection/mappers.ts b/packages/network/src/api/inspection/mappers.ts index 30e001b36..e7637ed0c 100644 --- a/packages/network/src/api/inspection/mappers.ts +++ b/packages/network/src/api/inspection/mappers.ts @@ -43,6 +43,7 @@ import { ApiImagesOCRTaskPostComponent, ApiInspectionGet, ApiInspectionPost, + ApiOdometerTaskPostComponent, ApiPartSeverityValue, ApiPricingTaskPostComponent, ApiPricingV2, @@ -54,6 +55,7 @@ import { ApiTasksComponent, ApiView, type ApiViews, + ApiWarningLightsTaskPostComponent, ApiWheelAnalysisTaskPostComponent, } from '../models'; import { mapApiImage } from '../image/mappers'; @@ -601,6 +603,26 @@ function getPricingOptions( : undefined; } +function getOdometerOptions( + options: CreateInspectionOptions, +): ApiOdometerTaskPostComponent | undefined { + return options.tasks.includes(TaskName.ODOMETER) + ? { + status: ProgressStatus.NOT_STARTED, + } + : undefined; +} + +function getWarningLightsOptions( + options: CreateInspectionOptions, +): ApiWarningLightsTaskPostComponent | undefined { + return options.tasks.includes(TaskName.WARNING_LIGHTS) + ? { + status: ProgressStatus.NOT_STARTED, + } + : undefined; +} + function getTasksOptions(options: CreateInspectionOptions): ApiTasksComponent { return { damage_detection: getDamageDetectionOptions(options), @@ -608,6 +630,8 @@ function getTasksOptions(options: CreateInspectionOptions): ApiTasksComponent { images_ocr: getImagesOCROptions(options), human_in_the_loop: getHumanInTheLoopOptions(options), pricing: getPricingOptions(options), + odometer: getOdometerOptions(options), + warning_lights: getWarningLightsOptions(options), }; } diff --git a/packages/network/src/api/models/image.ts b/packages/network/src/api/models/image.ts index e48ae377a..7405ade90 100644 --- a/packages/network/src/api/models/image.ts +++ b/packages/network/src/api/models/image.ts @@ -1,4 +1,4 @@ -import { TranslationObject } from '@monkvision/types'; +import { MileageUnit, TranslationObject, WarningLights } from '@monkvision/types'; import type { ApiAdditionalData, ApiCenterOnElement, ApiLabelPrediction } from './common'; import type { ApiRenderedOutputs } from './renderedOutput'; import type { ApiImageComplianceResults } from './compliance'; @@ -8,6 +8,8 @@ import { ApiHinlTaskPost, ApiImageCompliancesTaskPost, ApiImagesOCRTaskPost, + ApiImagesOdometerTaskPost, + ApiImagesWarningLightsTaskPost, } from './task'; export type ApiImageType = 'unknown' | 'beauty_shot' | 'close_up'; @@ -35,6 +37,20 @@ export interface ApiImageAdditionalData extends ApiAdditionalData { label?: TranslationObject; } +export interface ApiImageOdometer { + unit?: MileageUnit; + value?: number; + confidence_score?: number; + error?: string; + rotation?: string; + visualization_url?: string; +} + +export interface ApiImageWarningLights { + activated_warning_lights: WarningLights[]; + light_to_score: Record; +} + export interface ApiImage { additional_data?: ApiImageAdditionalData; binary_size: number; @@ -51,6 +67,8 @@ export interface ApiImage { name?: string; path: string; viewpoint?: ApiLabelPrediction; + odometer?: ApiImageOdometer; + warning_lights?: ApiImageWarningLights; } export interface ApiImageWithViews extends ApiImage { @@ -85,21 +103,15 @@ export interface ApiCompliance { } export type ApiImagePostTask = - | Omit< + | Extract< ApiBusinessTaskName, - | 'repair_estimate' - | 'images_ocr' - | 'image_editing' - | 'inspection_pdf' - | 'pricing' - | 'zoom_level' - | 'coverage_360' - | 'iqa_compliance' - | 'human_in_the_loop' + 'damage_detection' | 'wheel_analysis' | 'dashboard_ocr' | 'compliances' > | ApiImageCompliancesTaskPost | ApiHinlTaskPost - | ApiImagesOCRTaskPost; + | ApiImagesOCRTaskPost + | ApiImagesOdometerTaskPost + | ApiImagesWarningLightsTaskPost; export interface ApiImagePost { acquisition: ApiAcquisition; diff --git a/packages/network/src/api/models/task.ts b/packages/network/src/api/models/task.ts index c229d6bfa..1f4c031a0 100644 --- a/packages/network/src/api/models/task.ts +++ b/packages/network/src/api/models/task.ts @@ -47,6 +47,16 @@ export interface ApiImagesOCRTaskPost { image_details: ApiImagesOCRImageDetails; } +export interface ApiImagesOdometerTaskPost { + name: 'odometer'; + wait_for_result?: boolean; +} + +export interface ApiImagesWarningLightsTaskPost { + name: 'warning_lights'; + wait_for_result?: boolean; +} + export type ApiTaskProgressStatus = | 'NOT_STARTED' | 'TODO' @@ -127,10 +137,20 @@ export interface ApiPricingTaskPostComponent { methodology?: ApiPricingMethodology; } +export interface ApiOdometerTaskPostComponent { + status?: ApiTaskPostProgressStatus; +} + +export interface ApiWarningLightsTaskPostComponent { + status?: ApiTaskPostProgressStatus; +} + export interface ApiTasksComponent { damage_detection?: ApiDamageDetectionTaskPostComponent; wheel_analysis?: ApiWheelAnalysisTaskPostComponent; images_ocr?: ApiImagesOCRTaskPostComponent; human_in_the_loop?: ApiHinlTaskPostComponent; pricing?: ApiPricingTaskPostComponent; + odometer?: ApiOdometerTaskPostComponent; + warning_lights?: ApiWarningLightsTaskPostComponent; } diff --git a/packages/network/test/api/image/requests.test.ts b/packages/network/test/api/image/requests.test.ts index 6ef809a16..c0e451f3c 100644 --- a/packages/network/test/api/image/requests.test.ts +++ b/packages/network/test/api/image/requests.test.ts @@ -50,7 +50,14 @@ function createBeautyShotImageOptions(): AddBeautyShotImageOptions { }, inspectionId: 'test-inspection-id', sightId: 'test-sight-1', - tasks: [TaskName.DAMAGE_DETECTION, TaskName.WHEEL_ANALYSIS, TaskName.HUMAN_IN_THE_LOOP], + tasks: [ + TaskName.DAMAGE_DETECTION, + TaskName.WHEEL_ANALYSIS, + TaskName.HUMAN_IN_THE_LOOP, + TaskName.IMAGES_OCR, + TaskName.ODOMETER, + TaskName.WARNING_LIGHTS, + ], compliance: { enableCompliance: true, complianceIssues: [ComplianceIssue.INTERIOR_NOT_SUPPORTED], @@ -292,7 +299,15 @@ describe('Image requests', () => { }, image_type: ImageType.BEAUTY_SHOT, tasks: [ - ...options.tasks.filter((task) => task !== TaskName.HUMAN_IN_THE_LOOP), + ...options.tasks.filter( + (task) => + ![ + TaskName.HUMAN_IN_THE_LOOP, + TaskName.IMAGES_OCR, + TaskName.ODOMETER, + TaskName.WARNING_LIGHTS, + ].includes(task), + ), { name: TaskName.COMPLIANCES, image_details: { sight_id: options.sightId }, @@ -301,6 +316,18 @@ describe('Image requests', () => { name: TaskName.HUMAN_IN_THE_LOOP, image_details: { sight_label: sights[options.sightId].label }, }, + { + name: TaskName.IMAGES_OCR, + image_details: { image_type: 'VIN' }, + }, + { + name: TaskName.ODOMETER, + wait_for_result: true, + }, + { + name: TaskName.WARNING_LIGHTS, + wait_for_result: true, + }, ], additional_data: { sight_id: options.sightId, diff --git a/packages/types/src/state/image.ts b/packages/types/src/state/image.ts index b06be2606..345ad5a83 100644 --- a/packages/types/src/state/image.ts +++ b/packages/types/src/state/image.ts @@ -103,6 +103,32 @@ export interface Viewpoint { centersOn?: (VehiclePart | CentersOnElement)[]; } +export const WARNING_LIGHTS = { + CEL: 'CEL', + AIRBAGS: 'Airbags', + ABS: 'ABS', + TCS: 'TCS', + BATTERY: 'Battery', + TPMS: 'TPMS', + MAINT: 'Maint', + INFO: 'Info', + BRAKE: 'brake', + OTHER: 'Other', + DRIVETRAIN: 'DriveTrain', + LIGHTS: 'Lights', + STEERING: 'Steering', + OIL: 'oil', + COOLANT: 'Coolant', + SECONDARY: 'Secondary', + SUSPENSION: 'Suspension', + TRANSMISSION: 'Transmission', +} as const; + +/** + * Enumeration of the warning lights that can be detected in an image. + */ +export type WarningLights = (typeof WARNING_LIGHTS)[keyof typeof WARNING_LIGHTS]; + /** * Enumeration of the possible statuses of an inspection image. */ @@ -513,4 +539,12 @@ export interface Image extends MonkEntity { * Additional data added during the upload of the image. */ additionalData?: ImageAdditionalData; + /** + * The odometer value of the vehicle in the image. + */ + odometer?: number; + /** + * The warning lights detected in the image. + */ + warningLights?: WarningLights[]; } diff --git a/packages/types/src/state/task.ts b/packages/types/src/state/task.ts index 97a69a541..bab38e181 100644 --- a/packages/types/src/state/task.ts +++ b/packages/types/src/state/task.ts @@ -50,6 +50,14 @@ export enum TaskName { * damages are detected they are sent to an annotator that will review them and edit them if needed. */ HUMAN_IN_THE_LOOP = 'human_in_the_loop', + /** + * The odometer task is used to estimate the mileage of the vehicle. + */ + ODOMETER = 'odometer', + /** + * The warning lights task is used to detect the presence of warning lights on the vehicle. + */ + WARNING_LIGHTS = 'warning_lights', } /**