From acf460c862edc05718f9fa3c5728818e6af610a6 Mon Sep 17 00:00:00 2001 From: Daisuke Miyazoe Date: Fri, 14 Aug 2026 11:25:17 +0900 Subject: [PATCH 1/6] =?UTF-8?q?=E3=82=BF=E3=82=B9=E3=82=AF=E3=82=B3?= =?UTF-8?q?=E3=83=A1=E3=83=B3=E3=83=88=E3=81=AEpost,put,delete=E5=AF=BE?= =?UTF-8?q?=E5=BF=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fastlabel/__init__.py | 124 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) diff --git a/fastlabel/__init__.py b/fastlabel/__init__.py index 3242504..0456188 100644 --- a/fastlabel/__init__.py +++ b/fastlabel/__init__.py @@ -5483,6 +5483,130 @@ def get_task_comments( params["limit"] = limit return self.api.get_request(endpoint, params=params) + def create_task_comment( + self, + project: str, + task_id: str, + content_id: str, + points: list, + text: str, + type: str = "text", + scale: float = 0, + frame: int = 0, + is_internally_published: bool = True, + status: str = None, + priority: int = None, + is_resolved: bool = False, + task_annotation_id: str = None, + issue_category_id: str = None, + color: str = None, + ) -> dict: + """ + Create a comment on a task. The comment author is recorded as + "via API" (not attributed to a specific user). + + project is slug of your project (Required). + task_id is the task id the comment belongs to (Required). + content_id is the content (image/frame) id the comment is anchored to (Required). + Must be a content of the given task. + points is the comment position as a numeric array (Required). + text is the comment body text (Required). + type can be 'text', 'navigation', 'free_hand', 'eraser' (default: 'text'). + scale is the canvas scale (Optional). + frame is the frame index for sequential/video (Optional). + is_internally_published toggles internal visibility (default: True). + status can be 'none', 'todo', 'in_progress', 'done' (Optional). + priority is one of 0(none)/10(low)/20(medium)/30(high) (Optional). + is_resolved marks the comment resolved (Optional). + task_annotation_id anchors the comment to an annotation of the task (Optional). + issue_category_id sets the issue category (Optional). + color is a hex color like #ffffff (Optional). + """ + endpoint = "comments" + payload = { + "project": project, + "taskId": task_id, + "contentId": content_id, + "points": points, + "text": text, + "type": type, + "isResolved": is_resolved, + "scale": scale, + "frame": frame, + "isInternallyPublished": is_internally_published, + } + if status is not None: + payload["status"] = status + if priority is not None: + payload["priority"] = priority + if task_annotation_id is not None: + payload["taskAnnotationId"] = task_annotation_id + if issue_category_id is not None: + payload["issueCategoryId"] = issue_category_id + if color is not None: + payload["color"] = color + return self.api.post_request(endpoint, payload=payload) + + def update_task_comment( + self, + comment_id: str, + is_resolved: bool = None, + points: list = None, + frame: int = None, + is_internally_published: bool = None, + status: str = None, + priority: int = None, + task_annotation_id: str = None, + issue_category_id: str = None, + threads: list = None, + ) -> dict: + """ + Update a comment. + + comment_id is the id of the comment to update (Required). + is_resolved marks the comment resolved (Optional). + points is the comment position as a numeric array (Optional). + frame is the frame index for sequential/video (Optional). + is_internally_published toggles internal visibility (Optional). + status can be 'none', 'todo', 'in_progress', 'done' (Optional). + priority is one of 0(none)/10(low)/20(medium)/30(high) (Optional). + task_annotation_id anchors the comment to an annotation (Optional). + issue_category_id sets the issue category (Optional). + threads updates existing thread bodies (Optional). + e.g.) [{"id": "THREAD_ID", "text": "updated text"}] + Only the provided fields are updated; omitted fields are left unchanged. + """ + endpoint = "comments/" + comment_id + payload = {} + if is_resolved is not None: + payload["isResolved"] = is_resolved + if points is not None: + payload["points"] = points + if frame is not None: + payload["frame"] = frame + if is_internally_published is not None: + payload["isInternallyPublished"] = is_internally_published + if status is not None: + payload["status"] = status + if priority is not None: + payload["priority"] = priority + if task_annotation_id is not None: + payload["taskAnnotationId"] = task_annotation_id + if issue_category_id is not None: + payload["issueCategoryId"] = issue_category_id + if threads is not None: + payload["threads"] = threads + return self.api.put_request(endpoint, payload=payload) + + def delete_task_comment(self, comment_id: str) -> None: + """ + Delete a comment. + + comment_id is the id of the comment to delete (Required). + """ + endpoint = "comments/" + comment_id + self.api.delete_request(endpoint) + def get_project_comments( self, project: str, From 8803f15751cd90d4a7f198f4eaeac829d7cf2642 Mon Sep 17 00:00:00 2001 From: Daisuke Miyazoe Date: Fri, 14 Aug 2026 11:27:32 +0900 Subject: [PATCH 2/6] =?UTF-8?q?=E3=82=BF=E3=82=B9=E3=82=AF=E3=82=B3?= =?UTF-8?q?=E3=83=A1=E3=83=B3=E3=83=88=E3=81=AEpost,put,delete=E5=AF=BE?= =?UTF-8?q?=E5=BF=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fastlabel/__init__.py | 37 ------------------------------------- 1 file changed, 37 deletions(-) diff --git a/fastlabel/__init__.py b/fastlabel/__init__.py index 0456188..567d5e1 100644 --- a/fastlabel/__init__.py +++ b/fastlabel/__init__.py @@ -5501,27 +5501,6 @@ def create_task_comment( issue_category_id: str = None, color: str = None, ) -> dict: - """ - Create a comment on a task. The comment author is recorded as - "via API" (not attributed to a specific user). - - project is slug of your project (Required). - task_id is the task id the comment belongs to (Required). - content_id is the content (image/frame) id the comment is anchored to (Required). - Must be a content of the given task. - points is the comment position as a numeric array (Required). - text is the comment body text (Required). - type can be 'text', 'navigation', 'free_hand', 'eraser' (default: 'text'). - scale is the canvas scale (Optional). - frame is the frame index for sequential/video (Optional). - is_internally_published toggles internal visibility (default: True). - status can be 'none', 'todo', 'in_progress', 'done' (Optional). - priority is one of 0(none)/10(low)/20(medium)/30(high) (Optional). - is_resolved marks the comment resolved (Optional). - task_annotation_id anchors the comment to an annotation of the task (Optional). - issue_category_id sets the issue category (Optional). - color is a hex color like #ffffff (Optional). - """ endpoint = "comments" payload = { "project": project, @@ -5560,22 +5539,6 @@ def update_task_comment( issue_category_id: str = None, threads: list = None, ) -> dict: - """ - Update a comment. - - comment_id is the id of the comment to update (Required). - is_resolved marks the comment resolved (Optional). - points is the comment position as a numeric array (Optional). - frame is the frame index for sequential/video (Optional). - is_internally_published toggles internal visibility (Optional). - status can be 'none', 'todo', 'in_progress', 'done' (Optional). - priority is one of 0(none)/10(low)/20(medium)/30(high) (Optional). - task_annotation_id anchors the comment to an annotation (Optional). - issue_category_id sets the issue category (Optional). - threads updates existing thread bodies (Optional). - e.g.) [{"id": "THREAD_ID", "text": "updated text"}] - Only the provided fields are updated; omitted fields are left unchanged. - """ endpoint = "comments/" + comment_id payload = {} if is_resolved is not None: From 43b26fe1ba6735216d9b60ca59cd56b9ae3cb383 Mon Sep 17 00:00:00 2001 From: Daisuke Miyazoe Date: Mon, 17 Aug 2026 12:02:03 +0900 Subject: [PATCH 3/6] =?UTF-8?q?is=5Finternally=5Fpublished=E3=81=AE?= =?UTF-8?q?=E5=BC=95=E6=95=B0=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fastlabel/__init__.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/fastlabel/__init__.py b/fastlabel/__init__.py index 567d5e1..85d600a 100644 --- a/fastlabel/__init__.py +++ b/fastlabel/__init__.py @@ -5487,13 +5487,12 @@ def create_task_comment( self, project: str, task_id: str, - content_id: str, points: list, text: str, + content_id: str = None, type: str = "text", scale: float = 0, frame: int = 0, - is_internally_published: bool = True, status: str = None, priority: int = None, is_resolved: bool = False, @@ -5501,19 +5500,25 @@ def create_task_comment( issue_category_id: str = None, color: str = None, ) -> dict: + """ + Create a comment on a task. The author is recorded as "via API". + + content_id is optional: if omitted and the task has a single content, + it is used automatically. Required for tasks with multiple contents. + """ endpoint = "comments" payload = { "project": project, "taskId": task_id, - "contentId": content_id, "points": points, "text": text, "type": type, "isResolved": is_resolved, "scale": scale, "frame": frame, - "isInternallyPublished": is_internally_published, } + if content_id is not None: + payload["contentId"] = content_id if status is not None: payload["status"] = status if priority is not None: @@ -5532,7 +5537,6 @@ def update_task_comment( is_resolved: bool = None, points: list = None, frame: int = None, - is_internally_published: bool = None, status: str = None, priority: int = None, task_annotation_id: str = None, @@ -5547,8 +5551,6 @@ def update_task_comment( payload["points"] = points if frame is not None: payload["frame"] = frame - if is_internally_published is not None: - payload["isInternallyPublished"] = is_internally_published if status is not None: payload["status"] = status if priority is not None: From 28fe09886733a3829ca01a785fc4bb0b518bcb29 Mon Sep 17 00:00:00 2001 From: Daisuke Miyazoe Date: Mon, 17 Aug 2026 16:04:01 +0900 Subject: [PATCH 4/6] =?UTF-8?q?issue=5Fcategory=E5=89=8A=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fastlabel/__init__.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/fastlabel/__init__.py b/fastlabel/__init__.py index 85d600a..37c4259 100644 --- a/fastlabel/__init__.py +++ b/fastlabel/__init__.py @@ -5485,7 +5485,6 @@ def get_task_comments( def create_task_comment( self, - project: str, task_id: str, points: list, text: str, @@ -5497,18 +5496,18 @@ def create_task_comment( priority: int = None, is_resolved: bool = False, task_annotation_id: str = None, - issue_category_id: str = None, color: str = None, ) -> dict: """ Create a comment on a task. The author is recorded as "via API". + The task is resolved by task_id alone (project is not required). + content_id is optional: if omitted and the task has a single content, it is used automatically. Required for tasks with multiple contents. """ endpoint = "comments" payload = { - "project": project, "taskId": task_id, "points": points, "text": text, @@ -5525,8 +5524,6 @@ def create_task_comment( payload["priority"] = priority if task_annotation_id is not None: payload["taskAnnotationId"] = task_annotation_id - if issue_category_id is not None: - payload["issueCategoryId"] = issue_category_id if color is not None: payload["color"] = color return self.api.post_request(endpoint, payload=payload) @@ -5540,7 +5537,6 @@ def update_task_comment( status: str = None, priority: int = None, task_annotation_id: str = None, - issue_category_id: str = None, threads: list = None, ) -> dict: endpoint = "comments/" + comment_id @@ -5557,8 +5553,6 @@ def update_task_comment( payload["priority"] = priority if task_annotation_id is not None: payload["taskAnnotationId"] = task_annotation_id - if issue_category_id is not None: - payload["issueCategoryId"] = issue_category_id if threads is not None: payload["threads"] = threads return self.api.put_request(endpoint, payload=payload) From a28c5a7a840e5771ecdb0d8c609733efcd7a33c9 Mon Sep 17 00:00:00 2001 From: Daisuke Miyazoe Date: Tue, 18 Aug 2026 12:02:26 +0900 Subject: [PATCH 5/6] =?UTF-8?q?=E3=83=A1=E3=82=BD=E3=83=83=E3=83=89?= =?UTF-8?q?=E3=81=AE=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 76 +++++++++++++++++++++++++++++++++++++++++++ fastlabel/__init__.py | 69 ++++++++++++++++----------------------- 2 files changed, 104 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index 348fa88..6261a9e 100644 --- a/README.md +++ b/README.md @@ -2967,6 +2967,82 @@ Example of a comment thread object } ``` +### Create Task Comment + +Create a comment on a task (creates a comment together with its first thread). The author is recorded as "via API". + +```python +comment = client.create_task_comment( + task_id="YOUR_TASK_ID", + points=[185.98, 86.55], + text="comment text", + frame=1, +) +``` + +#### Parameters + +| Name | Type | Required | Description | +|------|------|----------|-------------| +| task_id | str | Yes | Task ID the comment belongs to (the task is resolved by task_id alone) | +| points | list | Yes | Comment position as a numeric array | +| text | str | Yes | Comment body text | +| content_id | str | No | Content ID. If omitted and the task has a single content it is auto-selected; required for multi-content tasks | +| type | str | No | Comment type. Only `text` is supported (default: `text`) | +| scale | float | No | Canvas scale | +| frame | int | No | Frame index for sequential/video (1-indexed) | +| status | str | No | Comment status | +| priority | int | No | Comment priority | +| is_resolved | bool | No | Whether the comment is resolved | +| task_annotation_id | str | No | Annotation ID to anchor the comment to | +| color | str | No | Hex color like `#ffffff` | + +The response has the same shape as a comment object in [Get Task Comments](#get-task-comments). + +### Add a Comment Thread (Reply) + +Add a thread (reply) to an existing comment. The author is recorded as "via API". + +```python +comment = client.create_task_comment(comment_id="YOUR_COMMENT_ID", text="reply text") +``` + +#### Parameters + +| Name | Type | Required | Description | +|------|------|----------|-------------| +| comment_id | str | Yes | Parent comment ID | +| text | str | Yes | Thread body text | + +### Update a Comment Thread + +Update the body text of a single thread (message) by its thread ID. + +```python +comment = client.update_task_comment(thread_id="YOUR_THREAD_ID", text="updated text") +``` + +#### Parameters + +| Name | Type | Required | Description | +|------|------|----------|-------------| +| thread_id | str | Yes | Thread ID to update | +| text | str | Yes | New body text | + +### Delete a Comment Thread + +Delete a single thread (message) by its thread ID. When the deleted thread is the comment's last remaining thread, the comment itself is also removed. + +```python +client.delete_task_comment(thread_id="YOUR_THREAD_ID") +``` + +#### Parameters + +| Name | Type | Required | Description | +|------|------|----------|-------------| +| thread_id | str | Yes | Thread ID to delete | + ## Project ### Create Project diff --git a/fastlabel/__init__.py b/fastlabel/__init__.py index 37c4259..c7ea218 100644 --- a/fastlabel/__init__.py +++ b/fastlabel/__init__.py @@ -5485,9 +5485,9 @@ def get_task_comments( def create_task_comment( self, - task_id: str, - points: list, - text: str, + task_id: str = None, + points: list = None, + text: str = None, content_id: str = None, type: str = "text", scale: float = 0, @@ -5497,15 +5497,22 @@ def create_task_comment( is_resolved: bool = False, task_annotation_id: str = None, color: str = None, + comment_id: str = None, ) -> dict: """ - Create a comment on a task. The author is recorded as "via API". - - The task is resolved by task_id alone (project is not required). + Create a comment, or add a thread (message/reply) to an existing comment. + The author is recorded as "via API". - content_id is optional: if omitted and the task has a single content, - it is used automatically. Required for tasks with multiple contents. + - task_id を指定: 新規コメントを作成(comment + 最初の thread)。 + task は task_id のみで解決(project 不要)。content_id は省略可 + (単一 content は自動採用、複数 content は必須)。 + - comment_id を指定: 既存コメントに発言(thread)を追加(text のみ使用)。 """ + # comment_id 指定時は既存コメントへの発言(thread)追加に分岐 + if comment_id is not None: + return self.api.post_request( + "comments/" + comment_id + "/threads", payload={"text": text} + ) endpoint = "comments" payload = { "taskId": task_id, @@ -5528,43 +5535,23 @@ def create_task_comment( payload["color"] = color return self.api.post_request(endpoint, payload=payload) - def update_task_comment( - self, - comment_id: str, - is_resolved: bool = None, - points: list = None, - frame: int = None, - status: str = None, - priority: int = None, - task_annotation_id: str = None, - threads: list = None, - ) -> dict: - endpoint = "comments/" + comment_id - payload = {} - if is_resolved is not None: - payload["isResolved"] = is_resolved - if points is not None: - payload["points"] = points - if frame is not None: - payload["frame"] = frame - if status is not None: - payload["status"] = status - if priority is not None: - payload["priority"] = priority - if task_annotation_id is not None: - payload["taskAnnotationId"] = task_annotation_id - if threads is not None: - payload["threads"] = threads - return self.api.put_request(endpoint, payload=payload) + def update_task_comment(self, thread_id: str, text: str) -> dict: + """ + Update the body text of a comment thread (message) by its id. - def delete_task_comment(self, comment_id: str) -> None: + コメントの外形(frame/points/status など)は本 API では更新しない。 """ - Delete a comment. + endpoint = "comments/threads/" + thread_id + return self.api.put_request(endpoint, payload={"text": text}) - comment_id is the id of the comment to delete (Required). + def delete_task_comment(self, thread_id: str) -> None: """ - endpoint = "comments/" + comment_id - self.api.delete_request(endpoint) + Delete a comment thread (message) by its id. + + コメントの最後の1件を消すと、空の入れ物を残さないよう + コメント本体もカスケード削除される。 + """ + self.api.delete_request("comments/threads/" + thread_id) def get_project_comments( self, From e1fe151460463f9803769ffbe2a57337f5c1e16b Mon Sep 17 00:00:00 2001 From: Daisuke Miyazoe Date: Tue, 18 Aug 2026 14:21:43 +0900 Subject: [PATCH 6/6] =?UTF-8?q?=E6=97=A5=E6=9C=AC=E8=AA=9E=E3=81=AE?= =?UTF-8?q?=E3=82=B3=E3=83=A1=E3=83=B3=E3=83=88=E5=89=8A=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fastlabel/__init__.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/fastlabel/__init__.py b/fastlabel/__init__.py index c7ea218..fa28612 100644 --- a/fastlabel/__init__.py +++ b/fastlabel/__init__.py @@ -5502,13 +5502,7 @@ def create_task_comment( """ Create a comment, or add a thread (message/reply) to an existing comment. The author is recorded as "via API". - - - task_id を指定: 新規コメントを作成(comment + 最初の thread)。 - task は task_id のみで解決(project 不要)。content_id は省略可 - (単一 content は自動採用、複数 content は必須)。 - - comment_id を指定: 既存コメントに発言(thread)を追加(text のみ使用)。 """ - # comment_id 指定時は既存コメントへの発言(thread)追加に分岐 if comment_id is not None: return self.api.post_request( "comments/" + comment_id + "/threads", payload={"text": text} @@ -5538,8 +5532,6 @@ def create_task_comment( def update_task_comment(self, thread_id: str, text: str) -> dict: """ Update the body text of a comment thread (message) by its id. - - コメントの外形(frame/points/status など)は本 API では更新しない。 """ endpoint = "comments/threads/" + thread_id return self.api.put_request(endpoint, payload={"text": text}) @@ -5547,9 +5539,6 @@ def update_task_comment(self, thread_id: str, text: str) -> dict: def delete_task_comment(self, thread_id: str) -> None: """ Delete a comment thread (message) by its id. - - コメントの最後の1件を消すと、空の入れ物を残さないよう - コメント本体もカスケード削除される。 """ self.api.delete_request("comments/threads/" + thread_id)