Skip to content

Commit

Permalink
Added custom compliance thresholds logic
Browse files Browse the repository at this point in the history
  • Loading branch information
souyahia-monk committed May 10, 2024
1 parent 70396d5 commit e4c8170
Show file tree
Hide file tree
Showing 7 changed files with 431 additions and 105 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,11 @@ export function useInspectionGalleryItems(props: InspectionGalleryProps): Inspec
? {
enableCompliance: props.enableCompliance,
enableCompliancePerSight: props.enableCompliancePerSight,
useLiveCompliance: props.useLiveCompliance,
complianceIssues: props.complianceIssues,
complianceIssuesPerSight: props.complianceIssuesPerSight,
useLiveCompliance: props.useLiveCompliance,
customComplianceThresholds: props.customComplianceThresholds,
customComplianceThresholdsPerSight: props.customComplianceThresholdsPerSight,
}
: undefined,
delay: shouldFetch ? props.refreshIntervalMs ?? DEFAULT_REFRESH_INTERVAL_MS : null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ export function PhotoCapture({
enableCompliancePerSight,
complianceIssues,
complianceIssuesPerSight,
customComplianceThresholds,
customComplianceThresholdsPerSight,
useLiveCompliance = false,
allowSkipRetake = false,
enableAddDamage = true,
Expand All @@ -135,6 +137,8 @@ export function PhotoCapture({
complianceIssues,
complianceIssuesPerSight,
useLiveCompliance,
customComplianceThresholds,
customComplianceThresholdsPerSight,
});
const { t } = useTranslation();
const { handleError } = useMonitoring();
Expand Down Expand Up @@ -255,15 +259,11 @@ export function PhotoCapture({
showBackButton={true}
sights={sights}
allowSkipRetake={allowSkipRetake}
enableCompliance={enableCompliance}
enableCompliancePerSight={enableCompliancePerSight}
complianceIssues={complianceIssues}
complianceIssuesPerSight={complianceIssuesPerSight}
useLiveCompliance={useLiveCompliance}
onBack={handleGalleryBack}
onNavigateToCapture={handleNavigateToCapture}
onValidate={handleGalleryValidate}
enableAddDamage={enableAddDamage}
{...complianceOptions}
/>
)}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,11 @@ function createProps(): PhotoCaptureProps {
apiConfig: { apiDomain: 'test-api-domain-test', authToken: 'test-auth-token-test' },
enableCompliance: true,
enableCompliancePerSight: ['test-sight-id'],
useLiveCompliance: true,
complianceIssues: [ComplianceIssue.INTERIOR_NOT_SUPPORTED],
complianceIssuesPerSight: { test: [ComplianceIssue.OVEREXPOSURE] },
useLiveCompliance: true,
customComplianceThresholds: { blurriness: 0.3 },
customComplianceThresholdsPerSight: { test: { overexposure: 0.6 } },
onClose: jest.fn(),
onComplete: jest.fn(),
resolution: CameraResolution.NHD_360P,
Expand Down Expand Up @@ -112,9 +114,11 @@ describe('PhotoCapture component', () => {
complianceOptions: {
enableCompliance: props.enableCompliance,
enableCompliancePerSight: props.enableCompliancePerSight,
useLiveCompliance: props.useLiveCompliance,
complianceIssues: props.complianceIssues,
complianceIssuesPerSight: props.complianceIssuesPerSight,
useLiveCompliance: props.useLiveCompliance,
customComplianceThresholds: props.customComplianceThresholds,
customComplianceThresholdsPerSight: props.customComplianceThresholdsPerSight,
},
});

Expand All @@ -134,6 +138,8 @@ describe('PhotoCapture component', () => {
complianceIssues: props.complianceIssues,
complianceIssuesPerSight: props.complianceIssuesPerSight,
useLiveCompliance: props.useLiveCompliance,
customComplianceThresholds: props.customComplianceThresholds,
customComplianceThresholdsPerSight: props.customComplianceThresholdsPerSight,
},
});

Expand Down Expand Up @@ -260,9 +266,11 @@ describe('PhotoCapture component', () => {
allowSkipRetake: props.allowSkipRetake,
enableCompliance: props.enableCompliance,
enableCompliancePerSight: props.enableCompliancePerSight,
useLiveCompliance: props.useLiveCompliance,
complianceIssues: props.complianceIssues,
complianceIssuesPerSight: props.complianceIssuesPerSight,
useLiveCompliance: props.useLiveCompliance,
customComplianceThresholds: props.customComplianceThresholds,
customComplianceThresholdsPerSight: props.customComplianceThresholdsPerSight,
onBack: expect.any(Function),
onNavigateToCapture: expect.any(Function),
onValidate: expect.any(Function),
Expand Down
143 changes: 121 additions & 22 deletions packages/network/src/api/image/mappers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
COMPLIANCE_ISSUES_PRIORITY,
ComplianceIssue,
ComplianceOptions,
CustomComplianceThresholds,
DEFAULT_COMPLIANCE_ISSUES,
Image,
ImageStatus,
Expand All @@ -18,26 +19,13 @@ const DEFAULT_COMPLIANCE_OPTIONS = {
complianceIssues: DEFAULT_COMPLIANCE_ISSUES,
};

function filterCompliances(
issues: string[] | undefined,
validIssues: ComplianceIssue[],
): ComplianceIssue[] {
return (
(issues as ComplianceIssue[] | undefined)?.filter((issue) => validIssues.includes(issue)) ?? []
);
}

function compareComplianceIssues(a: ComplianceIssue, b: ComplianceIssue): number {
return COMPLIANCE_ISSUES_PRIORITY.indexOf(a) - COMPLIANCE_ISSUES_PRIORITY.indexOf(b);
}

function mapCompliance(
function getActiveComplianceOptions(
sightId?: string,
complianceResult?: ApiImageComplianceResults,
complianceOptions?: ComplianceOptions,
): {
status: ImageStatus;
complianceIssues?: ComplianceIssue[];
enableCompliance: boolean;
complianceIssues: ComplianceIssue[];
customComplianceThresholds?: CustomComplianceThresholds;
} {
const enableComplianceGlobal =
complianceOptions?.enableCompliance ?? DEFAULT_COMPLIANCE_OPTIONS.enableCompliance;
Expand All @@ -51,19 +39,130 @@ function mapCompliance(
sightId && complianceOptions?.complianceIssuesPerSight?.[sightId]
? complianceOptions.complianceIssuesPerSight[sightId]
: complianceIssuesGlobal;
const customComplianceThresholds = sightId
? complianceOptions?.customComplianceThresholdsPerSight?.[sightId]
: complianceOptions?.customComplianceThresholds;
return { enableCompliance, complianceIssues, customComplianceThresholds };
}

function getComplianceIssue(
thresholdName: keyof CustomComplianceThresholds,
): ComplianceIssue | undefined {
switch (thresholdName) {
case 'blurriness':
return ComplianceIssue.BLURRINESS;
case 'overexposure':
return ComplianceIssue.OVEREXPOSURE;
case 'underexposure':
return ComplianceIssue.UNDEREXPOSURE;
case 'lensFlare':
return ComplianceIssue.LENS_FLARE;
case 'wetness':
return ComplianceIssue.WETNESS;
case 'snowness':
return ComplianceIssue.SNOWNESS;
case 'dirtiness':
return ComplianceIssue.DIRTINESS;
case 'reflections':
return ComplianceIssue.REFLECTIONS;
default:
return undefined;
}
}

function getComplianceScore(
thresholdName: keyof CustomComplianceThresholds,
complianceResult?: ApiImageComplianceResults,
): number | undefined {
switch (thresholdName) {
case 'blurriness':
return complianceResult?.image_analysis?.blurriness;
case 'overexposure':
return complianceResult?.image_analysis?.overexposure;
case 'underexposure':
return complianceResult?.image_analysis?.underexposure;
case 'lensFlare':
return complianceResult?.image_analysis?.lens_flare;
case 'wetness':
return complianceResult?.vehicle_analysis?.wetness;
case 'snowness':
return complianceResult?.vehicle_analysis?.snowness;
case 'dirtiness':
return complianceResult?.vehicle_analysis?.dirtiness;
case 'reflections':
return complianceResult?.vehicle_analysis?.reflections;
case 'zoom':
return complianceResult?.image_analysis?.zoom;
default:
return undefined;
}
}

function applycustomComplianceThresholds(
issues: string[] | undefined,
complianceResult: ApiImageComplianceResults,
customComplianceThresholds?: CustomComplianceThresholds,
): string[] {
let complianceIssues = issues ?? [];
if (!customComplianceThresholds) {
return complianceIssues;
}
Object.keys(customComplianceThresholds).forEach((key) => {
const thresholdName = key as keyof CustomComplianceThresholds;
const complianceScore = getComplianceScore(thresholdName, complianceResult);
if (thresholdName === 'zoom' && complianceScore && customComplianceThresholds.zoom) {
complianceIssues = (complianceIssues as ComplianceIssue[]).filter(
(issue) => ![ComplianceIssue.TOO_ZOOMED, ComplianceIssue.NOT_ZOOMED_ENOUGH].includes(issue),
);
if (complianceScore < customComplianceThresholds.zoom.min) {
complianceIssues.push(ComplianceIssue.TOO_ZOOMED);
} else if (complianceScore > customComplianceThresholds.zoom.max) {
complianceIssues.push(ComplianceIssue.NOT_ZOOMED_ENOUGH);
}
return;
}
const customThreshold = customComplianceThresholds[thresholdName];
const complianceIssue = getComplianceIssue(thresholdName);
if (complianceScore && complianceIssue && customThreshold !== undefined) {
complianceIssues = complianceIssues.filter((issue) => issue !== complianceIssue);
if (complianceScore < customThreshold) {
complianceIssues.push(complianceIssue);
}
}
});
return complianceIssues;
}

function filterCompliances(issues: string[], validIssues: ComplianceIssue[]): ComplianceIssue[] {
return (issues as ComplianceIssue[]).filter((issue) => validIssues.includes(issue));
}

function compareComplianceIssues(a: ComplianceIssue, b: ComplianceIssue): number {
return COMPLIANCE_ISSUES_PRIORITY.indexOf(a) - COMPLIANCE_ISSUES_PRIORITY.indexOf(b);
}

function mapCompliance(
sightId?: string,
complianceResult?: ApiImageComplianceResults,
complianceOptions?: ComplianceOptions,
): {
status: ImageStatus;
complianceIssues?: ComplianceIssue[];
} {
const { enableCompliance, complianceIssues, customComplianceThresholds } =
getActiveComplianceOptions(sightId, complianceOptions);
if (!enableCompliance) {
return { status: ImageStatus.SUCCESS };
}
if (!complianceResult) {
return { status: ImageStatus.COMPLIANCE_RUNNING };
}
if (!complianceResult.should_retake) {
return { status: ImageStatus.SUCCESS };
}
const filteredCompliances = filterCompliances(
const newIssuesAfterCustomThresholds = applycustomComplianceThresholds(
complianceResult.compliance_issues,
complianceIssues,
complianceResult,
customComplianceThresholds,
);
const filteredCompliances = filterCompliances(newIssuesAfterCustomThresholds, complianceIssues);
if (filteredCompliances.length === 0) {
return { status: ImageStatus.SUCCESS };
}
Expand Down
22 changes: 22 additions & 0 deletions packages/network/src/api/models/compliance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,27 @@ export interface ApiZoomLevelComplianceResult {

export interface ApiVehicleAnalysis {
is_vehicle_present: boolean;
wetness?: number;
snowness?: number;
dirtiness?: number;
reflections?: number;
}

export type ApiImageOrientation = 'other' | 'landscape' | 'portrait';

export type ApiPredictedImageType = 'unknown' | 'beauty_shot' | 'close_up';

export interface ApiImageAnalysis {
binary_size: number;
image_height: number;
image_width: number;
orientation: ApiImageOrientation;
predicted_image_type: ApiPredictedImageType;
zoom?: number;
blurriness?: number;
overexposure?: number;
underexposure?: number;
lens_flare?: number;
}

export interface ApiImageComplianceResults {
Expand All @@ -42,6 +63,7 @@ export interface ApiImageComplianceResults {
image_quality_assessment?: ApiIQAComplianceResult;
zoom_level?: ApiZoomLevelComplianceResult;
vehicle_analysis?: ApiVehicleAnalysis;
image_analysis?: ApiImageAnalysis;
compliance_issues?: string[];
should_retake?: boolean;
}
Loading

0 comments on commit e4c8170

Please sign in to comment.