Skip to content

Commit 903e0e1

Browse files
authored
[Job Launcher] Implemented image polygons job type (#2845)
* Implemented image polygons job type * Removed console.log
1 parent a8b0f9b commit 903e0e1

File tree

9 files changed

+167
-1
lines changed

9 files changed

+167
-1
lines changed

packages/apps/job-launcher/client/src/components/Jobs/Create/CvatJobRequestForm.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,9 @@ export const CvatJobRequestForm = () => {
239239
onBlur={handleBlur}
240240
>
241241
<MenuItem value={CvatJobType.IMAGE_POINTS}>Points</MenuItem>
242+
<MenuItem value={CvatJobType.IMAGE_POLYGONS}>
243+
Polygons
244+
</MenuItem>
242245
<MenuItem value={CvatJobType.IMAGE_BOXES}>
243246
Bounding Boxes
244247
</MenuItem>

packages/apps/job-launcher/client/src/types/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ export enum JobType {
7777

7878
export enum CvatJobType {
7979
IMAGE_POINTS = 'image_points',
80+
IMAGE_POLYGONS = 'image_polygons',
8081
IMAGE_BOXES = 'image_boxes',
8182
IMAGE_BOXES_FROM_POINTS = 'image_boxes_from_points',
8283
IMAGE_SKELETONS_FROM_BOXES = 'image_skeletons_from_boxes',

packages/apps/job-launcher/server/src/common/constants/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export const SENDGRID_API_KEY_DISABLED = 'sendgrid-disabled';
3333
export const HEADER_SIGNATURE_KEY = 'human-signature';
3434

3535
export const CVAT_JOB_TYPES = [
36+
JobRequestType.IMAGE_POLYGONS,
3637
JobRequestType.IMAGE_BOXES,
3738
JobRequestType.IMAGE_POINTS,
3839
JobRequestType.IMAGE_BOXES_FROM_POINTS,

packages/apps/job-launcher/server/src/common/enums/job.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export enum JobSortField {
2727

2828
export enum JobRequestType {
2929
IMAGE_POINTS = 'image_points',
30+
IMAGE_POLYGONS = 'image_polygons',
3031
IMAGE_BOXES = 'image_boxes',
3132
IMAGE_BOXES_FROM_POINTS = 'image_boxes_from_points',
3233
IMAGE_SKELETONS_FROM_BOXES = 'image_skeletons_from_boxes',

packages/apps/job-launcher/server/src/common/utils/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,8 @@ export const mapJobType = (requestType: JobRequestType): string => {
121121
switch (requestType) {
122122
case JobRequestType.IMAGE_POINTS:
123123
return 'Points';
124+
case JobRequestType.IMAGE_POLYGONS:
125+
return 'Polygons';
124126
case JobRequestType.IMAGE_BOXES:
125127
return 'Bounding Boxes';
126128
case JobRequestType.IMAGE_BOXES_FROM_POINTS:

packages/apps/job-launcher/server/src/common/utils/storage.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ export function generateBucketUrl(
1212
jobType: JobRequestType,
1313
): URL {
1414
if (
15-
(jobType === JobRequestType.IMAGE_BOXES ||
15+
(jobType === JobRequestType.IMAGE_POLYGONS ||
16+
jobType === JobRequestType.IMAGE_BOXES ||
1617
jobType === JobRequestType.IMAGE_POINTS ||
1718
jobType === JobRequestType.IMAGE_BOXES_FROM_POINTS ||
1819
jobType === JobRequestType.IMAGE_SKELETONS_FROM_BOXES) &&
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { MigrationInterface, QueryRunner } from 'typeorm';
2+
3+
export class AddJobTypeToJobsRequestTypeEnum1732612497937
4+
implements MigrationInterface
5+
{
6+
name = 'AddJobTypeToJobsRequestTypeEnum1732612497937';
7+
8+
public async up(queryRunner: QueryRunner): Promise<void> {
9+
await queryRunner.query(`
10+
ALTER TYPE "hmt"."jobs_request_type_enum"
11+
RENAME TO "jobs_request_type_enum_old"
12+
`);
13+
await queryRunner.query(`
14+
CREATE TYPE "hmt"."jobs_request_type_enum" AS ENUM(
15+
'image_points',
16+
'image_polygons',
17+
'image_boxes',
18+
'image_boxes_from_points',
19+
'image_skeletons_from_boxes',
20+
'hcaptcha',
21+
'fortune'
22+
)
23+
`);
24+
await queryRunner.query(`
25+
ALTER TABLE "hmt"."jobs"
26+
ALTER COLUMN "request_type" TYPE "hmt"."jobs_request_type_enum" USING "request_type"::"text"::"hmt"."jobs_request_type_enum"
27+
`);
28+
await queryRunner.query(`
29+
DROP TYPE "hmt"."jobs_request_type_enum_old"
30+
`);
31+
}
32+
33+
public async down(queryRunner: QueryRunner): Promise<void> {
34+
await queryRunner.query(`
35+
CREATE TYPE "hmt"."jobs_request_type_enum_old" AS ENUM(
36+
'image_points',
37+
'image_boxes',
38+
'image_boxes_from_points',
39+
'image_skeletons_from_boxes',
40+
'hcaptcha',
41+
'fortune'
42+
)
43+
`);
44+
await queryRunner.query(`
45+
ALTER TABLE "hmt"."jobs"
46+
ALTER COLUMN "request_type" TYPE "hmt"."jobs_request_type_enum_old" USING "request_type"::"text"::"hmt"."jobs_request_type_enum_old"
47+
`);
48+
await queryRunner.query(`
49+
DROP TYPE "hmt"."jobs_request_type_enum"
50+
`);
51+
await queryRunner.query(`
52+
ALTER TYPE "hmt"."jobs_request_type_enum_old"
53+
RENAME TO "jobs_request_type_enum"
54+
`);
55+
}
56+
}

packages/apps/job-launcher/server/src/modules/job/job.service.spec.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,53 @@ describe('JobService', () => {
674674
});
675675
});
676676

677+
it('should create a valid CVAT manifest for image polygons job type', async () => {
678+
const jobBounty = '100';
679+
jest
680+
.spyOn(jobService, 'calculateJobBounty')
681+
.mockResolvedValueOnce(jobBounty);
682+
683+
const dto: JobCvatDto = {
684+
data: MOCK_CVAT_DATA_DATASET,
685+
labels: MOCK_CVAT_LABELS,
686+
requesterDescription: MOCK_REQUESTER_DESCRIPTION,
687+
userGuide: MOCK_FILE_URL,
688+
minQuality: 0.8,
689+
groundTruth: MOCK_STORAGE_DATA,
690+
type: JobRequestType.IMAGE_POLYGONS,
691+
fundAmount: 10,
692+
currency: JobCurrency.HMT,
693+
};
694+
695+
const requestType = JobRequestType.IMAGE_POLYGONS;
696+
const tokenFundAmount = 100;
697+
698+
const result = await jobService.createCvatManifest(
699+
dto,
700+
requestType,
701+
tokenFundAmount,
702+
);
703+
704+
expect(result).toEqual({
705+
data: {
706+
data_url: MOCK_BUCKET_FILE,
707+
},
708+
annotation: {
709+
labels: MOCK_CVAT_LABELS,
710+
description: MOCK_REQUESTER_DESCRIPTION,
711+
user_guide: MOCK_FILE_URL,
712+
type: requestType,
713+
job_size: 1,
714+
},
715+
validation: {
716+
min_quality: 0.8,
717+
val_size: 2,
718+
gt_url: MOCK_BUCKET_FILE,
719+
},
720+
job_bounty: jobBounty,
721+
});
722+
});
723+
677724
it('should create a valid CVAT manifest for image boxes from points job type', async () => {
678725
const jobBounty = '50.0';
679726

packages/apps/job-launcher/server/src/modules/job/job.service.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,14 @@ export class JobService {
462462
fundAmount,
463463
}),
464464
},
465+
[JobRequestType.IMAGE_POLYGONS]: {
466+
calculateFundAmount: async (dto: JobCvatDto) => dto.fundAmount,
467+
createManifest: (
468+
dto: JobCvatDto,
469+
requestType: JobRequestType,
470+
fundAmount: number,
471+
) => this.createCvatManifest(dto, requestType, fundAmount),
472+
},
465473
[JobRequestType.IMAGE_BOXES]: {
466474
calculateFundAmount: async (dto: JobCvatDto) => dto.fundAmount,
467475
createManifest: (
@@ -503,6 +511,9 @@ export class JobService {
503511
[JobRequestType.FORTUNE]: {
504512
getTrustedHandlers: () => [],
505513
},
514+
[JobRequestType.IMAGE_POLYGONS]: {
515+
getTrustedHandlers: () => [],
516+
},
506517
[JobRequestType.IMAGE_BOXES]: {
507518
getTrustedHandlers: () => [],
508519
},
@@ -526,6 +537,39 @@ export class JobService {
526537
getElementsCount: async () => 0,
527538
generateUrls: () => ({ dataUrl: new URL(''), gtUrl: new URL('') }),
528539
},
540+
[JobRequestType.IMAGE_POLYGONS]: {
541+
getElementsCount: async (urls: GenerateUrls) => {
542+
const gt = (await this.storageService.downloadJsonLikeData(
543+
`${urls.gtUrl.protocol}//${urls.gtUrl.host}${urls.gtUrl.pathname}`,
544+
)) as any;
545+
if (!gt || !gt.images || gt.images.length === 0)
546+
throw new ControlledError(
547+
ErrorJob.GroundThuthValidationFailed,
548+
HttpStatus.BAD_REQUEST,
549+
);
550+
551+
const data = await listObjectsInBucket(urls.dataUrl);
552+
if (!data || data.length === 0 || !data[0])
553+
throw new ControlledError(
554+
ErrorJob.DatasetValidationFailed,
555+
HttpStatus.BAD_REQUEST,
556+
);
557+
558+
await this.checkImageConsistency(gt.images, data);
559+
560+
return data.length - gt.images.length;
561+
},
562+
generateUrls: (
563+
data: CvatDataDto,
564+
groundTruth: StorageDataDto,
565+
): GenerateUrls => {
566+
const requestType = JobRequestType.IMAGE_POLYGONS;
567+
return {
568+
dataUrl: generateBucketUrl(data.dataset, requestType),
569+
gtUrl: generateBucketUrl(groundTruth, requestType),
570+
};
571+
},
572+
},
529573
[JobRequestType.IMAGE_BOXES]: {
530574
getElementsCount: async (urls: GenerateUrls) => {
531575
const gt = (await this.storageService.downloadJsonLikeData(
@@ -656,6 +700,16 @@ export class JobService {
656700
return { exchangeOracle, recordingOracle, reputationOracle };
657701
},
658702
},
703+
[JobRequestType.IMAGE_POLYGONS]: {
704+
getOracleAddresses: (): OracleAddresses => {
705+
const exchangeOracle = this.web3ConfigService.cvatExchangeOracleAddress;
706+
const recordingOracle =
707+
this.web3ConfigService.cvatRecordingOracleAddress;
708+
const reputationOracle = this.web3ConfigService.reputationOracleAddress;
709+
710+
return { exchangeOracle, recordingOracle, reputationOracle };
711+
},
712+
},
659713
[JobRequestType.IMAGE_BOXES]: {
660714
getOracleAddresses: (): OracleAddresses => {
661715
const exchangeOracle = this.web3ConfigService.cvatExchangeOracleAddress;

0 commit comments

Comments
 (0)