# 文案提取服务接口文档

## 服务说明

该服务用于提交视频/图文链接并异步提取文案。

服务启动后默认监听：

```text
http://172.16.18.10:10443
```

启动命令：

```bash
python3 text_extract_service.py
```

任务数据会写入 Redis：

```text
text_extract:task:{task_id}
```

因此服务重启后，只要 Redis 中仍有任务数据，就可以继续通过 `task_id` 查询结果。

## 接口列表

| 方法 | 路径 | 说明 |
| --- | --- | --- |
| POST | `/api/text-extract/tasks` | 提交一个或多个 URL，返回每个 URL 对应的任务 ID |
| GET | `/api/text-extract/tasks/{task_id}` | 根据任务 ID 查询文案提取结果 |

另提供一个等价查询接口：

```text
GET /api/text-extract/result?task_id={task_id}
```

## 1. 提交文案提取任务

### 请求

```http
POST /api/text-extract/tasks
Content-Type: application/json
```

### 请求参数

支持提交单个 URL：

```json
{
  "url": "https://www.douyin.com/jingxuan?modal_id=7654800977366715698"
}
```

也支持一次提交多个 URL：

```json
{
  "urls": [
    "https://www.douyin.com/jingxuan?modal_id=7654800977366715698",
    "https://www.xiaohongshu.com/discovery/item/xxxx?xsec_token=xxxx"
  ]
}
```

### 参数说明

| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| url | string | 否 | 单个待提取链接 |
| urls | array[string] | 否 | 多个待提取链接 |

说明：

- `url` 和 `urls` 二选一。
- 如果同时传入 `url` 和 `urls`，服务优先使用 `urls`。
- 当前支持的平台取决于原文案提取逻辑，主要包括抖音、小红书、快手、B站。

### curl 示例

提交单个 URL：

```bash
curl -X POST "http://172.16.18.10:10443/api/text-extract/tasks" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://www.douyin.com/jingxuan?modal_id=7654800977366715698"
  }'
```

提交多个 URL：

```bash
curl -X POST "http://172.16.18.10:10443/api/text-extract/tasks" \
  -H "Content-Type: application/json" \
  -d '{
    "urls": [
      "https://www.douyin.com/jingxuan?modal_id=7654800977366715698",
      "https://www.xiaohongshu.com/discovery/item/xxxx?xsec_token=xxxx"
    ]
  }'
```

### 成功响应

HTTP 状态码：

```text
202 Accepted
```

响应示例：

```json
{
  "code": 200,
  "msg": "success",
  "data": [
    {
      "url": "https://www.douyin.com/jingxuan?modal_id=7654800977366715698",
      "task_id": "0cb446fb-4938-4d52-a500-9d0e2fab109e",
      "status": "queued"
    }
  ]
}
```

### 响应字段说明

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| code | number | 业务状态码，成功为 `200` |
| msg | string | 响应信息 |
| data | array | 任务列表 |
| data[].url | string | 提交的原始 URL |
| data[].task_id | string | 任务 ID，后续查询结果使用 |
| data[].status | string | 任务初始状态，通常为 `queued` |

### 失败响应

请求参数错误：

```json
{
  "code": 400,
  "msg": "请提交 url 或 urls",
  "data": null
}
```

## 2. 查询文案提取结果

### 请求

```http
GET /api/text-extract/tasks/{task_id}
```

### 路径参数

| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| task_id | string | 是 | 提交任务时返回的任务 ID |

### curl 示例

```bash
curl -X GET "http://172.16.18.10:10443/api/text-extract/tasks/0cb446fb-4938-4d52-a500-9d0e2fab109e"
```

也可以使用 query 参数查询：

```bash
curl -X GET "http://172.16.18.10:10443/api/text-extract/result?task_id=0cb446fb-4938-4d52-a500-9d0e2fab109e"
```

### 成功响应

任务处理中：

