|
|
"""CVAT API task methods.""" |
|
|
|
|
|
from __future__ import annotations |
|
|
|
|
|
from typing import TYPE_CHECKING |
|
|
|
|
|
from metrics_evaluation.schema.cvat import CvatApiTaskDetails, CvatApiTaskMediasMetainformation |
|
|
|
|
|
from .retry import retry_with_backoff |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if TYPE_CHECKING: |
|
|
from .client import CvatApiClient |
|
|
|
|
|
|
|
|
class TasksMethods: |
|
|
"""Task-level operations for CVAT API.""" |
|
|
|
|
|
def __init__(self, client: "CvatApiClient"): |
|
|
"""Initialize task methods with client reference. |
|
|
|
|
|
Args: |
|
|
client: Parent CvatApiClient instance |
|
|
""" |
|
|
self.client = client |
|
|
|
|
|
@retry_with_backoff(max_retries=3, initial_delay=1.0) |
|
|
def list(self, project_id: int | None = None, token: str | None = None) -> list[CvatApiTaskDetails]: |
|
|
"""List all tasks, optionally filtered by project. |
|
|
|
|
|
Args: |
|
|
project_id: Filter by project ID (optional) |
|
|
token: Authentication token (optional) |
|
|
|
|
|
Returns: |
|
|
List of task details objects |
|
|
""" |
|
|
headers = self.client._get_headers(token) |
|
|
url = f"{self.client.cvat_host}/api/tasks?page_size=1000" |
|
|
if project_id is not None: |
|
|
url += f"&project_id={project_id}" |
|
|
|
|
|
response = self.client._make_request( |
|
|
method="GET", |
|
|
url=url, |
|
|
headers=headers, |
|
|
resource_name="tasks list", |
|
|
) |
|
|
|
|
|
response_data = response.json() |
|
|
return [ |
|
|
CvatApiTaskDetails.model_validate(task) |
|
|
for task in response_data.get("results", []) |
|
|
] |
|
|
|
|
|
@retry_with_backoff(max_retries=3, initial_delay=1.0) |
|
|
def get_task_details( |
|
|
self, task_id: int, token: str | None = None |
|
|
) -> CvatApiTaskDetails: |
|
|
"""Fetch task details. |
|
|
|
|
|
Args: |
|
|
task_id: The ID of the task |
|
|
token: Authentication token (optional) |
|
|
|
|
|
Returns: |
|
|
Task details object |
|
|
""" |
|
|
headers = self.client._get_headers(token) |
|
|
url = f"{self.client.cvat_host}/api/tasks/{task_id}" |
|
|
|
|
|
return self.client._make_request( |
|
|
method="GET", |
|
|
url=url, |
|
|
headers=headers, |
|
|
resource_name="task", |
|
|
resource_id=task_id, |
|
|
response_model=CvatApiTaskDetails, |
|
|
) |
|
|
|
|
|
@retry_with_backoff(max_retries=3, initial_delay=1.0) |
|
|
def get_task_media_metainformation( |
|
|
self, task_id: int, token: str | None = None |
|
|
) -> CvatApiTaskMediasMetainformation: |
|
|
"""Fetch task media metadata. |
|
|
|
|
|
Args: |
|
|
task_id: The ID of the task |
|
|
token: Authentication token (optional) |
|
|
|
|
|
Returns: |
|
|
Task media metadata object |
|
|
""" |
|
|
headers = self.client._get_headers(token) |
|
|
url = f"{self.client.cvat_host}/api/tasks/{task_id}/data/meta" |
|
|
|
|
|
return self.client._make_request( |
|
|
method="GET", |
|
|
url=url, |
|
|
headers=headers, |
|
|
resource_name="task media metadata", |
|
|
resource_id=task_id, |
|
|
response_model=CvatApiTaskMediasMetainformation, |
|
|
) |
|
|
|
|
|
@retry_with_backoff(max_retries=3, initial_delay=1.0) |
|
|
def get_task_job_ids(self, task_id: int, token: str | None = None) -> list[int]: |
|
|
"""Fetch all job IDs for a task. |
|
|
|
|
|
Args: |
|
|
task_id: The ID of the task |
|
|
token: Authentication token (optional) |
|
|
|
|
|
Returns: |
|
|
List of job IDs |
|
|
""" |
|
|
from metrics_evaluation.schema.cvat import CvatApiJobsListResponse |
|
|
|
|
|
headers = self.client._get_headers(token) |
|
|
url = f"{self.client.cvat_host}/api/jobs?task_id={task_id}&page_size=1000" |
|
|
|
|
|
response = self.client._make_request( |
|
|
method="GET", |
|
|
url=url, |
|
|
headers=headers, |
|
|
resource_name="task jobs", |
|
|
resource_id=task_id, |
|
|
response_model=CvatApiJobsListResponse, |
|
|
) |
|
|
|
|
|
return [job.id for job in response.results] |
|
|
|
|
|
@retry_with_backoff(max_retries=3, initial_delay=1.0) |
|
|
def update_task( |
|
|
self, task_id: int, task_data: CvatApiTaskDetails, token: str | None = None |
|
|
) -> CvatApiTaskDetails: |
|
|
"""Update task details (e.g., name, assignee, labels). |
|
|
|
|
|
Args: |
|
|
task_id: The ID of the task |
|
|
task_data: Updated task details |
|
|
token: Authentication token (optional) |
|
|
|
|
|
Returns: |
|
|
Updated task details object |
|
|
""" |
|
|
headers = self.client._get_headers(token) |
|
|
url = f"{self.client.cvat_host}/api/tasks/{task_id}" |
|
|
|
|
|
return self.client._make_request( |
|
|
method="PATCH", |
|
|
url=url, |
|
|
headers=headers, |
|
|
json_data=task_data.model_dump(exclude_unset=True), |
|
|
resource_name="task", |
|
|
resource_id=task_id, |
|
|
response_model=CvatApiTaskDetails, |
|
|
) |
|
|
|
|
|
@retry_with_backoff(max_retries=3, initial_delay=1.0) |
|
|
def get_frame(self, task_id: int, frame_number: int, token: str | None = None) -> bytes: |
|
|
"""Download a single frame from a task. |
|
|
|
|
|
Args: |
|
|
task_id: The ID of the task |
|
|
frame_number: The frame number to download |
|
|
token: Authentication token (optional) |
|
|
|
|
|
Returns: |
|
|
Raw image bytes |
|
|
""" |
|
|
headers = self.client._get_headers(token) |
|
|
url = f"{self.client.cvat_host}/api/tasks/{task_id}/data?type=frame&number={frame_number}&quality=original" |
|
|
|
|
|
response = self.client._make_request( |
|
|
method="GET", |
|
|
url=url, |
|
|
headers=headers, |
|
|
resource_name="task frame", |
|
|
resource_id=task_id, |
|
|
) |
|
|
|
|
|
return response.content |
|
|
|