Skip to content

Commit 6d9e601

Browse files
authored
Added "standard" task creation (#605)
* added method to create task without any base annotation * updated changelog * applied PR feedback
1 parent 4428ee6 commit 6d9e601

File tree

2 files changed

+84
-26
lines changed

2 files changed

+84
-26
lines changed

webknossos/Changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ For upgrade instructions, please check the respective *Breaking Changes* section
1212
### Breaking Changes
1313

1414
### Added
15+
- Added `Task.create()` method to create tasks by prodiving a dataset name, location, and rotation. [#605](https://github.com/scalableminds/webknossos-libs/pull/605)
1516

1617
### Changed
1718

webknossos/webknossos/administration/task.py

Lines changed: 83 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
task_info,
1313
)
1414
from webknossos.client.context import _get_generated_client
15-
from webknossos.geometry import BoundingBox
15+
from webknossos.geometry import BoundingBox, Vec3Int
1616

1717
logger = logging.getLogger(__name__)
1818

@@ -64,9 +64,11 @@ def create_from_annotations(
6464
bounding_box: Optional[BoundingBox] = None,
6565
) -> List["Task"]:
6666
"""Submits tasks in webKnossos based on existing annotations, and returns the Task objects"""
67+
6768
assert (
6869
len(base_annotations) > 0
6970
), "Must supply at least one base annotation to create tasks"
71+
7072
client = _get_generated_client()
7173
url = f"{client.base_url}/api/tasks/createFromFiles"
7274
task_parameters = {
@@ -86,6 +88,7 @@ def create_from_annotations(
8688
files: Mapping[str, Tuple[str, Union[bytes, BinaryIO]]] = {
8789
f"{a.name}.zip": (f"{a.name}.zip", a.binary()) for a in base_annotations
8890
}
91+
8992
response = httpx.post(
9093
url=url,
9194
headers=client.get_headers(),
@@ -97,31 +100,56 @@ def create_from_annotations(
97100
assert (
98101
response.status_code == 200
99102
), f"Failed to create tasks from files: {response.status_code}: {response.content.decode('utf-8')}"
100-
result = json.loads(response.content)
101-
if "warnings" in result:
102-
warnings = result["warnings"]
103-
if len(warnings) > 0:
104-
logger.warning(
105-
f"There were {len(warnings)} warnings during task creation:"
106-
)
107-
for warning in warnings:
108-
logger.warning(warning)
109-
assert "tasks" in result, "Invalid result of task creation"
110-
successes = []
111-
errors = []
112-
for t in result["tasks"]:
113-
print(t)
114-
if "success" in t:
115-
successes.append(t["success"])
116-
if "error" in t:
117-
errors.append(t["error"])
118-
if len(errors) > 0:
119-
logger.error(f"{len(errors)} tasks could not be created:")
120-
for error in errors:
121-
logger.error(error)
122-
if len(successes) > 0:
123-
logger.info(f"{len(successes)} tasks were successfully created.")
124-
return [cls._from_dict(t) for t in successes]
103+
104+
return cls._handle_task_creation_response(response)
105+
106+
@classmethod
107+
def create(
108+
cls,
109+
task_type_id: str,
110+
project_name: str,
111+
dataset_name: str,
112+
needed_experience_domain: str,
113+
needed_experience_value: int,
114+
starting_position: Vec3Int,
115+
starting_rotation: Optional[Vec3Int] = Vec3Int(0, 0, 0),
116+
instances: int = 1,
117+
script_id: Optional[str] = None,
118+
bounding_box: Optional[BoundingBox] = None,
119+
) -> List["Task"]:
120+
"""Submits tasks in webKnossos based on a dataset, starting position + rotation, and returns the Task objects"""
121+
122+
client = _get_generated_client()
123+
url = f"{client.base_url}/api/tasks"
124+
task_parameters = {
125+
"taskTypeId": task_type_id,
126+
"neededExperience": {
127+
"domain": needed_experience_domain,
128+
"value": needed_experience_value,
129+
},
130+
"openInstances": instances,
131+
"projectName": project_name,
132+
"scriptId": script_id,
133+
"dataSet": dataset_name,
134+
"editPosition": starting_position,
135+
"editRotation": starting_rotation,
136+
"boundingBox": bounding_box.to_wkw_dict()
137+
if bounding_box is not None
138+
else None,
139+
}
140+
141+
response = httpx.post(
142+
url=url,
143+
headers=client.get_headers(),
144+
cookies=client.get_cookies(),
145+
timeout=client.get_timeout(),
146+
json=[task_parameters],
147+
)
148+
assert (
149+
response.status_code == 200
150+
), f"Failed to create tasks: {response.status_code}: {response.content.decode('utf-8')}"
151+
152+
return cls._handle_task_creation_response(response)
125153

126154
@classmethod
127155
def _from_dict(cls, response_dict: Dict) -> "Task":
@@ -159,3 +187,32 @@ def get_annotation_infos(self) -> List[AnnotationInfo]:
159187
def get_project(self) -> Project:
160188
"""Returns the project this task belongs to"""
161189
return Project.get_by_id(self.project_id)
190+
191+
@classmethod
192+
def _handle_task_creation_response(cls, response: httpx.Response) -> List["Task"]:
193+
result = json.loads(response.content)
194+
if "warnings" in result:
195+
warnings = result["warnings"]
196+
if len(warnings) > 0:
197+
logger.warning(
198+
f"There were {len(warnings)} warnings during task creation:"
199+
)
200+
for warning in warnings:
201+
logger.warning(warning)
202+
assert "tasks" in result, "Invalid result of task creation"
203+
204+
successes = []
205+
errors = []
206+
for t in result["tasks"]:
207+
print(t)
208+
if "success" in t:
209+
successes.append(t["success"])
210+
if "error" in t:
211+
errors.append(t["error"])
212+
if len(errors) > 0:
213+
logger.error(f"{len(errors)} tasks could not be created:")
214+
for error in errors:
215+
logger.error(error)
216+
if len(successes) > 0:
217+
logger.info(f"{len(successes)} tasks were successfully created.")
218+
return [cls._from_dict(t) for t in successes]

0 commit comments

Comments
 (0)