この記事は「Asana コミュニティ Advent Calendar 2024」8日目の記事です。
なんか枠が空いたままだったので、いただき男子しました。いただき男子ばるちゃんです。
はじめに
どーもばるすです。
今回は、AsanaとChatGPTを組み合わせて「タスクの自動分解」にトライしてみようって話です。
Asanaで新規タスクが作成or編集されたら、ChatGPTがタスクの分割案を考えてサブタスクを作成する自動化 を作ってみました。
タスク着手するときに「何から手をつければいいんだっけ?」って迷いがちなので、AIに下ごしらえを頼むと楽になるんじゃないかなと思った次第。
動作イメージ
処理概要
- Asanaでタスクが作成される
- 特定のプロジェクトやフォーム投稿でもOK。
- iPaaS(今回はMakeを想定)でWebhook/トリガーが発火
- ChatGPT APIにプロンプトを投げて、タスクを分割&概要を書いてもらう
処理フロー図
make:Scenario
構築のポイント
AsanaWebhookの取り回し
- 複数のEventが配列で渡されるので、重複排除が必要
- Webhook登録時のFilter設定で対象を絞る
Asana側で監視対象とするイベントの種類をFilterで定義する
▼リクエスト例
{ "data": { "filters": [ { "action": "changed", "resource_type": "task" } ], "resource": "[ResourceID]", "target":"[webhookURL]" } }
重複するタスクIDを一つにまとめる
- Events配列からタスクGid単位で重複排除して、同じタスクに対する変更でも重複処理しないようにする
- 1つのタスクで複数イベントが飛んできても、同じ変更なら1回だけ処理すればOK
- ここを雑にやると、同じサブタスクが2回作成されたり、無駄な処理が増えてしまう
- 重複排除にはText aggregatorを使って、既存サブタスクの有無をチェックする
現タスクにサブタスクが存在するか否かで分岐する
- 既存サブタスクと同じ内容でサブタスク作成してしまうと逆に管理の手間が増えるので、これを防止する
ChatGPTのInput/Output
▼Input
Systemプロンプト
あなたはプロジェクトマネージャーのアシスタントです。 Userが入力したタスクと作成済のサブタスクを分析し、新規作成が必要なサブタスクのリストをJSON形式で提案してください。 既に作成されているサブタスクと重複するなどの理由により、作成必要なサブタスクが0件の場合は空配列を返してください。 応答は以下の条件を満たす必要があります: - subtasksという配列のみを含むJSONを返すこと - 各サブタスクには name と description フィールドを含めること - サブタスクが不要な場合は空配列を返すこと - 説明文には具体的なアクションアイテムを含めること - 日本語で記述すること
Userプロンプト
## Input タスク名: {{taskName}} タスク概要: {{taskNotes}} 現在定義済のサブタスク:{{subTaskList}}
▼Output
レスポンスをJsonで受け取りたいのでJsonModeを利用
Scenario Json
今回ご紹介したScenarioの完成品を添付しておきます。
makeはScenarioの中身が全部Jsonに入るので、ブログでシェアしやすいんですよね。
以下Jsonをお使いのmake環境にてコピペした後、Connectionなど諸々設定してご利用ください
```json { "subflows": [ { "flow": [ { "id": 6, "module": "gateway:CustomWebHook", "version": 1, "parameters": { "hook": 23578, "maxResults": 1 }, "mapper": {}, "metadata": { "designer": { "x": 0, "y": 600 }, "restore": { "parameters": { "hook": { "data": { "editable": "true" }, "label": "your-webhook" } } }, "parameters": [ { "name": "hook", "type": "hook:gateway-webhook", "label": "Webhook", "required": true }, { "name": "maxResults", "type": "number", "label": "Maximum number of results" } ], "interface": [ { "name": "__IMTHEADERS__", "spec": [ { "name": "name", "type": "text", "label": "Name" }, { "name": "value", "type": "text", "label": "Value" } ], "type": "array", "label": "Headers" }, { "name": "__IMTMETHOD__", "type": "text", "label": "Method" } ] } }, { "id": 2, "module": "builtin:BasicRouter", "version": 1, "mapper": null, "metadata": { "designer": { "x": 300, "y": 600 } }, "routes": [ { "flow": [ { "id": 3, "module": "gateway:WebhookRespond", "version": 1, "parameters": {}, "filter": { "name": "", "conditions": [ [ { "a": "{{6.`__IMTHEADERS__`[12].name}}", "b": "x-hook-secret", "o": "text:equal" } ] ] }, "mapper": { "body": "", "status": "200", "headers": [ { "key": "x-hook-secret", "value": "{{6.`__IMTHEADERS__`[12].value}}" } ] }, "metadata": { "designer": { "x": 590, "y": 290, "name": "Heartbeat用処理" }, "restore": { "expect": { "headers": { "mode": "chose", "items": [ null ] } } }, "expect": [ { "name": "status", "type": "uinteger", "label": "Status", "required": true, "validate": { "min": 100 } }, { "name": "body", "type": "any", "label": "Body" }, { "name": "headers", "spec": [ { "name": "key", "type": "text", "label": "Key", "required": true, "validate": { "max": 256 } }, { "name": "value", "type": "text", "label": "Value", "required": true, "validate": { "max": 4096 } } ], "type": "array", "label": "Custom headers", "validate": { "maxItems": 16 } } ], "advanced": true } } ] }, { "flow": [ { "id": 5, "module": "gateway:WebhookRespond", "version": 1, "parameters": {}, "filter": { "name": "", "conditions": [ [ { "a": "{{6.`__IMTHEADERS__`[12].name}}", "b": "x-hook-secret", "o": "text:notequal" } ] ] }, "mapper": { "body": "", "status": "200", "headers": [] }, "metadata": { "designer": { "x": 600, "y": 750 }, "restore": { "expect": { "headers": { "mode": "chose" } } }, "expect": [ { "name": "status", "type": "uinteger", "label": "Status", "required": true, "validate": { "min": 100 } }, { "name": "body", "type": "any", "label": "Body" }, { "name": "headers", "spec": [ { "name": "key", "type": "text", "label": "Key", "required": true, "validate": { "max": 256 } }, { "name": "value", "type": "text", "label": "Value", "required": true, "validate": { "max": 4096 } } ], "type": "array", "label": "Custom headers", "validate": { "maxItems": 16 } } ], "advanced": true } }, { "id": 34, "module": "builtin:BasicFeeder", "version": 1, "parameters": {}, "mapper": { "array": "{{deduplicate(map(6.events; \"resource.gid\"))}}" }, "metadata": { "designer": { "x": 900, "y": 750 }, "restore": { "expect": { "array": { "mode": "edit" } } }, "expect": [ { "mode": "edit", "name": "array", "spec": [], "type": "array", "label": "Array" } ] } }, { "id": 15, "module": "asana:GetTask", "version": 2, "parameters": { "__IMTCONN__": 32410 }, "mapper": { "task_gid": "{{34.value}}", "selectOrMap": "map" }, "metadata": { "designer": { "x": 1200, "y": 750 }, "restore": { "expect": { "selectOrMap": { "label": "Enter manually" } }, "parameters": { "__IMTCONN__": { "data": { "scoped": "true", "connection": "asana" }, "label": "your-asana-connection" } } }, "parameters": [ { "name": "__IMTCONN__", "type": "account:asana", "label": "Connection", "required": true } ], "expect": [ { "name": "selectOrMap", "type": "select", "label": "Enter a Task ID", "required": true, "validate": { "enum": [ "map", "select" ] } }, { "name": "task_gid", "type": "text", "label": "Task ID", "required": true } ] }, "onerror": [ { "id": 18, "module": "builtin:Commit", "version": 1, "metadata": { "designer": { "x": 1500, "y": 1200 } } } ] }, { "id": 38, "module": "asana:ListTaskSubtasks", "version": 2, "parameters": { "__IMTCONN__": 32410 }, "mapper": { "page": "100", "task_gid": "{{15.gid}}", "selectOrMap": "map" }, "metadata": { "designer": { "x": 1500, "y": 600 }, "restore": { "expect": { "selectOrMap": { "label": "Enter manually" } }, "parameters": { "__IMTCONN__": { "data": { "scoped": "true", "connection": "asana" }, "label": "your-asana-connection" } } }, "parameters": [ { "name": "__IMTCONN__", "type": "account:asana", "label": "Connection", "required": true } ], "expect": [ { "name": "selectOrMap", "type": "select", "label": "Enter a Task ID", "required": true, "validate": { "enum": [ "map", "select" ] } }, { "name": "page", "type": "uinteger", "label": "Limit" }, { "name": "task_gid", "type": "text", "label": "Task ID", "required": true } ] } }, { "id": 54, "module": "builtin:BasicRouter", "version": 1, "mapper": null, "metadata": { "designer": { "x": 1800, "y": 600 } }, "routes": [ { "flow": [ { "id": 44, "module": "util:TextAggregator", "version": 1, "parameters": { "feeder": 38, "rowSeparator": "\n" }, "filter": { "name": "", "conditions": [ [ { "a": "{{38.`__IMTLENGTH__`}}", "b": "0", "o": "number:greater" } ] ] }, "mapper": { "value": "-----\nサブタスク名:{{38.name}}\nサブタスク概要:{{38.notes}}\n-----" }, "metadata": { "designer": { "x": 2100, "y": 450 }, "restore": { "extra": { "feeder": { "label": "Asana - List a Task's Subtasks [38]" } }, "parameters": { "rowSeparator": { "label": "New row" } } }, "parameters": [ { "name": "rowSeparator", "type": "select", "label": "Row separator", "validate": { "enum": [ "\n", "\t", "other" ] } } ], "expect": [ { "name": "value", "type": "text", "label": "Text" } ], "advanced": true }, "flags": { "stopIfEmpty": true } }, { "id": 7, "module": "openai-gpt-3:CreateCompletion", "version": 1, "parameters": { "__IMTCONN__": 32472 }, "mapper": { "model": "gpt-4o-mini", "top_p": "1", "select": "chat", "messages": [ { "role": "system", "content": "あなたはプロジェクトマネージャーのアシスタントです。\nUserが入力したタスクと作成済のサブタスクを分析し、新規作成が必要なサブタスクのリストをJSON形式で提案してください。\n既に作成されているサブタスクと重複するなどの理由により、作成必要なサブタスクが0件の場合は空配列を返してください。\n\n応答は以下の条件を満たす必要があります:\n- subtasksという配列のみを含むJSONを返すこと\n- 各サブタスクには name と description フィールドを含めること\n- サブタスクが不要な場合は空配列を返すこと\n- 説明文には具体的なアクションアイテムを含めること\n- 日本語で記述すること" }, { "role": "user", "content": "## Input\nタスク名: {{15.name}}\nタスク概要: {{15.notes}}\n現在定義済のサブタスク:{{44.text}}", "imageDetail": "auto" } ], "max_tokens": "4096", "temperature": "1", "n_completions": "1", "response_format": "json_object", "parseJSONResponse": true }, "metadata": { "designer": { "x": 2400, "y": 450, "name": "OpenAI" }, "restore": { "expect": { "stop": { "mode": "chose" }, "model": { "mode": "chose", "label": "gpt-4o-mini (system)" }, "select": { "label": "Create a Chat Completion (GPT and o1 models)" }, "messages": { "mode": "chose", "items": [ { "role": { "mode": "chose", "label": "Developer / System" } }, { "role": { "mode": "chose", "label": "User" }, "imageDetail": { "mode": "chose", "label": "Auto" }, "imageInputType": { "mode": "chose", "label": "Empty" } } ] }, "logit_bias": { "mode": "chose" }, "response_format": { "mode": "chose", "label": "JSON Object" }, "parseJSONResponse": { "mode": "chose" }, "additionalParameters": { "mode": "chose" } }, "parameters": { "__IMTCONN__": { "data": { "scoped": "true", "connection": "openai-gpt-3" }, "label": "your-openai-connection" } } }, "parameters": [ { "name": "__IMTCONN__", "type": "account:openai-gpt-3", "label": "Connection", "required": true } ], "expect": [ { "name": "select", "type": "select", "label": "Select Method", "required": true, "validate": { "enum": [ "chat", "prompt" ] } }, { "name": "temperature", "type": "number", "label": "Temperature", "validate": { "max": 2, "min": 0 } }, { "name": "top_p", "type": "number", "label": "Top P", "validate": { "max": 1, "min": 0 } }, { "name": "n_completions", "type": "number", "label": "Number" }, { "name": "frequency_penalty", "type": "number", "label": "Frequency Penalty", "validate": { "max": 2, "min": -2 } }, { "name": "presence_penalty", "type": "number", "label": "Presence Penalty", "validate": { "max": 2, "min": -2 } }, { "name": "logit_bias", "spec": { "name": "value", "spec": [ { "name": "token", "type": "text", "label": "Token ID", "required": true }, { "name": "probability", "type": "number", "label": "Probability", "required": true, "validate": { "max": 100, "min": -100 } } ], "type": "collection", "label": "Token Probability" }, "type": "array", "label": "Token Probability" }, { "name": "seed", "type": "integer", "label": "Seed" }, { "name": "stop", "spec": { "name": "value", "type": "text", "label": "Stop Sequence" }, "type": "array", "label": "Stop Sequences", "validate": { "maxItems": 4 } }, { "name": "additionalParameters", "spec": { "name": "value", "spec": [ { "name": "key", "type": "text", "label": "Parameter Name", "required": true }, { "name": "type", "type": "select", "label": "Input Type", "options": [ { "label": "Text", "value": "text", "nested": [ { "name": "value", "type": "text", "label": "Parameter Value" } ], "default": true }, { "label": "Number", "value": "number", "nested": [ { "name": "value", "type": "number", "label": "Parameter Value" } ] }, { "label": "Boolean", "value": "boolean", "nested": [ { "name": "value", "type": "boolean", "label": "Parameter Value" } ] }, { "label": "Date", "value": "date", "nested": [ { "name": "value", "type": "date", "label": "Parameter Value" } ] }, { "label": "Any", "value": "any", "nested": [ { "name": "value", "type": "any", "label": "Parameter Value" } ] } ] } ], "type": "collection", "label": "Input Parameter" }, "type": "array", "label": "Other Input Parameters" }, { "name": "model", "type": "select", "label": "Model", "required": true }, { "name": "max_tokens", "type": "uinteger", "label": "Max Completion Tokens" }, { "name": "messages", "spec": { "name": "value", "spec": [ { "name": "role", "type": "select", "label": "Role", "options": { "store": [ { "label": "Developer / System", "value": "system", "nested": [ { "help": "Text content of the message on behalf of the selected __Role__.", "name": "content", "type": "text", "label": "Text Content" } ] }, { "label": "User", "value": "user", "nested": [ { "help": "Text content of the message on behalf of the selected __Role__.", "name": "content", "type": "text", "label": "Text Content" }, { "name": "imageInputType", "type": "select", "label": "Image Input Type", "options": [ { "label": "URL", "value": "url", "nested": [ { "help": "Make sure to use a publicly accessible URL.\nYou can test if your image is publicly accessible by opening the link in an incognito tab.", "name": "imageUrl", "type": "url", "label": "Image URL" } ] }, { "label": "Image File", "value": "file", "nested": [ { "name": "imageFile", "spec": [ { "help": "Accepted extensions: `.jpg`, `.jpeg`, `.png`, `.webp` and `.gif`.", "name": "imageFilename", "type": "filename", "label": "Image Filename", "semantic": "file:name", "extension": [ "jpg", "jpeg", "png", "webp", "gif" ] }, { "name": "imageData", "type": "buffer", "label": "Image Data", "semantic": "file:data" } ], "type": "collection", "label": "Image" } ] } ], "mappable": false }, { "name": "imageDetail", "type": "select", "label": "Image Detail", "options": [ { "label": "Auto", "value": "auto", "default": true }, { "label": "High", "value": "high" }, { "label": "Low", "value": "low" } ], "advanced": true } ] }, { "label": "Assistant", "value": "assistant", "nested": [ { "help": "Text content of the message on behalf of the selected __Role__.", "name": "content", "type": "text", "label": "Text Content" } ] } ] }, "required": true } ], "type": "collection", "label": "Message" }, "type": "array", "label": "Messages", "required": true }, { "name": "response_format", "type": "select", "label": "Response Format", "validate": { "enum": [ "text", "json_object" ] } }, { "name": "parseJSONResponse", "type": "boolean", "label": "Parse JSON Response", "required": true } ], "interface": [ { "name": "result", "type": "any", "label": "Result" }, { "name": "id", "type": "text", "label": "ID" }, { "name": "object", "type": "text", "label": "Object" }, { "name": "created", "type": "date", "label": "Created" }, { "name": "model", "type": "text", "label": "Model" }, { "name": "choices", "spec": { "spec": [ { "name": "text", "type": "text", "label": "Text" }, { "name": "index", "type": "number", "label": "Index" }, { "name": "logprobs", "type": "text", "label": "Log Probs" }, { "name": "finish_reason", "type": "text", "label": "Finish Reason" }, { "name": "message", "spec": [ { "name": "role", "type": "text", "label": "Role" }, { "name": "content", "type": "text", "label": "Content" }, { "name": "refusal", "type": "text", "label": "Refusal" } ], "type": "collection", "label": "Message" } ], "type": "collection" }, "type": "array", "label": "Choices" }, { "name": "usage", "spec": [ { "name": "prompt_tokens", "type": "number", "label": "Prompt Tokens" }, { "name": "completion_tokens", "type": "text", "label": "Completion Tokens" }, { "name": "total_tokens", "type": "number", "label": "Total Tokens" }, { "name": "prompt_tokens_details", "spec": [ { "name": "cached_tokens", "type": "uinteger", "label": "Cached Tokens" }, { "name": "text_tokens", "type": "uinteger", "label": "Text Tokens" }, { "name": "image_tokens", "type": "uinteger", "label": "Image Tokens" }, { "name": "audio_tokens", "type": "uinteger", "label": "Audio Tokens" } ], "type": "collection", "label": "Prompt Tokens Details" }, { "name": "completion_tokens_details", "spec": [ { "name": "reasoning_tokens", "type": "uinteger", "label": "Reasoning Tokens" }, { "name": "text_tokens", "type": "uinteger", "label": "Text Tokens" }, { "name": "audio_tokens", "type": "uinteger", "label": "Audio Tokens" }, { "name": "accepted_prediction_tokens", "type": "uinteger", "label": "Accepted Prediction Tokens" }, { "name": "rejected_prediction_tokens", "type": "uinteger", "label": "Rejected Prediction Tokens" } ], "type": "collection", "label": "Completion Tokens Details" } ], "type": "collection", "label": "Usage" }, { "name": "system_fingerprint", "type": "text", "label": "System Fingerprint" } ], "advanced": true }, "onerror": [ { "id": 10, "module": "builtin:Commit", "version": 1, "metadata": { "designer": { "x": 2700, "y": 600 } } } ] }, { "id": 42, "module": "builtin:BasicFeeder", "version": 1, "parameters": {}, "filter": { "name": " ", "conditions": [ [ { "a": "{{7.result.subtasks}}", "b": "{{emptyarray}}", "o": "text:notequal" } ] ] }, "mapper": { "array": "{{7.result.subtasks}}" }, "metadata": { "designer": { "x": 2700, "y": 300 }, "restore": { "expect": { "array": { "mode": "edit", "items": [ null ] } } }, "expect": [ { "mode": "edit", "name": "array", "spec": [], "type": "array", "label": "Array" } ] } }, { "id": 36, "module": "asana:CreateTask", "version": 2, "parameters": { "__IMTCONN__": 32410 }, "mapper": { "destination": "parentTaskMap", "name": "{{42.name}}", "notes": "{{42.description}}", "external": {}, "parent": "{{15.gid}}", "assignee": "{{15.assignee.gid}}" }, "metadata": { "designer": { "x": 3000, "y": 300 }, "restore": { "parameters": { "__IMTCONN__": { "label": "your-asana-connection", "data": { "scoped": "true", "connection": "asana" } } }, "expect": { "destination": { "mode": "chose", "label": "Map Parent Task" }, "workspaceAlt": { "mode": "edit" }, "due": { "mode": "chose", "label": "Empty" }, "resource_subtype": { "mode": "chose", "label": "Empty" }, "liked": { "mode": "chose" }, "completed": { "mode": "chose" }, "workspaceAlt2": { "mode": "edit" }, "workspaceAlt3": { "mode": "edit" }, "workspace": { "mode": "chose", "label": "Empty" }, "assignee_status": { "mode": "chose", "label": "Empty" }, "followers": { "mode": "chose" }, "tags": { "mode": "chose" } } }, "parameters": [ { "name": "__IMTCONN__", "type": "account:asana", "label": "Connection", "required": true } ], "expect": [ { "name": "destination", "type": "select", "label": "Task destination", "required": true, "validate": { "enum": [ "workspace", "projects", "projAndSect", "parentTaskSelect", "parentTaskMap" ] } }, { "name": "name", "type": "text", "label": "Task Name" }, { "name": "notes", "type": "text", "label": "Notes" }, { "name": "html_notes", "type": "text", "label": "HTML Notes" }, { "name": "workspaceAlt", "type": "select", "label": "Workspace ID (for selecting assignees)", "mode": "edit" }, { "name": "due", "type": "select", "label": "Due", "validate": { "enum": [ "date", "datetime" ] } }, { "name": "resource_subtype", "type": "select", "label": "Resource Subtype", "validate": { "enum": [ "approval", "default_task", "milestone" ] } }, { "name": "liked", "type": "boolean", "label": "Liked" }, { "name": "completed", "type": "boolean", "label": "Task Completed?" }, { "name": "external", "type": "collection", "label": "External", "spec": [ { "name": "gid", "type": "text", "label": "External ID", "validate": { "max": 1024 } }, { "name": "data", "type": "text", "label": "External Data" } ] }, { "name": "workspaceAlt2", "type": "select", "label": "Workspace ID (for selecting followers)", "mode": "edit" }, { "name": "workspaceAlt3", "type": "select", "label": "Workspace ID (for selecting tags)", "mode": "edit" }, { "name": "parent", "type": "text", "label": "Parent Task ID", "required": true }, { "name": "workspace", "type": "select", "label": "Workspace ID" }, { "name": "assignee", "type": "any", "label": "Task Assignee ID" }, { "name": "assignee_status", "type": "select", "label": "Assignee Status", "validate": { "enum": [ "inbox", "later", "today", "upcoming" ] } }, { "name": "followers", "type": "array", "label": "Followers", "spec": { "type": "any", "name": "value" } }, { "name": "tags", "type": "array", "label": "Tags", "spec": { "type": "any", "name": "value" } } ] } } ] }, { "flow": [ { "id": 51, "module": "openai-gpt-3:CreateCompletion", "version": 1, "parameters": { "__IMTCONN__": 32472 }, "filter": { "name": "", "conditions": [ [ { "a": "{{38.`__IMTLENGTH__`}}", "b": "0", "o": "text:equal" } ] ] }, "mapper": { "model": "gpt-4o-mini", "top_p": "1", "select": "chat", "messages": [ { "role": "system", "content": "あなたはプロジェクトマネージャーのアシスタントです。\nUserが入力したタスクを分析し、必要なサブタスクのリストをJSON形式で提案してください。\n既に作成されているサブタスクと重複するなど、特にサブタスクの作成が不要な場合は空配列を返してください。\n\n応答は以下の条件を満たす必要があります:\n- subtasksという配列のみを含むJSONを返すこと\n- 各サブタスクには name と description フィールドを含めること\n- サブタスクが不要な場合は空配列を返すこと\n- 説明文には具体的なアクションアイテムを含めること\n- 日本語で記述すること" }, { "role": "user", "content": "## Input\nタスク名: {{15.name}}\nタスク概要: {{15.notes}}\n現在定義済のサブタスク:サブタスク無し", "imageDetail": "auto" } ], "max_tokens": "4096", "temperature": "1", "n_completions": "1", "response_format": "json_object", "parseJSONResponse": true }, "metadata": { "designer": { "x": 2100, "y": 900, "name": "OpenAI" }, "restore": { "expect": { "stop": { "mode": "chose" }, "model": { "mode": "chose", "label": "gpt-4o-mini (system)" }, "select": { "label": "Create a Chat Completion (GPT and o1 models)" }, "messages": { "mode": "chose", "items": [ { "role": { "mode": "chose", "label": "Developer / System" } }, { "role": { "mode": "chose", "label": "User" }, "imageDetail": { "mode": "chose", "label": "Auto" }, "imageInputType": { "mode": "chose", "label": "Empty" } } ] }, "logit_bias": { "mode": "chose" }, "response_format": { "mode": "chose", "label": "JSON Object" }, "parseJSONResponse": { "mode": "chose" }, "additionalParameters": { "mode": "chose" } }, "parameters": { "__IMTCONN__": { "data": { "scoped": "true", "connection": "openai-gpt-3" }, "label": "your-openai-connection" } } }, "parameters": [ { "name": "__IMTCONN__", "type": "account:openai-gpt-3", "label": "Connection", "required": true } ], "expect": [ { "name": "select", "type": "select", "label": "Select Method", "required": true, "validate": { "enum": [ "chat", "prompt" ] } }, { "name": "temperature", "type": "number", "label": "Temperature", "validate": { "max": 2, "min": 0 } }, { "name": "top_p", "type": "number", "label": "Top P", "validate": { "max": 1, "min": 0 } }, { "name": "n_completions", "type": "number", "label": "Number" }, { "name": "frequency_penalty", "type": "number", "label": "Frequency Penalty", "validate": { "max": 2, "min": -2 } }, { "name": "presence_penalty", "type": "number", "label": "Presence Penalty", "validate": { "max": 2, "min": -2 } }, { "name": "logit_bias", "spec": { "name": "value", "spec": [ { "name": "token", "type": "text", "label": "Token ID", "required": true }, { "name": "probability", "type": "number", "label": "Probability", "required": true, "validate": { "max": 100, "min": -100 } } ], "type": "collection", "label": "Token Probability" }, "type": "array", "label": "Token Probability" }, { "name": "seed", "type": "integer", "label": "Seed" }, { "name": "stop", "spec": { "name": "value", "type": "text", "label": "Stop Sequence" }, "type": "array", "label": "Stop Sequences", "validate": { "maxItems": 4 } }, { "name": "additionalParameters", "spec": { "name": "value", "spec": [ { "name": "key", "type": "text", "label": "Parameter Name", "required": true }, { "name": "type", "type": "select", "label": "Input Type", "options": [ { "label": "Text", "value": "text", "nested": [ { "name": "value", "type": "text", "label": "Parameter Value" } ], "default": true }, { "label": "Number", "value": "number", "nested": [ { "name": "value", "type": "number", "label": "Parameter Value" } ] }, { "label": "Boolean", "value": "boolean", "nested": [ { "name": "value", "type": "boolean", "label": "Parameter Value" } ] }, { "label": "Date", "value": "date", "nested": [ { "name": "value", "type": "date", "label": "Parameter Value" } ] }, { "label": "Any", "value": "any", "nested": [ { "name": "value", "type": "any", "label": "Parameter Value" } ] } ] } ], "type": "collection", "label": "Input Parameter" }, "type": "array", "label": "Other Input Parameters" }, { "name": "model", "type": "select", "label": "Model", "required": true }, { "name": "max_tokens", "type": "uinteger", "label": "Max Completion Tokens" }, { "name": "messages", "spec": { "name": "value", "spec": [ { "name": "role", "type": "select", "label": "Role", "options": { "store": [ { "label": "Developer / System", "value": "system", "nested": [ { "help": "Text content of the message on behalf of the selected __Role__.", "name": "content", "type": "text", "label": "Text Content" } ] }, { "label": "User", "value": "user", "nested": [ { "help": "Text content of the message on behalf of the selected __Role__.", "name": "content", "type": "text", "label": "Text Content" }, { "name": "imageInputType", "type": "select", "label": "Image Input Type", "options": [ { "label": "URL", "value": "url", "nested": [ { "help": "Make sure to use a publicly accessible URL.\nYou can test if your image is publicly accessible by opening the link in an incognito tab.", "name": "imageUrl", "type": "url", "label": "Image URL" } ] }, { "label": "Image File", "value": "file", "nested": [ { "name": "imageFile", "spec": [ { "help": "Accepted extensions: `.jpg`, `.jpeg`, `.png`, `.webp` and `.gif`.", "name": "imageFilename", "type": "filename", "label": "Image Filename", "semantic": "file:name", "extension": [ "jpg", "jpeg", "png", "webp", "gif" ] }, { "name": "imageData", "type": "buffer", "label": "Image Data", "semantic": "file:data" } ], "type": "collection", "label": "Image" } ] } ], "mappable": false }, { "name": "imageDetail", "type": "select", "label": "Image Detail", "options": [ { "label": "Auto", "value": "auto", "default": true }, { "label": "High", "value": "high" }, { "label": "Low", "value": "low" } ], "advanced": true } ] }, { "label": "Assistant", "value": "assistant", "nested": [ { "help": "Text content of the message on behalf of the selected __Role__.", "name": "content", "type": "text", "label": "Text Content" } ] } ] }, "required": true } ], "type": "collection", "label": "Message" }, "type": "array", "label": "Messages", "required": true }, { "name": "response_format", "type": "select", "label": "Response Format", "validate": { "enum": [ "text", "json_object" ] } }, { "name": "parseJSONResponse", "type": "boolean", "label": "Parse JSON Response", "required": true } ], "interface": [ { "name": "result", "type": "any", "label": "Result" }, { "name": "id", "type": "text", "label": "ID" }, { "name": "object", "type": "text", "label": "Object" }, { "name": "created", "type": "date", "label": "Created" }, { "name": "model", "type": "text", "label": "Model" }, { "name": "choices", "spec": { "spec": [ { "name": "text", "type": "text", "label": "Text" }, { "name": "index", "type": "number", "label": "Index" }, { "name": "logprobs", "type": "text", "label": "Log Probs" }, { "name": "finish_reason", "type": "text", "label": "Finish Reason" }, { "name": "message", "spec": [ { "name": "role", "type": "text", "label": "Role" }, { "name": "content", "type": "text", "label": "Content" }, { "name": "refusal", "type": "text", "label": "Refusal" } ], "type": "collection", "label": "Message" } ], "type": "collection" }, "type": "array", "label": "Choices" }, { "name": "usage", "spec": [ { "name": "prompt_tokens", "type": "number", "label": "Prompt Tokens" }, { "name": "completion_tokens", "type": "text", "label": "Completion Tokens" }, { "name": "total_tokens", "type": "number", "label": "Total Tokens" }, { "name": "prompt_tokens_details", "spec": [ { "name": "cached_tokens", "type": "uinteger", "label": "Cached Tokens" }, { "name": "text_tokens", "type": "uinteger", "label": "Text Tokens" }, { "name": "image_tokens", "type": "uinteger", "label": "Image Tokens" }, { "name": "audio_tokens", "type": "uinteger", "label": "Audio Tokens" } ], "type": "collection", "label": "Prompt Tokens Details" }, { "name": "completion_tokens_details", "spec": [ { "name": "reasoning_tokens", "type": "uinteger", "label": "Reasoning Tokens" }, { "name": "text_tokens", "type": "uinteger", "label": "Text Tokens" }, { "name": "audio_tokens", "type": "uinteger", "label": "Audio Tokens" }, { "name": "accepted_prediction_tokens", "type": "uinteger", "label": "Accepted Prediction Tokens" }, { "name": "rejected_prediction_tokens", "type": "uinteger", "label": "Rejected Prediction Tokens" } ], "type": "collection", "label": "Completion Tokens Details" } ], "type": "collection", "label": "Usage" }, { "name": "system_fingerprint", "type": "text", "label": "System Fingerprint" } ], "advanced": true } }, { "id": 52, "module": "builtin:BasicFeeder", "version": 1, "parameters": {}, "filter": { "name": " ", "conditions": [ [ { "a": "{{51.result.subtasks}}", "b": "{{emptyarray}}", "o": "text:notequal" } ] ] }, "mapper": { "array": "{{51.result.subtasks}}" }, "metadata": { "designer": { "x": 2400, "y": 900 }, "restore": { "expect": { "array": { "mode": "edit", "items": [ null ] } } }, "expect": [ { "mode": "edit", "name": "array", "spec": [], "type": "array", "label": "Array" } ] } }, { "id": 53, "module": "asana:CreateTask", "version": 2, "parameters": { "__IMTCONN__": 32410 }, "mapper": { "destination": "parentTaskMap", "name": "{{52.name}}", "notes": "{{52.description}}", "external": {}, "parent": "{{15.gid}}", "assignee": "{{15.assignee.gid}}" }, "metadata": { "designer": { "x": 2700, "y": 900 }, "restore": { "parameters": { "__IMTCONN__": { "label": "your-asana-connection", "data": { "scoped": "true", "connection": "asana" } } }, "expect": { "destination": { "mode": "chose", "label": "Map Parent Task" }, "workspaceAlt": { "mode": "edit" }, "due": { "mode": "chose", "label": "Empty" }, "resource_subtype": { "mode": "chose", "label": "Empty" }, "liked": { "mode": "chose" }, "completed": { "mode": "chose" }, "workspaceAlt2": { "mode": "edit" }, "workspaceAlt3": { "mode": "edit" }, "workspace": { "mode": "chose", "label": "Empty" }, "assignee_status": { "mode": "chose", "label": "Empty" }, "followers": { "mode": "chose" }, "tags": { "mode": "chose" } } }, "parameters": [ { "name": "__IMTCONN__", "type": "account:asana", "label": "Connection", "required": true } ], "expect": [ { "name": "destination", "type": "select", "label": "Task destination", "required": true, "validate": { "enum": [ "workspace", "projects", "projAndSect", "parentTaskSelect", "parentTaskMap" ] } }, { "name": "name", "type": "text", "label": "Task Name" }, { "name": "notes", "type": "text", "label": "Notes" }, { "name": "html_notes", "type": "text", "label": "HTML Notes" }, { "name": "workspaceAlt", "type": "select", "label": "Workspace ID (for selecting assignees)", "mode": "edit" }, { "name": "due", "type": "select", "label": "Due", "validate": { "enum": [ "date", "datetime" ] } }, { "name": "resource_subtype", "type": "select", "label": "Resource Subtype", "validate": { "enum": [ "approval", "default_task", "milestone" ] } }, { "name": "liked", "type": "boolean", "label": "Liked" }, { "name": "completed", "type": "boolean", "label": "Task Completed?" }, { "name": "external", "type": "collection", "label": "External", "spec": [ { "name": "gid", "type": "text", "label": "External ID", "validate": { "max": 1024 } }, { "name": "data", "type": "text", "label": "External Data" } ] }, { "name": "workspaceAlt2", "type": "select", "label": "Workspace ID (for selecting followers)", "mode": "edit" }, { "name": "workspaceAlt3", "type": "select", "label": "Workspace ID (for selecting tags)", "mode": "edit" }, { "name": "parent", "type": "text", "label": "Parent Task ID", "required": true }, { "name": "workspace", "type": "select", "label": "Workspace ID" }, { "name": "assignee", "type": "any", "label": "Task Assignee ID" }, { "name": "assignee_status", "type": "select", "label": "Assignee Status", "validate": { "enum": [ "inbox", "later", "today", "upcoming" ] } }, { "name": "followers", "type": "array", "label": "Followers", "spec": { "type": "any", "name": "value" } }, { "name": "tags", "type": "array", "label": "Tags", "spec": { "type": "any", "name": "value" } } ] } } ] } ] } ] } ] } ] } ], "metadata": { "version": 1 } } ```
使ってみた感想
実際に試しで何回か動かしてみた感想としては、意図通り動作すればめっちゃ便利。
ChatGPTがそれっぽい分割案をくれるのはかなり助かる。
ただし、「タスク名が抽象的すぎるとAIの提案が微妙になる」ケースはやっぱり避けられない。
少し具体的なタスク名(「新サービス立ち上げのマーケ施策プラン作成」とか)にするだけで回避はできる。
何も考えずに書き始めるより、AIの提案を見ながら「コレとコレは合体させた方がいいな」「このサブタスクは不要かも」みたいに考えられるので、余計なことに気を回さなくて良いが素晴らしい。
おわりに
AsanaとChatGPTを連携させると、一人で悩んでいた「タスクの分解作業」をそこそこサポートできる。
もちろん丸投げは危険だけど、“自分が考えるきっかけづくり”とか“どこから手を付けるか見当を付ける”程度なら、かなり使えるんじゃないかと感じた。
今後はさらにプロンプトを細かく練ったり、別の機能と組み合わせていきたいところ。
タスク分解以外にも、進捗管理やレポート生成とか、いろいろアイデアが広がりそう。
ではでは。