You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
827 lines
28 KiB
TypeScript
827 lines
28 KiB
TypeScript
import { ArgumentError, DataError } from './exceptions';
|
|
import { HistoryActions } from './enums';
|
|
import loggerStorage from './logger-storage';
|
|
import serverProxy from './server-proxy';
|
|
import {
|
|
getFrame,
|
|
deleteFrame,
|
|
restoreFrame,
|
|
getRanges,
|
|
getPreview,
|
|
clear as clearFrames,
|
|
findNotDeletedFrame,
|
|
getContextImage,
|
|
patchMeta,
|
|
getDeletedFrames,
|
|
} from './frames';
|
|
import Issue from './issue';
|
|
import { checkObjectType } from './common';
|
|
import {
|
|
getAnnotations, putAnnotations, saveAnnotations,
|
|
hasUnsavedChanges, searchAnnotations, searchEmptyFrame,
|
|
mergeAnnotations, splitAnnotations, groupAnnotations,
|
|
clearAnnotations, selectObject, annotationsStatistics,
|
|
importCollection, exportCollection, importDataset,
|
|
exportDataset, undoActions, redoActions,
|
|
freezeHistory, clearActions, getActions,
|
|
clearCache, getHistory,
|
|
} from './annotations';
|
|
|
|
// must be called with task/job context
|
|
async function deleteFrameWrapper(jobID, frame) {
|
|
const history = getHistory(this);
|
|
const redo = async () => {
|
|
deleteFrame(jobID, frame);
|
|
};
|
|
|
|
await redo();
|
|
history.do(HistoryActions.REMOVED_FRAME, async () => {
|
|
restoreFrame(jobID, frame);
|
|
}, redo, [], frame);
|
|
}
|
|
|
|
async function restoreFrameWrapper(jobID, frame) {
|
|
const history = getHistory(this);
|
|
const redo = async () => {
|
|
restoreFrame(jobID, frame);
|
|
};
|
|
|
|
await redo();
|
|
history.do(HistoryActions.RESTORED_FRAME, async () => {
|
|
deleteFrame(jobID, frame);
|
|
}, redo, [], frame);
|
|
}
|
|
|
|
export function implementJob(Job) {
|
|
Job.prototype.save.implementation = async function () {
|
|
if (this.id) {
|
|
const jobData = this._updateTrigger.getUpdated(this);
|
|
if (jobData.assignee) {
|
|
jobData.assignee = jobData.assignee.id;
|
|
}
|
|
|
|
const data = await serverProxy.jobs.save(this.id, jobData);
|
|
this._updateTrigger.reset();
|
|
return new Job(data);
|
|
}
|
|
|
|
throw new ArgumentError('Could not save job without id');
|
|
};
|
|
|
|
Job.prototype.issues.implementation = async function () {
|
|
const result = await serverProxy.issues.get(this.id);
|
|
return result.map((issue) => new Issue(issue));
|
|
};
|
|
|
|
Job.prototype.openIssue.implementation = async function (issue, message) {
|
|
checkObjectType('issue', issue, null, Issue);
|
|
checkObjectType('message', message, 'string');
|
|
const result = await serverProxy.issues.create({
|
|
...issue.serialize(),
|
|
message,
|
|
});
|
|
return new Issue(result);
|
|
};
|
|
|
|
Job.prototype.frames.get.implementation = async function (frame, isPlaying, step) {
|
|
if (!Number.isInteger(frame) || frame < 0) {
|
|
throw new ArgumentError(`Frame must be a positive integer. Got: "${frame}"`);
|
|
}
|
|
|
|
if (frame < this.startFrame || frame > this.stopFrame) {
|
|
throw new ArgumentError(`The frame with number ${frame} is out of the job`);
|
|
}
|
|
|
|
const frameData = await getFrame(
|
|
this.id,
|
|
this.dataChunkSize,
|
|
this.dataChunkType,
|
|
this.mode,
|
|
frame,
|
|
this.startFrame,
|
|
this.stopFrame,
|
|
isPlaying,
|
|
step,
|
|
this.dimension,
|
|
);
|
|
return frameData;
|
|
};
|
|
|
|
Job.prototype.frames.delete.implementation = async function (frame) {
|
|
if (!Number.isInteger(frame)) {
|
|
throw new Error(`Frame must be an integer. Got: "${frame}"`);
|
|
}
|
|
|
|
if (frame < this.startFrame || frame > this.stopFrame) {
|
|
throw new Error('The frame is out of the job');
|
|
}
|
|
|
|
await deleteFrameWrapper.call(this, this.id, frame);
|
|
};
|
|
|
|
Job.prototype.frames.restore.implementation = async function (frame) {
|
|
if (!Number.isInteger(frame)) {
|
|
throw new Error(`Frame must be an integer. Got: "${frame}"`);
|
|
}
|
|
|
|
if (frame < this.startFrame || frame > this.stopFrame) {
|
|
throw new Error('The frame is out of the job');
|
|
}
|
|
|
|
await restoreFrameWrapper.call(this, this.id, frame);
|
|
};
|
|
|
|
Job.prototype.frames.save.implementation = async function () {
|
|
const result = await patchMeta(this.id);
|
|
return result;
|
|
};
|
|
|
|
Job.prototype.frames.ranges.implementation = async function () {
|
|
const rangesData = await getRanges(this.id);
|
|
return rangesData;
|
|
};
|
|
|
|
Job.prototype.frames.preview.implementation = async function () {
|
|
if (this.id === null || this.taskId === null) {
|
|
return '';
|
|
}
|
|
|
|
const frameData = await getPreview(this.taskId, this.id);
|
|
return frameData;
|
|
};
|
|
|
|
Job.prototype.frames.contextImage.implementation = async function (frameId) {
|
|
const result = await getContextImage(this.id, frameId);
|
|
return result;
|
|
};
|
|
|
|
Job.prototype.frames.search.implementation = async function (filters, frameFrom, frameTo) {
|
|
if (typeof filters !== 'object') {
|
|
throw new ArgumentError('Filters should be an object');
|
|
}
|
|
|
|
if (!Number.isInteger(frameFrom) || !Number.isInteger(frameTo)) {
|
|
throw new ArgumentError('The start and end frames both must be an integer');
|
|
}
|
|
|
|
if (frameFrom < this.startFrame || frameFrom > this.stopFrame) {
|
|
throw new ArgumentError('The start frame is out of the job');
|
|
}
|
|
|
|
if (frameTo < this.startFrame || frameTo > this.stopFrame) {
|
|
throw new ArgumentError('The stop frame is out of the job');
|
|
}
|
|
if (filters.notDeleted) {
|
|
return findNotDeletedFrame(this.id, frameFrom, frameTo, filters.offset || 1);
|
|
}
|
|
return null;
|
|
};
|
|
|
|
// TODO: Check filter for annotations
|
|
Job.prototype.annotations.get.implementation = async function (frame, allTracks, filters) {
|
|
if (!Array.isArray(filters)) {
|
|
throw new ArgumentError('Filters must be an array');
|
|
}
|
|
|
|
if (!Number.isInteger(frame)) {
|
|
throw new ArgumentError('The frame argument must be an integer');
|
|
}
|
|
|
|
if (frame < this.startFrame || frame > this.stopFrame) {
|
|
throw new ArgumentError(`Frame ${frame} does not exist in the job`);
|
|
}
|
|
|
|
const annotationsData = await getAnnotations(this, frame, allTracks, filters);
|
|
const deletedFrames = await getDeletedFrames('job', this.id);
|
|
if (frame in deletedFrames) {
|
|
return [];
|
|
}
|
|
|
|
return annotationsData;
|
|
};
|
|
|
|
Job.prototype.annotations.search.implementation = function (filters, frameFrom, frameTo) {
|
|
if (!Array.isArray(filters)) {
|
|
throw new ArgumentError('Filters must be an array');
|
|
}
|
|
|
|
if (!Number.isInteger(frameFrom) || !Number.isInteger(frameTo)) {
|
|
throw new ArgumentError('The start and end frames both must be an integer');
|
|
}
|
|
|
|
if (frameFrom < this.startFrame || frameFrom > this.stopFrame) {
|
|
throw new ArgumentError('The start frame is out of the job');
|
|
}
|
|
|
|
if (frameTo < this.startFrame || frameTo > this.stopFrame) {
|
|
throw new ArgumentError('The stop frame is out of the job');
|
|
}
|
|
|
|
const result = searchAnnotations(this, filters, frameFrom, frameTo);
|
|
return result;
|
|
};
|
|
|
|
Job.prototype.annotations.searchEmpty.implementation = function (frameFrom, frameTo) {
|
|
if (!Number.isInteger(frameFrom) || !Number.isInteger(frameTo)) {
|
|
throw new ArgumentError('The start and end frames both must be an integer');
|
|
}
|
|
|
|
if (frameFrom < this.startFrame || frameFrom > this.stopFrame) {
|
|
throw new ArgumentError('The start frame is out of the job');
|
|
}
|
|
|
|
if (frameTo < this.startFrame || frameTo > this.stopFrame) {
|
|
throw new ArgumentError('The stop frame is out of the job');
|
|
}
|
|
|
|
const result = searchEmptyFrame(this, frameFrom, frameTo);
|
|
return result;
|
|
};
|
|
|
|
Job.prototype.annotations.save.implementation = async function (onUpdate) {
|
|
const result = await saveAnnotations(this, onUpdate);
|
|
return result;
|
|
};
|
|
|
|
Job.prototype.annotations.merge.implementation = async function (objectStates) {
|
|
const result = await mergeAnnotations(this, objectStates);
|
|
return result;
|
|
};
|
|
|
|
Job.prototype.annotations.split.implementation = async function (objectState, frame) {
|
|
const result = await splitAnnotations(this, objectState, frame);
|
|
return result;
|
|
};
|
|
|
|
Job.prototype.annotations.group.implementation = async function (objectStates, reset) {
|
|
const result = await groupAnnotations(this, objectStates, reset);
|
|
return result;
|
|
};
|
|
|
|
Job.prototype.annotations.hasUnsavedChanges.implementation = function () {
|
|
const result = hasUnsavedChanges(this);
|
|
return result;
|
|
};
|
|
|
|
Job.prototype.annotations.clear.implementation = async function (
|
|
reload, startframe, endframe, delTrackKeyframesOnly,
|
|
) {
|
|
const result = await clearAnnotations(this, reload, startframe, endframe, delTrackKeyframesOnly);
|
|
return result;
|
|
};
|
|
|
|
Job.prototype.annotations.select.implementation = function (frame, x, y) {
|
|
const result = selectObject(this, frame, x, y);
|
|
return result;
|
|
};
|
|
|
|
Job.prototype.annotations.statistics.implementation = function () {
|
|
const result = annotationsStatistics(this);
|
|
return result;
|
|
};
|
|
|
|
Job.prototype.annotations.put.implementation = function (objectStates) {
|
|
const result = putAnnotations(this, objectStates);
|
|
return result;
|
|
};
|
|
|
|
Job.prototype.annotations.upload.implementation = async function (
|
|
format: string,
|
|
useDefaultLocation: boolean,
|
|
sourceStorage: Storage,
|
|
file: File | string,
|
|
options?: { convMaskToPoly?: boolean },
|
|
) {
|
|
const result = await importDataset(this, format, useDefaultLocation, sourceStorage, file, options);
|
|
return result;
|
|
};
|
|
|
|
Job.prototype.annotations.import.implementation = function (data) {
|
|
const result = importCollection(this, data);
|
|
return result;
|
|
};
|
|
|
|
Job.prototype.annotations.export.implementation = function () {
|
|
const result = exportCollection(this);
|
|
return result;
|
|
};
|
|
|
|
Job.prototype.annotations.exportDataset.implementation = async function (
|
|
format: string,
|
|
saveImages: boolean,
|
|
useDefaultSettings: boolean,
|
|
targetStorage: Storage,
|
|
customName?: string,
|
|
) {
|
|
const result = await exportDataset(this, format, saveImages, useDefaultSettings, targetStorage, customName);
|
|
return result;
|
|
};
|
|
|
|
Job.prototype.actions.undo.implementation = async function (count) {
|
|
const result = await undoActions(this, count);
|
|
return result;
|
|
};
|
|
|
|
Job.prototype.actions.redo.implementation = async function (count) {
|
|
const result = await redoActions(this, count);
|
|
return result;
|
|
};
|
|
|
|
Job.prototype.actions.freeze.implementation = function (frozen) {
|
|
const result = freezeHistory(this, frozen);
|
|
return result;
|
|
};
|
|
|
|
Job.prototype.actions.clear.implementation = function () {
|
|
const result = clearActions(this);
|
|
return result;
|
|
};
|
|
|
|
Job.prototype.actions.get.implementation = function () {
|
|
const result = getActions(this);
|
|
return result;
|
|
};
|
|
|
|
Job.prototype.logger.log.implementation = async function (logType, payload, wait) {
|
|
const result = await loggerStorage.log(logType, { ...payload, task_id: this.taskId, job_id: this.id }, wait);
|
|
return result;
|
|
};
|
|
|
|
Job.prototype.predictor.status.implementation = async function () {
|
|
if (!Number.isInteger(this.projectId)) {
|
|
throw new DataError('The job must belong to a project to use the feature');
|
|
}
|
|
|
|
const result = await serverProxy.predictor.status(this.projectId);
|
|
return {
|
|
message: result.message,
|
|
progress: result.progress,
|
|
projectScore: result.score,
|
|
timeRemaining: result.time_remaining,
|
|
mediaAmount: result.media_amount,
|
|
annotationAmount: result.annotation_amount,
|
|
};
|
|
};
|
|
|
|
Job.prototype.predictor.predict.implementation = async function (frame) {
|
|
if (!Number.isInteger(frame) || frame < 0) {
|
|
throw new ArgumentError(`Frame must be a positive integer. Got: "${frame}"`);
|
|
}
|
|
|
|
if (frame < this.startFrame || frame > this.stopFrame) {
|
|
throw new ArgumentError(`The frame with number ${frame} is out of the job`);
|
|
}
|
|
|
|
if (!Number.isInteger(this.projectId)) {
|
|
throw new DataError('The job must belong to a project to use the feature');
|
|
}
|
|
|
|
const result = await serverProxy.predictor.predict(this.taskId, frame);
|
|
return result;
|
|
};
|
|
|
|
Job.prototype.close.implementation = function closeTask() {
|
|
clearFrames(this.id);
|
|
clearCache(this);
|
|
return this;
|
|
};
|
|
|
|
return Job;
|
|
}
|
|
|
|
export function implementTask(Task) {
|
|
Task.prototype.close.implementation = function closeTask() {
|
|
for (const job of this.jobs) {
|
|
clearFrames(job.id);
|
|
clearCache(job);
|
|
}
|
|
|
|
clearCache(this);
|
|
return this;
|
|
};
|
|
|
|
Task.prototype.save.implementation = async function (onUpdate) {
|
|
// TODO: Add ability to change an owner and an assignee
|
|
if (typeof this.id !== 'undefined') {
|
|
// If the task has been already created, we update it
|
|
const taskData = this._updateTrigger.getUpdated(this, {
|
|
bugTracker: 'bug_tracker',
|
|
projectId: 'project_id',
|
|
assignee: 'assignee_id',
|
|
});
|
|
if (taskData.assignee_id) {
|
|
taskData.assignee_id = taskData.assignee_id.id;
|
|
}
|
|
if (taskData.labels) {
|
|
taskData.labels = this._internalData.labels;
|
|
taskData.labels = taskData.labels.map((el) => el.toJSON());
|
|
}
|
|
|
|
const data = await serverProxy.tasks.save(this.id, taskData);
|
|
this._updateTrigger.reset();
|
|
return new Task(data);
|
|
}
|
|
|
|
const taskSpec: any = {
|
|
name: this.name,
|
|
labels: this.labels.map((el) => el.toJSON()),
|
|
};
|
|
|
|
if (typeof this.bugTracker !== 'undefined') {
|
|
taskSpec.bug_tracker = this.bugTracker;
|
|
}
|
|
if (typeof this.segmentSize !== 'undefined') {
|
|
taskSpec.segment_size = this.segmentSize;
|
|
}
|
|
if (typeof this.overlap !== 'undefined') {
|
|
taskSpec.overlap = this.overlap;
|
|
}
|
|
if (typeof this.projectId !== 'undefined') {
|
|
taskSpec.project_id = this.projectId;
|
|
}
|
|
if (typeof this.subset !== 'undefined') {
|
|
taskSpec.subset = this.subset;
|
|
}
|
|
|
|
if (this.targetStorage) {
|
|
taskSpec.target_storage = this.targetStorage.toJSON();
|
|
}
|
|
|
|
if (this.sourceStorage) {
|
|
taskSpec.source_storage = this.sourceStorage.toJSON();
|
|
}
|
|
|
|
const taskDataSpec = {
|
|
client_files: this.clientFiles,
|
|
server_files: this.serverFiles,
|
|
remote_files: this.remoteFiles,
|
|
image_quality: this.imageQuality,
|
|
use_zip_chunks: this.useZipChunks,
|
|
use_cache: this.useCache,
|
|
sorting_method: this.sortingMethod,
|
|
};
|
|
|
|
if (typeof this.startFrame !== 'undefined') {
|
|
taskDataSpec.start_frame = this.startFrame;
|
|
}
|
|
if (typeof this.stopFrame !== 'undefined') {
|
|
taskDataSpec.stop_frame = this.stopFrame;
|
|
}
|
|
if (typeof this.frameFilter !== 'undefined') {
|
|
taskDataSpec.frame_filter = this.frameFilter;
|
|
}
|
|
if (typeof this.dataChunkSize !== 'undefined') {
|
|
taskDataSpec.chunk_size = this.dataChunkSize;
|
|
}
|
|
if (typeof this.copyData !== 'undefined') {
|
|
taskDataSpec.copy_data = this.copyData;
|
|
}
|
|
if (typeof this.cloudStorageId !== 'undefined') {
|
|
taskDataSpec.cloud_storage_id = this.cloudStorageId;
|
|
}
|
|
|
|
const task = await serverProxy.tasks.create(taskSpec, taskDataSpec, onUpdate);
|
|
return new Task(task);
|
|
};
|
|
|
|
Task.prototype.delete.implementation = async function () {
|
|
const result = await serverProxy.tasks.delete(this.id);
|
|
return result;
|
|
};
|
|
|
|
Task.prototype.backup.implementation = async function (
|
|
targetStorage: Storage,
|
|
useDefaultSettings: boolean,
|
|
fileName?: string,
|
|
) {
|
|
const result = await serverProxy.tasks.backup(this.id, targetStorage, useDefaultSettings, fileName);
|
|
return result;
|
|
};
|
|
|
|
Task.restore.implementation = async function (storage: Storage, file: File | string) {
|
|
// eslint-disable-next-line no-unsanitized/method
|
|
const result = await serverProxy.tasks.restore(storage, file);
|
|
return result;
|
|
};
|
|
|
|
Task.prototype.frames.get.implementation = async function (frame, isPlaying, step) {
|
|
if (!Number.isInteger(frame) || frame < 0) {
|
|
throw new ArgumentError(`Frame must be a positive integer. Got: "${frame}"`);
|
|
}
|
|
|
|
if (frame >= this.size) {
|
|
throw new ArgumentError(`The frame with number ${frame} is out of the task`);
|
|
}
|
|
|
|
const job = this.jobs.filter((_job) => _job.startFrame <= frame && _job.stopFrame >= frame)[0];
|
|
|
|
const result = await getFrame(
|
|
job.id,
|
|
this.dataChunkSize,
|
|
this.dataChunkType,
|
|
this.mode,
|
|
frame,
|
|
job.startFrame,
|
|
job.stopFrame,
|
|
isPlaying,
|
|
step,
|
|
);
|
|
return result;
|
|
};
|
|
|
|
Task.prototype.frames.ranges.implementation = async function () {
|
|
const rangesData = {
|
|
decoded: [],
|
|
buffered: [],
|
|
};
|
|
for (const job of this.jobs) {
|
|
const { decoded, buffered } = await getRanges(job.id);
|
|
rangesData.decoded.push(decoded);
|
|
rangesData.buffered.push(buffered);
|
|
}
|
|
return rangesData;
|
|
};
|
|
|
|
Task.prototype.frames.preview.implementation = async function () {
|
|
if (this.id === null) {
|
|
return '';
|
|
}
|
|
|
|
const frameData = await getPreview(this.id);
|
|
return frameData;
|
|
};
|
|
|
|
Task.prototype.frames.delete.implementation = async function (frame) {
|
|
if (!Number.isInteger(frame)) {
|
|
throw new Error(`Frame must be an integer. Got: "${frame}"`);
|
|
}
|
|
|
|
if (frame < 0 || frame >= this.size) {
|
|
throw new Error('The frame is out of the task');
|
|
}
|
|
|
|
const job = this.jobs.filter((_job) => _job.startFrame <= frame && _job.stopFrame >= frame)[0];
|
|
if (job) {
|
|
await deleteFrameWrapper.call(this, job.id, frame);
|
|
}
|
|
};
|
|
|
|
Task.prototype.frames.restore.implementation = async function (frame) {
|
|
if (!Number.isInteger(frame)) {
|
|
throw new Error(`Frame must be an integer. Got: "${frame}"`);
|
|
}
|
|
|
|
if (frame < 0 || frame >= this.size) {
|
|
throw new Error('The frame is out of the task');
|
|
}
|
|
|
|
const job = this.jobs.filter((_job) => _job.startFrame <= frame && _job.stopFrame >= frame)[0];
|
|
if (job) {
|
|
await restoreFrameWrapper.call(this, job.id, frame);
|
|
}
|
|
};
|
|
|
|
Task.prototype.frames.save.implementation = async function () {
|
|
return Promise.all(this.jobs.map((job) => patchMeta(job.id)));
|
|
};
|
|
|
|
Task.prototype.frames.search.implementation = async function (filters, frameFrom, frameTo) {
|
|
if (typeof filters !== 'object') {
|
|
throw new ArgumentError('Filters should be an object');
|
|
}
|
|
|
|
if (!Number.isInteger(frameFrom) || !Number.isInteger(frameTo)) {
|
|
throw new ArgumentError('The start and end frames both must be an integer');
|
|
}
|
|
|
|
if (frameFrom < 0 || frameFrom > this.size) {
|
|
throw new ArgumentError('The start frame is out of the task');
|
|
}
|
|
|
|
if (frameTo < 0 || frameTo > this.size) {
|
|
throw new ArgumentError('The stop frame is out of the task');
|
|
}
|
|
|
|
const jobs = this.jobs.filter((_job) => (
|
|
(frameFrom >= _job.startFrame && frameFrom <= _job.stopFrame) ||
|
|
(frameTo >= _job.startFrame && frameTo <= _job.stopFrame) ||
|
|
(frameFrom < _job.startFrame && frameTo > _job.stopFrame)
|
|
));
|
|
|
|
if (filters.notDeleted) {
|
|
for (const job of jobs) {
|
|
const result = await findNotDeletedFrame(
|
|
job.id, Math.max(frameFrom, job.startFrame), Math.min(frameTo, job.stopFrame), 1,
|
|
);
|
|
|
|
if (result !== null) return result;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
};
|
|
|
|
// TODO: Check filter for annotations
|
|
Task.prototype.annotations.get.implementation = async function (frame, allTracks, filters) {
|
|
if (!Array.isArray(filters) || filters.some((filter) => typeof filter !== 'string')) {
|
|
throw new ArgumentError('The filters argument must be an array of strings');
|
|
}
|
|
|
|
if (!Number.isInteger(frame) || frame < 0) {
|
|
throw new ArgumentError(`Frame must be a positive integer. Got: "${frame}"`);
|
|
}
|
|
|
|
if (frame >= this.size) {
|
|
throw new ArgumentError(`Frame ${frame} does not exist in the task`);
|
|
}
|
|
|
|
const result = await getAnnotations(this, frame, allTracks, filters);
|
|
const deletedFrames = await getDeletedFrames('task', this.id);
|
|
if (frame in deletedFrames) {
|
|
return [];
|
|
}
|
|
|
|
return result;
|
|
};
|
|
|
|
Task.prototype.annotations.search.implementation = function (filters, frameFrom, frameTo) {
|
|
if (!Array.isArray(filters) || filters.some((filter) => typeof filter !== 'string')) {
|
|
throw new ArgumentError('The filters argument must be an array of strings');
|
|
}
|
|
|
|
if (!Number.isInteger(frameFrom) || !Number.isInteger(frameTo)) {
|
|
throw new ArgumentError('The start and end frames both must be an integer');
|
|
}
|
|
|
|
if (frameFrom < 0 || frameFrom >= this.size) {
|
|
throw new ArgumentError('The start frame is out of the task');
|
|
}
|
|
|
|
if (frameTo < 0 || frameTo >= this.size) {
|
|
throw new ArgumentError('The stop frame is out of the task');
|
|
}
|
|
|
|
const result = searchAnnotations(this, filters, frameFrom, frameTo);
|
|
return result;
|
|
};
|
|
|
|
Task.prototype.annotations.searchEmpty.implementation = function (frameFrom, frameTo) {
|
|
if (!Number.isInteger(frameFrom) || !Number.isInteger(frameTo)) {
|
|
throw new ArgumentError('The start and end frames both must be an integer');
|
|
}
|
|
|
|
if (frameFrom < 0 || frameFrom >= this.size) {
|
|
throw new ArgumentError('The start frame is out of the task');
|
|
}
|
|
|
|
if (frameTo < 0 || frameTo >= this.size) {
|
|
throw new ArgumentError('The stop frame is out of the task');
|
|
}
|
|
|
|
const result = searchEmptyFrame(this, frameFrom, frameTo);
|
|
return result;
|
|
};
|
|
|
|
Task.prototype.annotations.save.implementation = async function (onUpdate) {
|
|
const result = await saveAnnotations(this, onUpdate);
|
|
return result;
|
|
};
|
|
|
|
Task.prototype.annotations.merge.implementation = async function (objectStates) {
|
|
const result = await mergeAnnotations(this, objectStates);
|
|
return result;
|
|
};
|
|
|
|
Task.prototype.annotations.split.implementation = async function (objectState, frame) {
|
|
const result = await splitAnnotations(this, objectState, frame);
|
|
return result;
|
|
};
|
|
|
|
Task.prototype.annotations.group.implementation = async function (objectStates, reset) {
|
|
const result = await groupAnnotations(this, objectStates, reset);
|
|
return result;
|
|
};
|
|
|
|
Task.prototype.annotations.hasUnsavedChanges.implementation = function () {
|
|
const result = hasUnsavedChanges(this);
|
|
return result;
|
|
};
|
|
|
|
Task.prototype.annotations.clear.implementation = async function (reload) {
|
|
const result = await clearAnnotations(this, reload);
|
|
return result;
|
|
};
|
|
|
|
Task.prototype.annotations.select.implementation = function (frame, x, y) {
|
|
const result = selectObject(this, frame, x, y);
|
|
return result;
|
|
};
|
|
|
|
Task.prototype.annotations.statistics.implementation = function () {
|
|
const result = annotationsStatistics(this);
|
|
return result;
|
|
};
|
|
|
|
Task.prototype.annotations.put.implementation = function (objectStates) {
|
|
const result = putAnnotations(this, objectStates);
|
|
return result;
|
|
};
|
|
|
|
Task.prototype.annotations.upload.implementation = async function (
|
|
format: string,
|
|
useDefaultLocation: boolean,
|
|
sourceStorage: Storage,
|
|
file: File | string,
|
|
options?: { convMaskToPoly?: boolean },
|
|
) {
|
|
const result = await importDataset(this, format, useDefaultLocation, sourceStorage, file, options);
|
|
return result;
|
|
};
|
|
|
|
Task.prototype.annotations.import.implementation = function (data) {
|
|
const result = importCollection(this, data);
|
|
return result;
|
|
};
|
|
|
|
Task.prototype.annotations.export.implementation = function () {
|
|
const result = exportCollection(this);
|
|
return result;
|
|
};
|
|
|
|
Task.prototype.annotations.exportDataset.implementation = async function (
|
|
format: string,
|
|
saveImages: boolean,
|
|
useDefaultSettings: boolean,
|
|
targetStorage: Storage,
|
|
customName?: string,
|
|
) {
|
|
const result = await exportDataset(this, format, saveImages, useDefaultSettings, targetStorage, customName);
|
|
return result;
|
|
};
|
|
|
|
Task.prototype.actions.undo.implementation = function (count) {
|
|
const result = undoActions(this, count);
|
|
return result;
|
|
};
|
|
|
|
Task.prototype.actions.redo.implementation = function (count) {
|
|
const result = redoActions(this, count);
|
|
return result;
|
|
};
|
|
|
|
Task.prototype.actions.freeze.implementation = function (frozen) {
|
|
const result = freezeHistory(this, frozen);
|
|
return result;
|
|
};
|
|
|
|
Task.prototype.actions.clear.implementation = function () {
|
|
const result = clearActions(this);
|
|
return result;
|
|
};
|
|
|
|
Task.prototype.actions.get.implementation = function () {
|
|
const result = getActions(this);
|
|
return result;
|
|
};
|
|
|
|
Task.prototype.logger.log.implementation = async function (logType, payload, wait) {
|
|
const result = await loggerStorage.log(logType, { ...payload, task_id: this.id }, wait);
|
|
return result;
|
|
};
|
|
|
|
Task.prototype.predictor.status.implementation = async function () {
|
|
if (!Number.isInteger(this.projectId)) {
|
|
throw new DataError('The task must belong to a project to use the feature');
|
|
}
|
|
|
|
const result = await serverProxy.predictor.status(this.projectId);
|
|
return {
|
|
message: result.message,
|
|
progress: result.progress,
|
|
projectScore: result.score,
|
|
timeRemaining: result.time_remaining,
|
|
mediaAmount: result.media_amount,
|
|
annotationAmount: result.annotation_amount,
|
|
};
|
|
};
|
|
|
|
Task.prototype.predictor.predict.implementation = async function (frame) {
|
|
if (!Number.isInteger(frame) || frame < 0) {
|
|
throw new ArgumentError(`Frame must be a positive integer. Got: "${frame}"`);
|
|
}
|
|
|
|
if (frame >= this.size) {
|
|
throw new ArgumentError(`The frame with number ${frame} is out of the task`);
|
|
}
|
|
|
|
if (!Number.isInteger(this.projectId)) {
|
|
throw new DataError('The task must belong to a project to use the feature');
|
|
}
|
|
|
|
const result = await serverProxy.predictor.predict(this.id, frame);
|
|
return result;
|
|
};
|
|
|
|
return Task;
|
|
}
|