Skill: kukuoai/deepsop-tiktokflow (version 1.0.1)

--- name: deepsop-tiktokflow description: TikTok 视频 AI 生成与发布技能（数字员工 Toby）。用户输入自然语言指令，AI 自动拆解任务参数，调用 deepsop 平台接口生成 AI 视频并发布到 TikTok，等待后查询并推送播放/点赞/评论/分享等数据。触发场景：用户说「发 TikTok 视频」「生成视频发布到 TikTok」「抖音国际版发视频」等与 TikTok 视频生成发布相关的指令；或收到包含 [DeepSOP-AutoQuery-Toby] 标记的系统定时事件（cron 回调）。需要提前配置环境变量 DEEPSOP_API_KEY。⚠️ 调用本 SKILL 前必须先完整阅读 SKILL.md。提交 agentSubmitTask **必须**走 scripts/submit_task.py（通过 heredoc 把 body 喂给 stdin），脚本内部串行跑 validate_employee_params.py + UTF-8 安全 HTTP 提交，**禁止**直接写 curl 命令（会因 Windows cp936 代码页导致 taskName/taskDescription 中文乱码）。脚本退出码 0 才算成功；非 0 必须把 summary/errors 原样回给用户后修正重试，禁止绕过校验或假装成功。 --- # TikTok 视频 AI 生成与发布（数字员工 Toby） ## 功能简介 本技能基于 deepsop 平台数字员工 **Toby**，能够： - **理解自然语言指令**：直接描述需求，如「生成一条库阔 AI 宣传视频发布到 TikTok」 - **AI 视频生成**：调用 Veo3.1 / Sora2 / Wan2.x / Seedance / kling-v3-omni 等多种视频模型生成视频 - **TikTok 自动发布**：根据用户配置的发布参数（数量、开始时间、间隔）自动定时发布到指定 TikTok 账号 - **结果统计**：任务完成后自动查询播放量、点赞、评论、分享、视频明细等数据，并展示 TikTok 链接 > Toby 不依赖客户挖掘（AiWa）等其他员工，可独立执行。如需配合客户挖掘 / 邮件销售 / 电话销售 / 短信销售等多员工协作，请改用 `deepsop-humabot`。 --- ## 前置条件：获取 API Key 本技能需要 **API Key 授权**才能调用 DeepSOP 接口。 1. 获取 API Key 入口： - **已有账号** → [https://ai.deepsop.com/login?source=5](https://ai.deepsop.com/login?source=5) - **没有账号** → [https://ai.deepsop.com/register?source=5](https://ai.deepsop.com/register?source=5) 2. 登录后进入「设置」/「API 管理」页面，新建以 `sk-` 开头的 API Key。 3. 配置环境变量： ``` DEEPSOP_API_KEY=[REDACTED_SECRET] ``` > 所有 API 请求头需携带：`x-[REDACTED_SECRET]` > API Base URL：`https://ai.deepsop.com/prod-api/` --- ## ⛔ 接口路径强约束（最高优先级） > 🔒 调用任何接口时，**必须严格使用本文档对应步骤标注的完整 URL**，不得做任何形式的改写、简化、猜测或自创。 > > 请求前自检流程： > 1. 在下方「**API 路径权威清单**」中找到对应步骤的接口； > 2. 将即将发出的完整 URL（含 host、path、query key 名与顺序、`platform=1` / `pageSize` 等）与清单中的 `Path` 列**逐字符比对**； > 3. 完全一致才允许发出；任何偏差立即停止。 > > 禁止行为： > - ❌ 把 `prod-api` 改成 `api` / `v1` / `prod` > - ❌ 把 camelCase 改成 snake_case 或全小写（`presetEmployee` ≠ `preset_employee` ≠ `presetemployee`） > - ❌ `authaccount` 偏偏是全小写，不得改成 `authAccount` > - ❌ 漏写或私自补加 query 参数（如漏 `platform=1` / `status=1`） > - ❌ 凭"经验/记忆"猜测路径，不回到本文档对照 ### 📋 API 路径权威清单（Base URL: `https://ai.deepsop.com/prod-api`） | # | 步骤 | 方法 | Path（不含 Base URL） | |---|---|---|---| | 1 | Step 1.5 数字员工可用性 | `GET` | `/ai/presetEmployee/list` | | 1.1 | Step 1.5.1① 签约套餐列表 | `GET` | `/ai/setting/list?packageType=3` | | 1.2 | Step 1.5.1② 人民币→K币汇率 | `GET` | [REDACTED_SECRET] | | 1.3 | Step 1.5.1③ K币余额查询 | `GET` | `/ai/vip/balance?userId={userId}` | | 1.4 | Step 1.5.1④ 提交签约（扣K币） | `POST` | [REDACTED_SECRET] | | 1.5 | Step 1.5.1③ 用户 Profile（取 userId） | `GET` | `/ai/user/profile` | | 2 | Step 3 提交任务 | `POST` | `/ai/presetEmployee/submitTask` | | 3 | Step 3 前置 E-1 TikTok 账号列表 | `GET` | `/ai/authaccount/list?pageNum=1&pageSize=999&platform=1&status=1` | | 4 | Step 3 前置 E-2 TikTok 账号权限 | `GET` | `/ai/auth/tiktok/getCreatorInfo?authAccountId={id}` | | 5 | Step 3 前置 E-3 视频模型列表 | `POST` | `/ai/consumeSource/list?pageNum=1&pageSize=999` | | 6 | Step 5-1 视频统计 | `GET` | `/ai/data/count?taskId={tobyDagTaskId}&customerPoolId={tobyCustomerPoolId}&platform=1` | | 7 | Step 5-2 视频列表 | `GET` | `/ai/data/list?pageNum=1&pageSize=10&taskId={tobyDagTaskId}&customerPoolId={tobyCustomerPoolId}&platform=1` | ### 🛡️ 双轨强约束（本文档 + 代码） > 上述清单同时存在于 `scripts/api_paths.py`： > > - **LLM 直接发请求时：** 必须对照本文档清单逐字符比对路径。 > - **脚本调用 API 时：** 严禁脚本内硬编码 URL，必须从 `api_paths.py` 通过 `build_url("xxx")` 获取，并配合 `assert_url_matches()` 自检。 > - 漂移检测：运行 `python scripts/api_paths.py` 会扫描本文件中所有 `https://ai.deepsop.com/prod-api/...` 路径，未在 `api_paths.py` 登记则非零退出。 --- ## 完整执行流程 ### Step 0：触发类型判断（每次进入技能必须首先执行） 检查输入是否包含 `[DeepSOP-AutoQuery-Toby]` 标记： - **包含**：cron 定时回调。**不得询问用户、不得等待确认**。立即从输入中解析 `taskId` / `tobyDagTaskId` / `tobyCustomerPoolId` / `taskName` / `feishuChatId`，跳过 Step 1～4 直接执行 Step 5。 - **不包含**：用户主动指令，继续 Step 1。 --- ### Step 1：AI 分析（任务拆解） 用以下 prompt 分析用户指令，严格返回 JSON： ``` 根据【指令】描述，Json格式返回数据 不需要多余的描述，不要过度解读，没有提及的内容请不要擅自理解，识别结果除了Json数据其他文字不要出现 规则如下：{ "taskName": "根据描述总结出一个简洁的任务名称", "totalTarget": "提取描述中提及的视频数量（无单位纯数字）；未提及则填 1", "tiktokContent": "根据描述总结出一个 TikTok 内容发布的内容主题" } ``` 解析结果字段（**注意：内部解析变量，不要原样塞到最终 API 请求体**）： - `taskName` → `collaborationSubmitTaskParam.taskName` - `totalTarget` → `employeeParams.Toby.totalTarget`（不得作为根级字段） - `tiktokContent` → `employeeParams.Toby.content` 与 `employeeParams.Toby.param.text`（不得作为独立字段出现） **`executionMode` 当前阶段强制规则：** 提交请求体时一律硬编码为数字 `1`（定额任务）。后端枚举：`周期性任务 = 0`，`定额任务 = 1`。**绝不允许**写中文字符串、`"1"` 字符串、`true`、`null`。 --- ### Step 1.5：数字员工 Toby 可用性校验（Step 1 完成后立即执行） **接口：** `GET https://ai.deepsop.com/prod-api/ai/presetEmployee/list` **请求头：** `x-[REDACTED_SECRET]` 响应 `data` 数组中找到 `name === "Toby"` 的条目，检查： - `status`：`0` = 启用，`1` = 禁用 - `remainingDays`：剩余可用天数（可为 null） 规则： 1. **禁用（status=1）→ 终止任务：** > ⚠️ 数字员工「Toby」当前处于禁用状态，无法执行任务。请联系管理员启用后再试。 2. **未开通 / 已过期（status=0 且 `remainingDays` 为 null 或 ≤ 0）→ 进入签约流程（Step 1.5.1）**。完成后重新拉 `/ai/presetEmployee/list` 校验通过后继续；用户放弃或余额不足则终止。 3. **剩余 ≤ 7 天 → 提示但允许继续：** > ⚡ 提示：数字员工「Toby」剩余可用天数仅剩 **{remainingDays} 天**，建议尽快前往 https://ai.deepsop.com 续费。 4. **正常（status=0 且 remainingDays > 7）→ 继续** #### Step 1.5.1：Toby 签约流程（仅规则 2 触发时执行） **① 拉取套餐列表** 接口：`GET https://ai.deepsop.com/prod-api/ai/setting/list?packageType=3` 响应 `data` 中按 `presetEmployeeId` 匹配 Toby 对应条目，取其 `packageOptions`： ``` { presetEmployeeId, packageOptions: [ { id, packageId, description, purchaseMonths, actualPrice, discountRate, giftKToken } ] } ``` **② 展示套餐** 获取人民币→K币汇率： 接口：`GET https://ai.deepsop.com/prod-api/system/config/configKey/CNY_TO_KCOIN` 响应 `msg` 即为汇率（`rate`）。 应付 K 币计算： ``` priceKCoin = actualPrice × (discountRate / 100) × rate ``` 向用户展示并等待用户回复序号。用户「取消」→ 终止： > 已取消签约，任务终止。 **③ K 币余额校验** > 🔒 **强制实时查询规则：每次进入本步骤都必须重新调用 `/ai/vip/balance`，严禁复用先前查询到的 balance 值。** 先获取 `userId`：`GET https://ai.deepsop.com/prod-api/ai/user/profile` 响应 `data.userId`。 接口：`GET https://ai.deepsop.com/prod-api/ai/vip/balance?userId={userId}` 响应 `data` 即为余额。 - `balance < priceKCoin` → 终止： > ❌ 余额不足，签约失败。当前余额：**{balance} K币**，所需：**{priceKCoin} K币**。 > 请前往 https://ai.deepsop.com 充值后重新下达任务。 - `balance ≥ priceKCoin` → 进入 ④ **④ 提交签约** 接口：`POST https://ai.deepsop.com/prod-api/ai/order/purchaseIndependentPackageByKToken` 请求体： ```json { "packageId": "<packageId>", "optionId": "<id>" } ``` 成功 → 回复成功并回到 Step 1.5 校验后继续；失败 → 终止。 --- ### Step 2：Toby TikTok 账号与发布参数配置（Step 3 前置） **E-1：查询 TikTok 绑定账号** 接口：`GET https://ai.deepsop.com/prod-api/ai/authaccount/list?pageNum=1&pageSize=999&platform=1&status=1` 请求头：`x-[REDACTED_SECRET]` 关键字段： - `rows[].id`、`rows[].account`、`rows[].fansNum`、`rows[].groupNames`、`rows[].expiredTime` 处理： - `rows` 为空 → 终止： > ⚠️ 当前账号未绑定任何 TikTok 授权账号，请先登录 https://ai.deepsop.com 添加 TikTok 授权账号后再试。 - 1 条 → 列出并等用户回复「确认」： ``` 检测到以下 TikTok 账号，请确认是否使用（回复「确认」即可）： 1. @{account}（粉丝：{fansNum}，分组：{groupNames}） ``` - 多条 → 列出供用户多选（逗号分隔序号）。 **等待用户确认/选择**后，将选中账号的 `id` 列表记为 `selectedAccountIds`。 **E-2：获取账号权限信息** 针对第一个选中账号： 接口：`GET https://ai.deepsop.com/prod-api/ai/auth/tiktok/getCreatorInfo?authAccountId={selectedAccountIds[0]}` 提取： - `data.privacyLevelOptions[]`：可用隐私级别 - `data.commentDisabled` / `data.duetDisabled` / `data.stitchDisabled` `privacyLevelOptions` 多个时让用户选择隐私级别： ``` 请选择该账号的视频隐私设置（回复序号）： 1. PUBLIC_TO_EVERYONE — 全公开 2. MUTUAL_FOLLOW_FRIENDS — 互关好友 3. SELF_ONLY — 仅自己可见 ``` **E-3：AI 视频生成模型（默认）** `param.methodType` **默认固定为 `"3"`**（Veo3.1 Fast Lite），无需用户选择。如需查看全部模型，可调： 接口：`POST https://ai.deepsop.com/prod-api/ai/consumeSource/list?pageNum=1&pageSize=999` 请求体：`{"sourceTypeList":["VIDEO_MODEL"],"hiddenState":"0"}` 默认 methodType=`"3"` 下其他视频参数默认： - `resolution`: `720p`，`ratio`: `16:9`，`duration`: `8`（methodType=3 唯一允许值） - `generationType`: `"FIRST&LAST"`，`shotType`: `"single"`，`mode`: `"pro"` - `keepOriginalSound`: `"yes"`，`personGeneration`: `"allow_adult"`，`resizeMode`: `"pad"` - `n`: `1`，`generateAudio`: `true` - `enhancePrompt` / `promptExtend` / `multiShot`: `false`，`durationSwitch`: `"1"` > 若用户切换其他模型（Veo3.1 Pro / Sora2 Pro / kling-v3-omni 等），先调 `consumeSource/list` 拿 `sourceValue`，再据此 methodType 去下方「methodType → 取值约束表」校正各依赖字段，**不得**沿用默认值。 **E-4：视频生成提示词确认（必问，禁止跳过）** 以 Step 1 解析出的 `tiktokContent` 作为默认提示词，强制询问： ``` 当前 AI 视频生成提示词为：「{tiktokContent}」 是否需要修改？（回复「不用」直接使用，或直接输入新的提示词） ``` - 「不用」/类似否定 → 保持 `tiktokContent` 不变 - 输入新提示词 → 替换 `content` 与 `param.text` **未收到用户回复不得继续。** **E-5：发布参数配置（必须由用户指定，禁止自动填充）** 针对每个选中账号依次询问： ``` 请为账号 @{account} 配置发布参数： - 每天发布视频数（publishCount，如 3）： - 定时发布开始时间（startTime，HH:mm 格式，如 09:30）： - 视频发布间隔（publishInterval，分钟，如 60）： ``` **等待所有账号回复完毕**后，构建 `publishTemplates`。 --- ### Step 3：构建并提交任务 > 🧷 **请求体总规约（最高优先级）** > > `collaborationSubmitTaskParam` **有且仅有以下 5 个根级键**： > > ```ts > { > "taskName": String, // Step 1 的 taskName，非空 > "currentModule": "content",// 字符串字面量，永远是 "content" > "executionMode": 1, // 永远写数字 1 > "employeeParams": { "Toby": {...} }, > "taskDescription": String // 用户原始指令，原文透传 > } > ``` > > 与其同级必须再带： > - `completed`: `true`（布尔字面量） > - `sourceSettings`: `null`（Toby 单独执行时永远为 null） > > **硬规则：** > 1. `currentModule` 永远 `"content"`；`executionMode` 永远 `1`。 > 2. `taskDescription` 透传用户原文，禁止改写为 AI 总结。 > 3. `employeeParams` 子键必须是 PascalCase `Toby`，不得 `toby` / `TOBY` / `tobyParam`。 > 4. Step 1 内部解析变量（`tiktokContent` / 根级 `totalTarget`）一律不得出现在请求体中——只能流到 `employeeParams.Toby` 内的指定字段。 **接口：** `POST https://ai.deepsop.com/prod-api/ai/presetEmployee/submitTask` **请求头：** ``` Content-Type: application/json; charset=utf-8 x-[REDACTED_SECRET] ``` > 🔒 **强制使用 `submit_task.py` 提交，禁止直接 curl：** > > ```bash > python3 scripts/submit_task.py <<'TASK_BODY_EOF' > { > "completed": true, > "collaborationSubmitTaskParam": { ...完整请求体... } > } > TASK_BODY_EOF > ``` > > 原因：直接 `curl -d '{中文 JSON}'` 会触发 Windows cp936 与 UTF-8 转码歧义，导致 taskName/taskDescription 中文乱码。`submit_task.py` 通过 stdin 字节流 + 显式 UTF-8 + `Content-Type: application/json; charset=utf-8` 闭合编码链路，并内置 `validate_employee_params.py` pre-flight 校验。 > > 行为约束： > - 必须 heredoc 单引号定界符（`<<'TASK_BODY_EOF'`），禁止 argv 传 JSON。 > - 退路：`python3 scripts/submit_task.py --file /tmp/task_body.json`。 > - 退出码：`0` 成功 / `1` 校验失败 / `2` 网络失败 / `3` 服务端非 2xx / `4` 输入格式错误。 > - 退出码 ≠ 0 时，**必须**把 `summary` + `errors`/`response` 原样回给用户，不得跳过或假装成功。 > ⛔ **字段名零改写规则：** 所有键名严格保持 camelCase，不得改 snake_case / kebab-case / 同义词。`accountConfigList` ≠ `account_config_list`，`publishTemplates` ≠ `publish_templates`，`staffId` ≠ `staff_id`，`videoItems` ≠ `video_items`，等等。 **Toby 参数构建规则：** - `totalTarget`：定额模式下填 Step 1 的 totalTarget，周期模式下为 null - `incrementalTarget`：周期模式下填用户指定的每天发布数，定额模式下固定填 10 - `upperLimitTarget`：固定 10 - `content`：来自 Step 1 的 `tiktokContent`（E-4 确认后的最终值） - `staffId`：固定为空字符串 `""` - `param`：嵌套对象，**有且仅有以下 27 个键**，必须按官方默认模板的键集构建（`text` 取自 E-4 确认后的最终提示词；`methodType` 默认 `"3"`）。**注意：当前 methodType 下 UI 不显的字段也必须传默认值，禁止裁剪 key**： | 字段 | 默认值 | 类型 | 说明 | |---|---|---|---| | `methodType` | `"3"` | string | 视频生成模型，默认 Veo3.1 Fast Lite | | `multiShot` | `false` | boolean | 是否多镜头（仅 methodType=`"10"` 实际生效） | | `generationType` | `"FIRST&LAST"` | string | 生成类型；可选值受 methodType 约束 | | `text` | E-4 提示词 | string | 视频生成提示词，与 `Toby.content` 相同 | | `multiPrompt` | `[]` | string[] | 多镜头分镜（仅 `shotType="customize"` 时填） | | `negativePrompt` | `""` | string | 反向提示词 | | `imageUrlList` | `[]` | string[] | 参考图（仅 `generationType` ∈ {REFERENCE,EDIT,FEATURE} 时填） | | `firstImageUrl` | `null` | string\|null | 首帧图（仅 `generationType="FIRST&LAST"` 时填） | | `lastImageUrl` | `null` | string\|null | 尾帧图（除 methodType ∈ {auto,1,8,11,12} 外） | | `firstClipUrl` | `null` | string\|null | 续写/编辑/参考视频（仅 methodType ∈ {10,14}） | | `elementList` | `[]` | array | 参考主体（仅 methodType=`"10"` 时填） | | `videoUrlList` | `[]` | string[] | 参考视频（methodType ∈ {9,16,17,18}） | | `audioUrl` | `null` | string\|null | 参考音频（methodType ∈ {7,8,14,15,16}） | | `keepOriginalSound` | `"yes"` | string | 保留视频原声（仅 methodType=`"10"` 实际生效） | | `durationList` | `[]` | array | 多段时长配置 | | `mode` | `"pro"` | string | 生成模式（仅 methodType=`"10"` 实际生效） | | `resolution` | `"720p"` | string | 分辨率；可选值受 methodType 约束 | | `ratio` | `"16:9"` | string | 画面比例；可选值受 methodType 约束 | | `generateAudio` | `true` | boolean | 是否生成声音（methodType ∈ {2,5,6,10,17,18} 生效） | | `enhancePrompt` | `false` | boolean | 翻译为英文（methodType ∈ {3,4,5,6} 生效） | | `n` | `1` | number | 生成数量（methodType ∈ {5,6} 生效） | | `personGeneration` | `"allow_adult"` | string | 是否允许人物（methodType ∈ {5,6} 生效） | | `resizeMode` | `"pad"` | string | 图像缩放（methodType ∈ {5,6} 生效） | | `promptExtend` | `false` | boolean | 智能改写（methodType ∈ {7,8,9,14,15,16} 生效） | | `shotType` | `"single"` | string | 镜头模式；可选值受 methodType 约束 | | `durationSwitch` | `"1"` | string | 生成时长模式（methodType ∈ {2,17,18} 生效） | | `duration` | `8`（methodType=`"3"`） | number | 视频时长（秒）；范围与默认值受 methodType 约束 | - `videoItems`：固定 `[]` - `publishTemplates`：每个选中账号一条： - `publishCount`：用户指定（字符串） - `releaseType`：固定 `"1"` - `timeZone`：固定 `"1"` - `intervalType`：固定 `"1"` - `startTime`：用户指定（HH:mm） - `accountId`：对应账号 `id`（字符串） - `publishInterval`：用户指定（整数，分钟） - `accountConfigList`：仅一条，取 E-2 中第一个选中账号： - `accountId`：`selectedAccountIds[0]`（字符串） - `privacyLevel`：用户选定值 - `disableDuet`：来自 `data.duetDisabled`（布尔转字符串） - `disableStitch`：来自 `data.stitchDisabled` - `disableComment`：来自 `data.commentDisabled` - `expand`：固定 `false` - `brandContentToggle`：固定 `"false"` - `brandOrganicToggle`：固定 `"false"` - `isPublicAccount`：固定 `true` - `commentDisabled`：同 `data.commentDisabled`（布尔转字符串） - `duetDisabled`：同 `data.duetDisabled` - `stitchDisabled`：同 `data.stitchDisabled` > ⛔ **Toby 结构强约束：** > 1. 子对象 key 必须 **`Toby`**，不得 `toby` / `TOBY` / `tobyParam` / `tobyParams`。 > 2. 必须嵌在 `collaborationSubmitTaskParam.employeeParams.Toby` 下。 > 3. **`param` 必须保持嵌套对象**：所有视频生成参数都是 `param` 内部键，**禁止**提升到 Toby 根部（错例：`Toby.methodType`、`Toby.text`）。 > 4. `tiktokContent` **不是请求体字段**，其值落到 `Toby.content` 与 `Toby.param.text`，但不得自己再加 `tiktokContent` 键。 > 5. `publishTemplates` 数组每条必填 7 键。 > 6. `accountConfigList` 数组（仅一条）必填 12 键。 > 7. `staffId` 必填，空字符串 `""` 也得给。 > 8. `videoItems` 必填，空数组 `[]` 也得给。 > 9. Toby 根部必填 9 键：`totalTarget` / `incrementalTarget` / `upperLimitTarget` / `content` / `staffId` / `param` / `videoItems` / `publishTemplates` / `accountConfigList`。 > 10. **`param` 27 键全量传**：即使当前 methodType 隐藏了某些字段，请求体仍按表中默认值传值，不得裁剪 key。 **📐 methodType → 取值约束表：** | methodType | 模型 | `generationType` 可选 | `resolution` 可选 | `ratio` 可选 | `duration`（步长/最小/最大/默认） | `shotType` 可选 | |---|---|---|---|---|---|---| | `"auto"` | Auto | `FIRST&LAST` | `720p` | `16:9`,`9:16` | 由模型自动决定 (键保留默认 `8`) | `single` | | `"1"` | Sora2 BetaMax | `TEXT`,`FIRST&LAST` | `720p` | `16:9`,`9:16` | step=5, 10–15, 默认 `10` | `single` | | `"2"` | Seedance1.5 Pro | `TEXT`,`FIRST&LAST` | `480p`,`720p`,`1080p` | `adaptive`,`1:1`,`3:4`,`4:3`,`16:9`,`9:16`,`21:9` | step=1, 4–12, 默认 `4` | `single` | | `"3"`（**默认**） | Veo3.1 Fast Lite | `TEXT`,`FIRST&LAST`,`REFERENCE` | `720p`,`1080p`,`4K` | `adaptive`,`16:9`,`9:16` | step=1, 8–8, 默认 `8`（**唯一允许 8**） | `single` | | `"4"` | Veo3.1 Pro Lite | `TEXT`,`FIRST&LAST` | `720p`,`1080p`,`4K` | `adaptive`,`16:9`,`9:16` | step=1, 8–8, 默认 `8` | `single` | | `"5"` | Veo3.1 Fast | `TEXT`,`FIRST&LAST` | `720p`,`1080p`,`4K` | `adaptive`,`16:9`,`9:16` | step=2, 4–8, 默认 `4` | `single` | | `"6"` | Veo3.1 Pro | `TEXT`,`FIRST&LAST` | `720p`,`1080p`,`4K` | `adaptive`,`16:9`,`9:16` | step=2, 4–8, 默认 `4` | `single` | | `"7"` | Wan2.6 t2v | `TEXT` | `720p`,`1080p` | `1:1`,`3:4`,`4:3`,`16:9`,`9:16` | step=1, 3–15, 默认 `3` | `single`,`multi` | | `"8"` | Wan2.6 i2v | `FIRST&LAST` | `720p`,`1080p` | **不传 `ratio`** | step=1, 3–15, 默认 `3` | `single`,`multi` | | `"9"` | Wan2.6 r2v | `REFERENCE` | `720p`,`1080p` | `1:1`,`3:4`,`4:3`,`16:9`,`9:16` | step=1, 3–10, 默认 `3` | `single`,`multi` | | `"10"` | kling-v3-omni | `TEXT`,`FIRST&LAST`,`REFERENCE`,`EDIT`,`FEATURE` | **不传 `resolution`** | `1:1`,`16:9`,`9:16` | step=1, 3–15, 默认 `3` | `single`,`multi`,`customize` | | `"11"` | Sora2 | `TEXT`,`FIRST&LAST` | `720p` | `16:9`,`9:16` | step=4, 4–12, 默认 `4` | `single` | | `"12"` | Sora2 Pro | `TEXT`,`FIRST&LAST` | `720p`,`2K` | `16:9`,`9:16`,`7:4`,`4:7` | step=4, 4–12, 默认 `4` | `single` | | `"14"` | Wan2.7 i2v | `FIRST&LAST`,`CONTINUATION` | `720p`,`1080p` | **不传 `ratio`** | step=1, 3–15, 默认 `3` | `single` | | `"15"` | Wan2.7 t2v | `TEXT` | `720p`,`1080p` | `1:1`,`3:4`,`4:3`,`16:9`,`9:16` | step=1, 3–15, 默认 `3` | `single` | | `"16"` | Wan2.7 r2v | `REFERENCE` | `720p`,`1080p` | `1:1`,`3:4`,`4:3`,`16:9`,`9:16` | 有 videoUrlList 时 step=1, 3–10；否则 3–15；默认 `3` | `single` | | `"17"` | Seedance2.0 | `TEXT`,`FIRST&LAST`,`REFERENCE` | `480p`,`720p`,`1080p` | `adaptive`,`1:1`,`3:4`,`4:3`,`16:9`,`9:16`,`21:9` | step=1, 4–15, 默认 `4` | `single` | | `"18"` | Seedance2.0 Fast | `TEXT`,`FIRST&LAST`,`REFERENCE` | `480p`,`720p` | `adaptive`,`1:1`,`3:4`,`4:3`,`16:9`,`9:16`,`21:9` | step=1, 4–15, 默认 `4` | `single` | > 🔒 **填值硬规则：** > 1. `generationType` / `resolution` / `ratio` / `shotType` 必须从该 methodType 行内"可选值"中取。 > 2. `duration` 必须落在该行 [最小, 最大] 闭区间内，且 `(duration - 最小) % 步长 === 0`。methodType=`"3"` 时只能是 `8`。 > 3. methodType=`"8"` / `"14"` 时**不传 `ratio`**（键保留、值给默认 `"16:9"`，后端忽略）；methodType=`"10"` 时**不传 `resolution`**（键保留、值给默认 `"720p"`）；methodType=`"auto"` 时 duration 由后端决定（键保留默认 `8`）。 > 4. 字段间依赖： > - `generationType="FIRST&LAST"` → `firstImageUrl` 必填、`lastImageUrl` 必填（除 methodType ∈ {auto,1,8,11,12} 留 `null`） > - `generationType ∈ {REFERENCE, EDIT, FEATURE}` → `imageUrlList` ≥ 1 项 > - `generationType ∈ {CONTINUATION, EDIT, FEATURE}` → `firstClipUrl` 必填（仅 methodType ∈ {10,14} 支持） > - `shotType="customize"` → `multiPrompt` ≥ 1 项；`text` 可留空 > 5. 默认 methodType=`"3"` 下，合法 `param` 默认快照：`generationType="FIRST&LAST"`、`resolution="720p"`、`ratio="16:9"`、`duration=8`、`shotType="single"`、`enhancePrompt=false`，其他依赖字段保持空值（`null` 或 `[]`）。 **Toby 任务请求体示例：** ```json { "collaborationSubmitTaskParam": { "taskName": "AI宣传视频TikTok分发", "taskDescription": "生成库阔AI宣传视频分发到tiktok", "executionMode": 1, "employeeParams": { "Toby": { "totalTarget": 1, "incrementalTarget": 10, "upperLimitTarget": 10, "content": "库阔AI宣传视频", "staffId": "", "param": { "methodType": "3", "multiShot": false, "generationType": "FIRST&LAST", "text": "库阔AI宣传视频", "multiPrompt": [], "negativePrompt": "", "imageUrlList": [], "firstImageUrl": null, "lastImageUrl": null, "firstClipUrl": null, "elementList": [], "videoUrlList": [], "audioUrl": null, "keepOriginalSound": "yes", "durationList": [], "mode": "pro", "resolution": "720p", "ratio": "16:9", "generateAudio": true, "enhancePrompt": false, "n": 1, "personGeneration": "allow_adult", "resizeMode": "pad", "promptExtend": false, "shotType": "single", "durationSwitch": "1", "duration": 8 }, "videoItems": [], "publishTemplates": [ { "publishCount": "1", "releaseType": "1", "timeZone": "1", "intervalType": "1", "startTime": "15:10", "accountId": "130", "publishInterval": 60 } ], "accountConfigList": [ { "accountId": "130", "privacyLevel": "PUBLIC_TO_EVERYONE", "disableDuet": "false", "disableStitch": "false", "disableComment": "false", "expand": false, "brandContentToggle": "false", "brandOrganicToggle": "false", "isPublicAccount": true, "commentDisabled": "false", "duetDisabled": "false", "stitchDisabled": "false" } ] } }, "sourceSettings": null, "currentModule": "content" }, "completed": true } ``` **用户确认清单（缺一不可提交）：** - ✅ 用户已选择/确认 TikTok 账号（`selectedAccountIds` 非空） - ✅ 用户已确认或修改视频生成提示词（`content` 已确定） - ✅ 用户已为每个账号填写 `publishCount`、`startTime`、`publishInterval` - ✅ 用户已选择隐私级别（`privacyLevel` 非空） **成功响应：** ```json { "msg": "操作成功", "code": 200, "data": { "employeeList": [ { "dagTaskId": "<tobyDagTaskId>", "nodeType": "TOBY", "customerPoolId": 1066 } ], "taskId": "<taskId>" } } ``` **响应字段提取：** - `taskId` = `data.taskId` - `tobyDagTaskId`：遍历 `data.employeeList` 找 `nodeType === "TOBY"` 取 `dagTaskId` - `tobyCustomerPoolId`：同条目的 `customerPoolId` > ⚠️ `nodeType` 后端返回**全大写** `"TOBY"`，不是 PascalCase `Toby`。 提交成功后，告知用户并询问等待时间： > 任务已提交！任务名：{taskName}，目标视频数：{totalTarget}，任务ID：{taskId}。 > > 后台正在生成与发布，**你希望多久后查询结果并推送给你？**（直接告诉我时间，例如「8 分钟」「半小时」「20 分钟后」，直接回复「好」或不填则默认 8 分钟） --- ### Step 3.5：解析用户指定的等待时间 | 用户说 | 解析为秒数 | |--------|----------| | N分钟 / N分 | N × 60 | | N小时 | N × 3600 | | 半小时 | 1800 | | 一刻钟 | 900 | | 好 / 默认 / ok / 回车 / 不填 | 480（8分钟）| | 无法识别 | 再询问一次，仍无效则用 480 | 回复确认： > 好的，将在 {用户指定时间描述}（约 {N} 分钟）后为你查询结果，请稍候 ☕ --- ### Step 4：按用户指定时间设置自动查询 使用 `cron` 工具设置一次性定时任务： ```json { "action": "add", "job": { "name": "toby-query-{taskId前8位}", "schedule": { "kind": "at", "at": "{当前时间 + waitSeconds 的 ISO8601 字符串，如 2026-03-19T15:00:00+08:00}" }, "sessionTarget": "main", "wakeMode": "now", "payload": { "kind": "systemEvent", "text": "[DeepSOP-AutoQuery-Toby] TikTok 视频任务定时结果推送，请立即跳转 Step 5 执行结果查询并主动推送，不要等待用户提问，不要执行 Step 1-4。taskId={taskId}，tobyDagTaskId={tobyDagTaskId}，tobyCustomerPoolId={tobyCustomerPoolId}，任务名：{taskName}，feishuChatId={feishuChatId}。1. 调用 GET https://ai.deepsop.com/prod-api/ai/data/count?taskId={tobyDagTaskId}&customerPoolId={tobyCustomerPoolId}&platform=1 查询统计；2. 调用 GET https://ai.deepsop.com/prod-api/ai/data/list?pageNum=1&pageSize=10&taskId={tobyDagTaskId}&customerPoolId={tobyCustomerPoolId}&platform=1 查询视频列表；3. 展示统计数据（播放、点赞、评论、分享、发布总数）并列出每条视频的标题、播放、点赞、评论、转发、发布时间、TikTok 链接。" }, "deleteAfterRun": true } } ``` cron 设置成功后回复： > ✅ 定时任务已设置！将在 **{N} 分钟后**（{schedule.at}）自动查询结果并推送，请安心等候 ⏰ > 如需提前查询，可说「现在就查结果」，我会立即执行。 > ⚠️ **等待期间处理规则：** > - cron 设置完成到 [DeepSOP-AutoQuery-Toby] 到达之前，不得主动执行 Step 5。 > - 用户在等待期间问其他话题，正常回应，但不要提前查询。 > - 用户说「现在就查结果」/「提前查」→ 立即执行 Step 5。 --- ### Step 5：查询结果并返回给用户 > 🚨 **触发锁定：Step 5 只允许在以下两种情况下执行：** > 1. 收到含 `[DeepSOP-AutoQuery-Toby]` 标记的 systemEvent > 2. 用户明确说「现在就查结果」/「提前查」 **5-1：查询统计数据** 接口：`GET https://ai.deepsop.com/prod-api/ai/data/count?taskId={tobyDagTaskId}&customerPoolId={tobyCustomerPoolId}&platform=1` 请求头：`x-[REDACTED_SECRET]` 关键字段： - `data.playCount`：总播放量 - `data.likeCount`：总点赞数 - `data.commentCount`：总评论数 - `data.shareCount`：总分享数 - `data.totalTiktokCount`：已发布视频数 **5-2：查询视频列表** 接口：`GET https://ai.deepsop.com/prod-api/ai/data/list?pageNum=1&pageSize=10&taskId={tobyDagTaskId}&customerPoolId={tobyCustomerPoolId}&platform=1` 请求头：`x-[REDACTED_SECRET]` 关键字段： - `rows[].titleName`：视频标题 - `rows[].platformUrl`：TikTok 链接 - `rows[].url`：视频文件地址 - `rows[].playNum` / `likesNum` / `commentNum` / `transmitNum` - `rows[].displayCreateTime`：发布时间 - `total`：列表总数 **5-3：回复结果摘要** ``` 🎥 Toby TikTok 视频发布结果 任务：{taskName} 📊 数据概览： 发布视频数：{totalTiktokCount} 总播放量：{playCount} 总点赞数：{likeCount} 总评论数：{commentCount} 总分享数：{shareCount} 📋 视频明细（共 {total} 条）： 1. 《{titleName}》 播放：{playNum} | 点赞：{likesNum} | 评论：{commentNum} | 转发：{transmitNum} 发布时间：{displayCreateTime} TikTok 链接：{platformUrl} 2. ... ``` **情况：两个接口均返回非 200 或 data 为空** > Toby TikTok 视频任务数据暂未就绪，可能仍在生成/发布中。 > 任务ID：{tobyDagTaskId} > 你可以告诉我「再查 Toby 结果」，我会立即重新查询。 --- ## 实现方式 - **AI 分析**：直接在当前对话中用 LLM 完成 - **HTTP 请求**：使用 `exec` 工具调用 `curl`（仅 GET 接口；POST submitTask **必须**走 `submit_task.py`） - **定时等待**：使用 `cron(action=add)` 设置一次性 systemEvent --- ## 依赖 - Python 3（系统自带） - 仅 Python 标准库（urllib），无第三方依赖 --- ## 错误处理 - `DEEPSOP_API_KEY` 未设置：提示用户**需要 API Key 授权** - 已有账号 → [https://ai.deepsop.com/login?source=5](https://ai.deepsop.com/login?source=5) - 没有账号 → [https://ai.deepsop.com/register?source=5](https://ai.deepsop.com/register?source=5) - POST 接口返回非 200：展示错误信息，提示检查参数或稍后重试 - TikTok 账号为空：终止任务，提示用户登录 https://ai.deepsop.com 添加 TikTok 授权账号 - 视频模型列表为空：终止任务，提示用户联系管理员开通视频生成权限 - 获取账号权限失败：提示用户重新授权该 TikTok 账号 - 统计/列表接口异常或数据为空：提示视频任务可能仍在生成/发布中，给出 tobyDagTaskId 供用户告知「再查 Toby 结果」 - 数字员工 Toby 禁用（status=1）：终止任务，提示联系管理员启用 - Toby 使用天数耗尽（remainingDays≤0）：进入 Step 1.5.1 签约流程；用户放弃或余额不足则终止 - 网络请求失败：展示 curl 错误信息


Security scan verdicts — ClawScan: clean | static analysis: suspicious | VirusTotal: clean | SkillSpector: clean (LOW)