🔄 卡若AI 同步 2026-03-09 22:22 | 更新:卡木、运营中枢工作台 | 排除 >20MB: 11 个

This commit is contained in:
2026-03-09 22:22:54 +08:00
parent c35c03aa5d
commit 9832ec0ba1
4 changed files with 370 additions and 45 deletions

View File

@@ -1,88 +1,411 @@
---
name: 抖音发布
description: 通过抖音开放平台实现抖音登录OAuth与视频发布。与 Soul 竖屏成片、视频切片联动,将成片一键发布到抖音。若使用存客宝/腕推等矩阵工具发布抖音,可在此 Skill 补充对接方式。
triggers: 抖音发布、发布到抖音、抖音登录、抖音上传、腕推抖音
description: >
纯 API 命令行方式发布视频到抖音(不打开浏览器)。通过逆向抖音创作者中心的上传与发布接口,
实现 Cookie 认证 → VOD 上传 → CommitUpload → bd-ticket-guard 签名 → create_v2 发布的完整链路。
兼容存客宝/腕推等矩阵工具方案;与 Soul 竖屏成片、视频切片联动。
triggers: 抖音发布、发布到抖音、抖音登录、抖音上传、腕推抖音、纯API发布、命令行发布抖音
owner: 木叶
group: 木
version: "1.0"
updated: "2026-02-28"
version: "2.0"
updated: "2026-03-09"
---
# 抖音发布
# 抖音发布 Skillv2.0
> **登录与发布**:使用**抖音开放平台** OAuth 获取用户授权access_token、open_id再调用「上传视频」+「创建视频」接口发布。
> **存客宝**:当前存客宝 Skill 与文档中无抖音发布 SDK若后续存客宝或腕推等工具提供抖音发布能力可在此 Skill 补充脚本与配置。
> **核心能力**:纯 Python 命令行,无需打开浏览器,通过逆向抖音创作者中心内部 API 实现视频上传与发布。
> **认证方式**Playwright 扫码登录获取 `storage_state.json`Cookie + localStorage 安全密钥),之后全程 API 操作。
> **适用场景**Soul 派对切片批量分发、定时发布、自动化工作流。
---
## 一、流程概览
## 一、发布方式对比
| 方式 | 优点 | 缺点 | 推荐场景 |
|------|------|------|----------|
| **纯 API本 Skill 主方案)** | 无浏览器窗口、速度快、可自动化 | 需逆向维护、Cookie 有效期短 | 批量自动发布 |
| 抖音开放平台 OAuth | 官方接口、稳定 | 需企业资质、审核能力、有发布上限 | 正式产品集成 |
| 推兔/腕推webview 自动化) | 多平台支持 | 需安装桌面端、依赖 NW.js | 多平台矩阵 |
| Playwright 有头浏览器 | 简单直接 | 需显示窗口、速度慢 | 调试/备用 |
---
## 二、纯 API 完整流程6 步)
> 流程图见:`参考资料/抖音纯API发布流程图.png`
```
抖音开放平台应用(申请「代替用户发布内容到抖音」)
→ 用户 OAuth 登录授权 → 获得 access_token、open_id
→ 上传视频upload_video→ 获得 video_id
→ 创建视频create_video→ 发布到抖音
[Step 1] Cookie 认证
Playwright 扫码登录 → douyin_storage_state.json
提取: cookies, ec_privateKey, server_cert, ticket, ts_sign(web_protect), msToken
[Step 2] 获取 VOD 上传凭证
GET /web/api/media/upload/auth/v5/
返回: AccessKeyID, SecretAccessKey, SessionToken
[Step 3] 申请上传地址 (ApplyUploadInner)
GET vod.bytedanceapi.com/?Action=ApplyUploadInner
签名: AWS4-HMAC-SHA256 (GET)
返回: UploadHost, StoreUri, UploadID(预分配), SessionKey, Vid
[Step 4] 上传视频 (/upload/v1/ 协议)
POST https://{host}/upload/v1/{storeUri}?uploadid={UploadID}&part_number=1&phase=transfer
POST https://{host}/upload/v1/{storeUri}?uploadid={UploadID}&phase=finish
body: "1:{server_crc32}"
[Step 5] 提交上传 (CommitUploadInner) ★ 关键步骤
POST vod.bytedanceapi.com/?Action=CommitUploadInner&SpaceName=aweme&...
签名: AWS4-HMAC-SHA256 (POST, body hash)
body: JSON {"SessionKey": "...", "Functions": [{"Name": "GetMeta"}]}
返回: video_id, VideoMeta(Duration, Height, Width, Codec...)
[Step 6] 发布视频 (create_v2)
POST /web/api/media/aweme/create_v2/
签名: bd-ticket-guard (ECDH + HMAC)
body: JSON {item: {common: {text, video_id, ...}, cover: {...}}}
返回: aweme_id (视频ID) 或错误信息
```
---
## 二、前置条件
1. **抖音开放平台** [https://partner.open-douyin.com](https://partner.open-douyin.com) 注册开发者、创建应用。
2. **能力申请**:应用详情 → 能力管理 → 能力实验室 → **代替用户发布内容到抖音**
3. **用户授权**:用户通过 OAuth 授权后,获得 `access_token`(约 15 天)、`open_id`;可存于本地或存客宝等系统供脚本使用。
---
## 三、一键命令(发布单条成片)
## 三、一键命令
```bash
cd /Users/karuo/Documents/个人/卡若AI/03_卡木/木叶_视频内容/抖音发布/脚本
# 使用已保存的 token 发布(需先跑一次登录并保存)
python3 douyin_publish.py --video "/path/to/成片/标题.mp4" --title "视频标题 #话题"
# 1. 首次或 Cookie 过期时:扫码登录
python3 douyin_login.py
# 指定 token 文件(默认读 脚本/.env 或 config.json 中的 access_token、open_id
python3 douyin_publish.py --video "/path/to/xxx.mp4" --title "标题" --token-file ./tokens.json
# 2. 批量发布(成片目录下所有 .mp4
python3 douyin_pure_api.py
# 3. 发布单条
python3 douyin_pure_api.py --video "/path/to/video.mp4" --title "标题 #话题"
```
---
## 四、登录形式(获取 access_token / open_id
## 四、关键技术细节
抖音开放平台采用 **OAuth 2.0**
### 4.1 AWS4-HMAC-SHA256 签名
1. **授权码模式**:引导用户打开授权页 → 用户同意后回调带 `code` → 用 `code``access_token``open_id`
2. **脚本用法**:首次需在浏览器完成授权,或使用开放平台「获取 access_token」接口需 client_key、client_secret、code。将得到的 `access_token``open_id` 写入 `脚本/tokens.json` 或环境变量,供 `douyin_publish.py` 读取。
VOD API`vod.bytedanceapi.com`)使用 AWS4 签名。**GET 和 POST 的签名方式不同**
详见:`参考资料/抖音开放平台_登录与发布流程.md`
| 项目 | GET 请求 | POST 请求 |
|------|----------|-----------|
| Canonical Request 首行 | `GET` | `POST` |
| Signed Headers | `x-amz-date;x-amz-security-token` | `content-type;x-amz-date;x-amz-security-token` |
| Payload Hash | `sha256("")` 空字符串 | `sha256(实际body)` |
```python
# POST 签名的 canonical request 构造
canonical = f"POST\n/\n{qs}\n"
f"content-type:text/plain;charset=UTF-8\n"
f"x-amz-date:{amz_date}\n"
f"x-amz-security-token:{token}\n\n"
f"content-type;x-amz-date;x-amz-security-token\n"
f"{sha256(body)}"
```
### 4.2 bd-ticket-guard 签名create_v2 专用)
`create_v2` 接口使用字节跳动私有安全签名:
1.`localStorage``ec_privateKey`ECDH P-256`server_cert`X.509 证书内的公钥)
2. 生成临时 ECDH 密钥对 → 与服务端公钥做密钥交换 → 得到 `shared_secret`
3.`s_sdk_sign_data_key/web_protect``ticket``ts_sign``ts.2.{hex}` 格式)
4.`shared_secret``ts_sign` 前32字节做 XOR 得到新 `ts_sign`
5. HMAC-SHA256(`shared_secret`, `"{ticket},{path},{timestamp}"`) 得到 `req_sign`
6. 组装 5 个 `bd-ticket-guard-*` 请求头
### 4.3 CommitUploadInner 请求格式(★ 最关键)
```
方法: POST不是 GET
URL: https://vod.bytedanceapi.com/?Action=CommitUploadInner
&SpaceName=aweme&Version=2020-11-19&app_id=2906&user_id={uid}
Headers:
authorization: AWS4-HMAC-SHA256 ...POST 签名)
content-type: text/plain;charset=UTF-8
x-amz-date: {yyyymmddTHHMMSSZ}
x-amz-security-token: {token}
Body (JSON):
{"SessionKey": "...", "Functions": [{"Name": "GetMeta"}]}
```
**注意**
- `SessionKey``Functions`**POST body** 中,不在 URL query string
- `Functions` 必须是 **JSON 数组**,不是 JSON 字符串(`json.dumps`
- URL query string 只放 `Action`, `Version`, `SpaceName`, `app_id`, `user_id`
- `Content-Type``text/plain;charset=UTF-8`(不是 `application/json`
### 4.4 上传协议选择
`ApplyUploadInner` 返回的 `SDKParam` 指示客户端行为:
| 参数 | 值 | 含义 |
|------|-----|------|
| `enable_omit_initupload` | 1 | 跳过 init 阶段,使用预分配 UploadID |
| `enable_post_method` | 0 | 上传使用 POSTv1 协议),不是 PUT |
| `slice_size` | 1024 | 分片大小 1MB单位 KB |
上传协议为 `/upload/v1/` POST 协议:
```
# transfer 阶段
POST /upload/v1/{storeUri}?uploadid={UploadID}&part_number=1&phase=transfer
Content-Type: application/octet-stream
Content-CRC32: {hex_crc32}
Body: 文件二进制
# finish 阶段
POST /upload/v1/{storeUri}?uploadid={UploadID}&phase=finish
Content-Type: text/plain
Body: "1:{server_returned_crc32}"
```
### 4.5 SecurityKeys 加载注意事项
`localStorage``s_sdk_sign_data_key` 有两个变体:
| 键名 | 用途 | ticket 格式 | ts_sign 格式 |
|------|------|------------|-------------|
| `s_sdk_sign_data_key/web_protect` | ✅ bd-ticket-guard 签名 | `hash.{base64}` | `ts.2.{hex}` |
| `s_sdk_sign_data_key/token` | ❌ 不用于此场景 | `{base64}` | `#{base64}` |
**必须读取 `/web_protect` 版本**,否则 `compute_ticket_guard` 会因非 hex 格式崩溃。
---
## 五、与视频切片 / Soul 竖屏的联动
## 五、踩坑经验与解决方案汇总
- **成片目录**Soul 竖屏成片输出在 `xxx_output/成片/`,文件名为标题(如 `没人来就一个人站站到最后钱才来.mp4`)。
- **批量发布**:可对 `成片/` 目录遍历,逐条调用 `douyin_publish.py --video <path> --title <文件名或 highlights 标题>`;标题可来自 `成片/目录索引.md``highlights.json`。示例119 场成片可用 `脚本/batch_publish_119.py`(成片目录需与脚本内一致),发布清单见成片目录下 `119场_抖音发布清单.md`
- **腕推 / 存客宝 / 卡罗维亚**若使用腕推、卡罗维亚或存客宝的抖音发布能力可将对接方式API 文档、SDK 路径)补充到本 Skill 的「参考资料」或脚本说明中,脚本可改为调其接口;**标题与描述**可直接使用每批成片目录下的「发布清单」复制进对应工具
- **小黄车与挂载**:开放平台 create_video 支持挂载小程序;电商小黄车需在抖音端发布后编辑挂载或使用创作者中心。详见 `参考资料/抖音开放平台_登录与发布流程.md` 第四节。
### 5.1 CommitUploadInner 30515 "payload not found"
**现象**上传成功transfer + finish 均返回 2000但 CommitUploadInner 返回 `CodeN=30515, Message="payload not found error"`
**根因**CommitUploadInner 必须用 **POST 方法**`SessionKey``Functions` 放在 JSON body 中。使用 GET + query string 参数虽然签名通过(返回 200但服务端无法解析 SessionKey。
**排查过程**
1. 最初用 GET 方法SessionKey 在 URL query string → 30515
2. 尝试不同的 URL 编码方式 → 仍然 30515
3. 尝试 PUT 直传 vs `/upload/v1/` 协议 → 仍然 30515
4. 用无头浏览器捕获真实请求 → 发现是 **POST + JSON body**
5. 改为 POST 后,`Functions``json.dumps` 字符串 → 30402 "cannot unmarshal string into []ds.Function"
6. `Functions` 改为直接 JSON 数组 → **成功**
**教训**ByteDance VOD API 文档不公开必须通过浏览器抓包验证。GET 和 POST 的行为差异不在错误信息中体现。
### 5.2 finish 阶段 4019 "Mismatch Part List"
**现象**`/upload/v1/` 协议的 finish 阶段返回 `code=4019, message="Mismatch Part List"`
**根因**finish 请求 body 格式为 `{partNumber}:{crc32}`partNumber 必须与 transfer 阶段一致。transfer 用 `part_number=1`,则 finish body 必须是 `1:{crc32}`(不是 `0:{crc32}`)。
**关键**crc32 值使用**服务端返回的** `data.crc32`,不是客户端计算的。
### 5.3 SecurityKeys 读取错误的 sign 数据
**现象**`compute_ticket_guard``bytes.fromhex(ts_hex)` 处崩溃,因为 ts_sign 不是 hex 格式。
**根因**`s_sdk_sign_data_key` 有两个 localStorage 条目(`/web_protect``/token`),循环时后者覆盖前者。`/token` 的 ts_sign 是 base64 格式,不兼容。
**修复**:匹配条件加 `and "web_protect" in name`
### 5.4 Cookie 过期 / "用户未登录"
**现象**`create_v2` 返回 `status_code=8, status_msg="用户未登录"`
**原因**:抖音 Cookie 有效期约 2-4 小时,过期后需要重新扫码登录。
**处理**
- 运行 `python3 douyin_login.py` 重新扫码
- 存储状态文件 `douyin_storage_state.json` 自动更新
- 建议:在批量发布脚本中加入 Cookie 有效性检查
### 5.5 create_v2 返回 403 空响应
**现象**`create_v2` 返回 HTTP 403 且响应体为空。
**原因**:缺少 `bd-ticket-guard-*` 安全头或 `msToken` / `x-secsdk-csrf-token`
**修复**:确保请求包含:
- 5 个 `bd-ticket-guard-*`ECDH + HMAC 计算)
- `msToken` query 参数
- `x-secsdk-csrf-token` 头(格式 `000100000001{passport_csrf_token[:32]}`
### 5.6 账号级限制 "视频投稿功能已封禁"
**现象**`create_v2` 返回 `status_code=-20, status_msg="视频投稿功能已封禁"`
**原因**:抖音账号被平台封禁投稿功能,与 API 无关。
**处理**:检查抖音 APP 的 消息 → 系统通知 查看原因和解封时间;或换号发布。
### 5.7 httpx vs requests 的 URL 编码差异
**现象**:用 `httpx``params=dict` 参数时URL 编码可能与 AWS4 签名不一致。
**解决**:手动构建 query string`"&".join(f"{k}={v}" for k, v in sorted(...))`),直接拼接到 URL 中(`f"{VOD_HOST}/?{qs}"`),不依赖 HTTP 库的 params 编码。
---
## 六、相关文件
## 六、关键数据结构
### 6.1 ApplyUploadInner 返回结构
```json
{
"Result": {
"UploadAddress": null,
"InnerUploadAddress": {
"UploadNodes": [{
"Vid": "v0300fg10000...",
"UploadHost": "tos-nc2-slb1.douyin.com",
"SessionKey": "eyJhY2NvdW50VH...(base64 JSON)",
"StoreInfos": [{
"StoreUri": "tos-cn-v-0015c005/oXXXXXX",
"Auth": "SpaceKey/aweme/0/:version:v2:eyJhb...(JWT)",
"UploadID": "48f691646e17421fba96aaf4cb5d877a"
}]
}]
},
"SDKParam": { "enable_omit_initupload": 1, "enable_post_method": 0, ... }
}
}
```
- `UploadAddress``IsInner=1` 时为 `null`,只有 `InnerUploadAddress`
- `UploadID` 是预分配的transfer 阶段直接使用
- `SessionKey` 是 base64 编码的 JSON包含 `extra`(含上传参数)、`token`(嵌套 JWT`metaConfig`
### 6.2 SessionKey 解码后结构
```json
{
"accountType": "space",
"extra": "edge_node=hl&file_size=3033345.000000&host=tos-d-x-hl.douyin.com&...",
"fileType": "video",
"metaConfig": "{\"accurate\":false,\"need_poster\":true,...}",
"token": "eyJob3N0Ijoi...(嵌套 JWT)"
}
```
### 6.3 create_v2 请求体结构
```json
{
"item": {
"common": {
"text": "标题 #话题",
"caption": "标题 #话题",
"visibility_type": 0,
"creation_id": "{random}{timestamp}",
"media_type": 4,
"video_id": "v0300fg10000...",
"download": 1,
"timing": 0
},
"cover": {
"poster": "",
"poster_delay": 0
}
}
}
```
---
## 七、未来变数与应对
### 7.1 可能的变化
| 变化 | 影响 | 应对 |
|------|------|------|
| bd-ticket-guard 签名算法升级 | create_v2 返回 403/空响应 | 用无头浏览器抓包分析新算法 |
| CommitUploadInner 参数变化 | 30515 或新错误码 | 抓包对比浏览器请求 |
| Cookie 验证加强 | 登录频率增加 | 考虑 refresh token 机制 |
| /upload/v1/ 协议变更 | 上传失败 | 查看 SDKParam 参数适配 |
| VOD API 版本升级(当前 2020-11-19 | API 不兼容 | 抓包获取新版本号 |
| 创作者中心 URL/域名变更 | 请求 404 | 更新 BASE URL |
| msToken 生成方式变化 | 签名失败 | 研究新的 token 生成逻辑 |
### 7.2 万推/推兔的参考价值
通过逆向万推(推兔.app发现
- **B 站 / 视频号**:推兔用 HTTP API 直传preupload 分片、finder-assistant 分片)
- **抖音 / 快手 / 小红书**:推兔用 **webview + 页面内注入自动化**,不是纯 API
- 这意味着抖音纯 API 方案是**更深层的逆向**,需持续维护
### 7.3 降级策略
当纯 API 方案失效时,按以下优先级降级:
1. **无头 Playwright**`headless=True`,命令行操作、无可见窗口
2. **有头 Playwright**:弹出浏览器窗口,人工辅助
3. **抖音开放平台 OAuth**:需企业资质,但最稳定
4. **手动上传**:使用脚本生成的标题/描述,手动在创作者中心发布
---
## 八、调试方法
### 8.1 用无头浏览器捕获真实请求
当 API 行为不确定时,用 headless Playwright 上传一个视频并监听所有网络请求:
```python
async def on_request(req):
if "CommitUploadInner" in req.url or "upload/v1" in req.url:
print(f"[REQ] {req.method} {req.url[:150]}")
print(f" body: {req.post_data[:300] if req.post_data else 'None'}")
print(f" headers: {dict(req.headers)}")
page.on("request", on_request)
```
### 8.2 解码 SessionKey
```python
import base64, json
sk = "eyJhY2NvdW50VHlwZSI6..."
pad = sk + "=" * (4 - len(sk) % 4) if len(sk) % 4 else sk
print(json.dumps(json.loads(base64.b64decode(pad)), indent=2, ensure_ascii=False))
```
### 8.3 验证 Cookie 有效性
```python
resp = requests.get("https://creator.douyin.com/web/api/media/user/info/",
headers={"Cookie": cookie_str, "User-Agent": UA})
data = resp.json()
print(f"有效: {data.get('status_code') == 0}, 用户: {data.get('user_info',{}).get('nickname')}")
```
---
## 九、相关文件
| 文件 | 说明 |
|------|------|
| `脚本/douyin_publish.py` | 发布脚本:读 token → 上传视频 → 创建视频 |
| `参考资料/抖音开放平台_登录与发布流程.md` | 开放平台 OAuth、上传、创建视频接口说明与链接 |
| `脚本/douyin_pure_api.py` | **主脚本**:纯 API 视频上传+发布v2.0 |
| `脚本/douyin_login.py` | Playwright 扫码登录,生成 storage_state.json |
| `脚本/douyin_storage_state.json` | Cookie + localStorage 安全密钥存储 |
| `脚本/douyin_batch_publish.py` | 旧版批量发布脚本OAuth 方式) |
| `参考资料/抖音开放平台_登录与发布流程.md` | 开放平台 OAuth 方式文档 |
| `参考资料/抖音纯API发布流程图.png` | 完整 6 步流程图 |
---
## 七、API 摘要(抖音开放平台)
## 十、与其他平台的通用模式
| 步骤 | 接口 | 说明 |
|------|------|------|
| 登录 | OAuth 授权 → access_token、open_id | 用户授权后获得 |
| 上传 | POST `/api/douyin/v1/video/upload_video/` | form: video=@文件;返回加密 video_id |
| 发布 | POST `/api/douyin/v1/video/create_video/` | body: video_id、text标题可带话题 |
本方案揭示的 ByteDance 平台上传模式可推广:
视频时长不超过 15 分钟;标题不超过 1000 字;每日发布上限 75 条(同一应用下)。
| 步骤 | 抖音 | 西瓜视频 | 头条号 | 通用模式 |
|------|------|----------|--------|----------|
| 认证 | Cookie + bd-ticket-guard | Cookie + bd-ticket-guard | Cookie + bd-ticket-guard | Playwright 登录获取 |
| 上传申请 | ApplyUploadInner | ApplyUploadInner | ApplyUploadInner | VOD API + AWS4 签名 |
| 文件上传 | /upload/v1/ POST | /upload/v1/ POST | /upload/v1/ POST | TOS 分片上传 |
| 提交上传 | CommitUploadInner POST | CommitUploadInner POST | CommitUploadInner POST | VOD API + POST body |
| 发布 | create_v2 | 各自创建接口 | 各自创建接口 | bd-ticket-guard 签名 |
所有字节系平台(抖音、西瓜、头条)共用同一套 VOD 上传基础设施区别主要在最终的发布接口create_v2 等)和 `SpaceName`