```json
{
  "code": 200,
  "msg": "success",
  "data": {
    "task_id": "0cb446fb-4938-4d52-a500-9d0e2fab109e",
    "url": "https://www.douyin.com/jingxuan?modal_id=7654800977366715698",
    "status": "running",
    "status_message": "视频文案提取中",
    "video_info": {
      "aweme_type": "SHIPIN",
      "title": "视频标题",
      "item_title": "视频标题",
      "cover": "https://static2.douchacha.com/assets/xxx/cover.jpg",
      "duration": "268284",
      "comment_count": "386",
      "digg_count": "6123",
      "share_count": "870",
      "video_id": "7654800977366715698",
      "platform": "DY"
    },
    "text": "",
    "error": null,
    "created_at": "2026-07-07 20:02:12",
    "updated_at": "2026-07-07 20:02:30",
    "finished_at": null
  }
}
```

任务成功：

```json
{
  "code": 200,
  "msg": "success",
  "data": {
    "task_id": "0cb446fb-4938-4d52-a500-9d0e2fab109e",
    "url": "https://www.douyin.com/jingxuan?modal_id=7654800977366715698",
    "status": "success",
    "status_message": "文案提取完成",
    "video_info": {
      "aweme_type": "SHIPIN",
      "title": "视频标题",
      "item_title": "视频标题",
      "cover": "https://static2.douchacha.com/assets/xxx/cover.jpg",
      "duration": "268284",
      "comment_count": "386",
      "digg_count": "6123",
      "share_count": "870",
      "video_id": "7654800977366715698",
      "platform": "DY"
    },
    "text": "这里是最终提取出来的视频文案",
    "error": null,
    "created_at": "2026-07-07 20:02:12",
    "updated_at": "2026-07-07 20:02:59",
    "finished_at": "2026-07-07 20:02:59"
  }
}
```

任务失败：

```json
{
  "code": 200,
  "msg": "success",
  "data": {
    "task_id": "0cb446fb-4938-4d52-a500-9d0e2fab109e",
    "url": "https://example.com/wrong-url",
    "status": "failed",
    "status_message": "文案提取失败",
    "video_info": null,
    "text": "",
    "error": "未提取到文案",
    "created_at": "2026-07-07 20:02:12",
    "updated_at": "2026-07-07 20:02:59",
    "finished_at": "2026-07-07 20:02:59"
  }
}
```

### 响应字段说明

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| code | number | 业务状态码，成功为 `200` |
| msg | string | 响应信息 |
| data.task_id | string | 任务 ID |
| data.url | string | 提交的原始 URL |
| data.status | string | 任务状态 |
| data.status_message | string | 当前任务阶段说明 |
| data.video_info | object/null | 视频基础信息 |
| data.text | string | 提取出的文案结果 |
| data.error | string/null | 失败或异常信息 |
| data.created_at | string | 任务创建时间 |
| data.updated_at | string | 最近更新时间 |
| data.finished_at | string/null | 任务完成时间 |

## 任务状态说明

| 状态 | 说明 |
| --- | --- |
| queued | 任务已提交，等待后台线程处理 |
| running | 任务处理中 |
| success | 文案提取成功 |
| failed | 文案提取失败 |

## status_message 常见值

| status_message | 说明 |
| --- | --- |
| 任务已提交 | 已创建任务 |
| 任务处理中 | 后台线程已开始处理 |
| 已获取视频基础信息 | 已解析到视频基础信息 |
| 视频文案提取中 | 正在提取视频文案 |
| 识别完成 | ASR 识别完成 |
| 文案提取完成 | 已得到最终文案 |
| 文案提取失败 | 任务执行完成，但未提取到文案 |
| 文案提取异常 | 任务执行过程中出现异常 |

## 查询建议

提交任务后可以每 2-3 秒查询一次结果。

示例：

```bash
curl -X GET "http://172.16.18.10:10443/api/text-extract/tasks/你的task_id"
```

当返回：

```json
{
  "status": "success"
}
```

即可读取 `data.text` 作为最终文案结果。

## 注意事项

- `POST` 接口只负责提交任务，不会等待文案提取完成。
- 文案提取是后台异步执行的，耗时取决于爬虫解析、TOS 文件生成、ASR 识别等外部服务。
- 查询接口不会返回内部 `events`，只返回视频基础信息 `video_info` 和文案结果 `text`。
- Redis 不可用时，当前进程内仍可查询内存中的任务；但服务重启后无法恢复未写入 Redis 的任务。
