From b1771677254d0e86d52195bff4fdf354a46a4291 Mon Sep 17 00:00:00 2001 From: Kirill Lakhov Date: Thu, 31 Oct 2024 15:22:32 +0300 Subject: [PATCH 1/3] fixed random_per_job option on create job page --- cvat-core/src/session.ts | 2 +- cvat-ui/src/actions/jobs-actions.ts | 16 ++++- .../create-job-page/create-job-page.tsx | 7 +- .../components/create-job-page/job-form.tsx | 66 ++++++++++++------- 4 files changed, 61 insertions(+), 30 deletions(-) diff --git a/cvat-core/src/session.ts b/cvat-core/src/session.ts index 1164ae0c07d..c2dce22f688 100644 --- a/cvat-core/src/session.ts +++ b/cvat-core/src/session.ts @@ -463,7 +463,7 @@ export class Session { } } -type InitializerType = Readonly & { labels?: SerializedLabel[] }>; +type InitializerType = Readonly & { labels?: SerializedLabel[] }>>; export class Job extends Session { #data: { diff --git a/cvat-ui/src/actions/jobs-actions.ts b/cvat-ui/src/actions/jobs-actions.ts index 7c2df71a927..158b94dc2f5 100644 --- a/cvat-ui/src/actions/jobs-actions.ts +++ b/cvat-ui/src/actions/jobs-actions.ts @@ -96,10 +96,20 @@ export const getJobPreviewAsync = (job: Job): ThunkAction => async (dispatch) => } }; -export const createJobAsync = (data: JobData): ThunkAction => async (dispatch) => { - const jobInstance = new cvat.classes.Job(data); +export const createJobAsync = (data: JobData): ThunkAction> => async (dispatch) => { + const initialData = { + type: data.type, + task_id: data.taskID, + }; + const jobInstance = new cvat.classes.Job(initialData); try { - const savedJob = await jobInstance.save(data); + const extras = { + frame_selection_method: data.frameSelectionMethod, + seed: data.seed, + frame_count: data.frameCount, + frames_per_job_count: data.framesPerJobCount, + }; + const savedJob = await jobInstance.save(extras); return savedJob; } catch (error) { dispatch(jobsActions.createJobFailed(error)); diff --git a/cvat-ui/src/components/create-job-page/create-job-page.tsx b/cvat-ui/src/components/create-job-page/create-job-page.tsx index 4c46e1b99fb..c6a196cecc1 100644 --- a/cvat-ui/src/components/create-job-page/create-job-page.tsx +++ b/cvat-ui/src/components/create-job-page/create-job-page.tsx @@ -1,4 +1,4 @@ -// Copyright (C) 2023 CVAT.ai Corporation +// Copyright (C) 2023-2024 CVAT.ai Corporation // // SPDX-License-Identifier: MIT @@ -10,9 +10,8 @@ import { Row, Col } from 'antd/lib/grid'; import Text from 'antd/lib/typography/Text'; import Spin from 'antd/lib/spin'; import notification from 'antd/lib/notification'; -import { Task } from 'reducers'; import { useIsMounted } from 'utils/hooks'; -import { getCore } from 'cvat-core-wrapper'; +import { getCore, Task } from 'cvat-core-wrapper'; import JobForm from './job-form'; const core = getCore(); @@ -58,7 +57,7 @@ function CreateJobPage(): JSX.Element { { - fetchingTask ? ( + fetchingTask || !taskInstance ? (
diff --git a/cvat-ui/src/components/create-job-page/job-form.tsx b/cvat-ui/src/components/create-job-page/job-form.tsx index b94d8a5f3fa..9b5c5e3456f 100644 --- a/cvat-ui/src/components/create-job-page/job-form.tsx +++ b/cvat-ui/src/components/create-job-page/job-form.tsx @@ -4,7 +4,7 @@ import './styles.scss'; -import React, { useCallback, useState } from 'react'; +import React, { useCallback, useEffect, useState } from 'react'; import { useHistory } from 'react-router'; import { useDispatch } from 'react-redux'; import { Row, Col } from 'antd/lib/grid'; @@ -26,19 +26,20 @@ export enum FrameSelectionMethod { } interface JobDataMutual { - task_id: number; - frame_selection_method: FrameSelectionMethod; + taskID: number; + frameSelectionMethod: FrameSelectionMethod; type: JobType; seed?: number; } export interface JobData extends JobDataMutual { - frame_count: number; + frameCount?: number; + framesPerJobCount?: number; } export interface JobFormData extends JobDataMutual { quantity: number; - frame_count: number; + frameCount: number; } interface Props { @@ -49,21 +50,24 @@ const defaultQuantity = 5; function JobForm(props: Props): JSX.Element { const { task } = props; - const { size: taskSize } = task; + const { size: taskSize, segmentSize } = task; const [form] = Form.useForm(); const dispatch = useDispatch(); const history = useHistory(); const [fetching, setFetching] = useState(false); + const [frameSelectionMethod, setFrameSelectionMethod] = useState(FrameSelectionMethod.RANDOM); const submit = useCallback(async (): Promise => { try { const values: JobFormData = await form.validateFields(); const data: JobData = { - frame_selection_method: values.frame_selection_method, + taskID: task.id, + frameSelectionMethod: values.frameSelectionMethod, type: values.type, seed: values.seed, - frame_count: values.frame_count, - task_id: task.id, + ...(values.frameSelectionMethod === FrameSelectionMethod.RANDOM ? + { frameCount: values.frameCount } : { framesPerJobCount: values.frameCount } + ), }; const createdJob = await dispatch(createJobAsync(data)); @@ -86,24 +90,40 @@ function JobForm(props: Props): JSX.Element { } }; + const sizeBase = useCallback(() => { + if (frameSelectionMethod === FrameSelectionMethod.RANDOM) { + return taskSize; + } + return segmentSize; + }, [frameSelectionMethod, segmentSize, taskSize]); + + const quantityFromFrameCount = (value: number): number => Math.floor((value / sizeBase()) * 100); + const frameCountFromQuantity = (value: number): number => Math.round((value * sizeBase()) / 100); + const onQuantityChange = useCallback((value: number | null) => { if (value) { - const newFrameCount = Math.round((value * taskSize) / 100); + const newFrameCount = frameCountFromQuantity(value); form.setFieldsValue({ - frame_count: newFrameCount, + frameCount: newFrameCount, }); } - }, [taskSize]); + }, [taskSize, frameSelectionMethod, segmentSize]); const onFrameCountChange = useCallback((value: number | null) => { if (value) { - const newQuantity = Math.floor((value / taskSize) * 100); + const newQuantity = quantityFromFrameCount(value); form.setFieldsValue({ quantity: newQuantity, }); } - }, [taskSize]); - const frameCountDescription = 'A representative set, 5-15% of randomly chosen frames is recommended'; + }, [taskSize, frameSelectionMethod, segmentSize]); + + useEffect(() => { + const currentQuantity = form.getFieldValue('quantity'); + onQuantityChange(currentQuantity); + }, [form, frameSelectionMethod]); + + const setDescription = 'A representative set, 5-15% of randomly chosen frames is recommended'; return ( @@ -113,9 +133,9 @@ function JobForm(props: Props): JSX.Element { layout='vertical' initialValues={{ type: JobType.GROUND_TRUTH, - frame_selection_method: FrameSelectionMethod.RANDOM, + frameSelectionMethod: FrameSelectionMethod.RANDOM, quantity: defaultQuantity, - frame_count: Math.floor((defaultQuantity * taskSize) / 100), + frameCount: frameCountFromQuantity(defaultQuantity), }} > @@ -134,13 +154,14 @@ function JobForm(props: Props): JSX.Element {