Binary file not shown.

After

Width:  |  Height:  |  Size: 1011 KiB

View File

@@ -255,3 +255,4 @@
| 2026-03-08 09:14:27 | 🔄 卡若AI 同步 2026-03-08 09:14 | 更新:运营中枢工作台 | 排除 >20MB: 11 个 |
| 2026-03-08 10:53:09 | 🔄 卡若AI 同步 2026-03-08 10:53 | 更新:卡土、总索引与入口、运营中枢工作台 | 排除 >20MB: 11 个 |
| 2026-03-09 05:51:31 | 🔄 卡若AI 同步 2026-03-09 05:51 | 更新:金仓、水桥平台对接、卡木、运营中枢工作台 | 排除 >20MB: 11 个 |
| 2026-03-09 22:16:33 | 🔄 卡若AI 同步 2026-03-09 22:16 | 更新:水桥平台对接、水溪整理归档、卡木、运营中枢工作台 | 排除 >20MB: 11 个 |

View File

@@ -258,3 +258,4 @@
| 2026-03-08 09:14:27 | 成功 | 成功 | 🔄 卡若AI 同步 2026-03-08 09:14 | 更新:运营中枢工作台 | 排除 >20MB: 11 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |
| 2026-03-08 10:53:09 | 成功 | 成功 | 🔄 卡若AI 同步 2026-03-08 10:53 | 更新:卡土、总索引与入口、运营中枢工作台 | 排除 >20MB: 11 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |
| 2026-03-09 05:51:31 | 成功 | 成功 | 🔄 卡若AI 同步 2026-03-09 05:51 | 更新:金仓、水桥平台对接、卡木、运营中枢工作台 | 排除 >20MB: 11 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |
| 2026-03-09 22:16:33 | 成功 | 成功 | 🔄 卡若AI 同步 2026-03-09 22:16 | 更新:水桥平台对接、水溪整理归档、卡木、运营中枢工作台 | 排除 >20MB: 11 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |