> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gravitex.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Wan 2.7 비디오 편집

> Alibaba Wan wan2.7-videoedit 지시형 비디오 편집

## 소개

Gravitex 게이트웨이를 통해 Alibaba Cloud Bailian `wan2.7-videoedit` 모델을 호출하여 기존 비디오에 지시형 편집(인물 교체, 의상 변경, 장면 스타일 조정 등)을 수행합니다. 인터페이스는 비동기 방식입니다: 먼저 작업을 제출한 후 결과를 폴링합니다.

| 인터페이스        | 메서드    | 경로                                |
| ------------ | ------ | --------------------------------- |
| 비디오 편집 작업 생성 | `POST` | `/v1/video/generations`           |
| 작업 상태 조회     | `GET`  | `/v1/video/generations/{task_id}` |

`{task_id}`는 작업 생성 시 반환된 `id`입니다.

<Note>
  [Wan 2.7 비디오 생성](/ko/api-reference/endpoint/wan2.7)(T2V / I2V / R2V)과 통합 비디오 진입점을 공유하지만, 모델과 `media` 매개변수 의미가 다르므로 혼용하지 마세요.
</Note>

## 인증

<ParamField header="Authorization" type="string" required>
  Bearer Token, 예: `Bearer sk-xxxxxxxx`
</ParamField>

<ParamField header="Content-Type" type="string" required>
  `application/json`으로 고정
</ParamField>

<ParamField header="X-Trace-ID" type="string">
  요청 추적 ID, 매 요청마다 고유 값 생성 권장
</ParamField>

## 요청 매개변수

<ParamField body="model" type="string" required>
  `wan2.7-videoedit`로 고정
</ParamField>

<ParamField body="prompt" type="string" required>
  비디오 편집 지시문
</ParamField>

<ParamField body="duration" type="integer">
  출력 비디오 길이(초), 예시는 `4`
</ParamField>

<ParamField body="metadata.input.prompt" type="string" required>
  Alibaba Cloud에 전달되는 원본 프롬프트, 최상위 `prompt`와 동일하게 유지 권장
</ParamField>

<ParamField body="metadata.input.media" type="array" required>
  입력 미디어 배열, 최소 하나의 비디오 포함
</ParamField>

<ParamField body="metadata.input.media[].type" type="string" required>
  원본 비디오는 `video`; 참조 이미지는 `reference_image`(최대 4장)
</ParamField>

<ParamField body="metadata.input.media[].url" type="string" required>
  공개 접근 가능한 HTTP/HTTPS URL 또는 업스트림 요구사항에 맞는 임시 URL
</ParamField>

<ParamField body="metadata.parameters.resolution" type="string">
  `720P` 또는 `1080P`
</ParamField>

<ParamField body="metadata.parameters.prompt_extend" type="boolean">
  프롬프트 지능형 재작성 활성화 여부
</ParamField>

<ParamField body="metadata.parameters.watermark" type="boolean">
  워터마크 추가 여부
</ParamField>

## 요청 예제

**최소 요청(입력 비디오만):**

```bash theme={null}
curl --location 'https://api.gravitex.ai/v1/video/generations' \
  --header 'Authorization: Bearer sk-xxxxxxxx' \
  --header 'Content-Type: application/json' \
  --header 'X-Trace-ID: wan27-videoedit-test-001' \
  --data '{
    "model": "wan2.7-videoedit",
    "prompt": "背景不变，把视频中的小羊换成黑色的",
    "duration": 4,
    "metadata": {
      "input": {
        "prompt": "背景不变，把视频中的小羊换成黑色的",
        "media": [
          {
            "type": "video",
            "url": "https://your-public-oss.example.com/input.mp4"
          }
        ]
      },
      "parameters": {
        "resolution": "720P",
        "prompt_extend": true,
        "watermark": false
      }
    }
  }'
```

**참조 이미지 추가:**

동일한 `media` 배열에 참조 이미지를 추가할 수 있습니다. 프롬프트에서 「图 1」로 지칭할 수 있습니다. 최대 **4**장의 참조 이미지를 지원합니다.

```json theme={null}
{
  "model": "wan2.7-videoedit",
  "prompt": "保持视频中的人物动作不变，把人物衣服替换成参考图中的黑色西装",
  "duration": 4,
  "metadata": {
    "input": {
      "prompt": "保持视频中的人物动作不变，把人物衣服替换成参考图中的黑色西装",
      "media": [
        {
          "type": "video",
          "url": "https://your-public-oss.example.com/input.mp4"
        },
        {
          "type": "reference_image",
          "url": "https://your-public-oss.example.com/reference.png"
        }
      ]
    },
    "parameters": {
      "resolution": "720P",
      "prompt_extend": true,
      "watermark": false
    }
  }
}
```

## 작업 생성 응답

생성 성공 시 표준화된 비디오 작업 객체를 반환합니다(`code/message/data` 외부 래퍼 없음):

```json theme={null}
{
  "id": "76dc2556-f4****************29247",
  "object": "video",
  "model": "wan2.7-videoedit",
  "status": "queued",
  "progress": 0,
  "created_at": 1784714517,
  "metadata": {
    "output": {
      "task_id": "76dc2556-f4****************29247",
      "task_status": "PENDING"
    },
    "request_id": "86c168af-****************bf96d"
  }
}
```

반환된 `id`를 저장하여 후속 조회에 사용하세요.

## 작업 조회

```bash theme={null}
curl --location \
  'https://api.gravitex.ai/v1/video/generations/76dc2556-f4****************29247' \
  --header 'Authorization: Bearer sk-xxxxxxxx' \
  --header 'X-Trace-ID: wan27-videoedit-query-001'
```

조회 응답에는 `code/message/data` 외부 래퍼가 있습니다:

```json theme={null}
{
  "code": "success",
  "message": "",
  "data": {
    "id": "76dc2556-f4****************29247",
    "object": "video",
    "model": "wan2.7-videoedit",
    "status": "completed",
    "progress": 100,
    "created_at": 1784714517,
    "completed_at": 1784714687,
    "seconds": "8",
    "url": "https://signed-result-url.example.com/result.mp4",
    "video_url": "https://signed-result-url.example.com/result.mp4",
    "metadata": {
      "output": {
        "task_status": "SUCCEEDED",
        "input_video_duration": 4,
        "output_video_duration": 4,
        "video_url": "https://signed-result-url.example.com/result.mp4"
      }
    }
  }
}
```

## 상태 처리

클라이언트는 `data.status`를 플랫폼 표준 상태로 사용해야 합니다:

| `data.status` | 설명    | 클라이언트 처리                          |
| ------------- | ----- | --------------------------------- |
| `queued`      | 대기 중  | 계속 폴링                             |
| `in_progress` | 생성 중  | 계속 폴링                             |
| `completed`   | 생성 성공 | `data.video_url` 또는 `data.url` 읽기 |
| `failed`      | 생성 실패 | `data.error.message` 읽기           |

업스트림 상태는 `data.metadata.output.task_status`(예: `PENDING`, `SUCCEEDED`)에 있으며, 디버깅용으로만 사용하고 주 상태 판단 기준으로 사용하지 마세요.

폴링 간격 **5\~15초**를 권장하며, 고빈도 폴링은 피하세요.

## 출력 비디오 URL

성공 시 `data.video_url`을 우선 읽고, `data.url`도 읽을 수 있습니다(현재 어댑터에서는 보통 동일).

출력 URL은 서명된 임시 주소이므로 영구 비즈니스 리소스 주소로 저장해서는 안 됩니다. 장기 보관이 필요하면 유효 기간 내에 다운로드하거나 자체 OSS로 전송하세요.

## 길이 및 과금

실측에서 `duration: 4` 요청 시 업스트림 `usage`는 다음과 같을 수 있습니다:

| 필드                      | 의미                                |
| ----------------------- | --------------------------------- |
| `input_video_duration`  | 입력 비디오 길이                         |
| `output_video_duration` | 출력 비디오 길이                         |
| `usage.duration`        | 입력 + 출력 총 과금 길이                   |
| `data.seconds`          | 게이트웨이 응답에 대응하는 업스트림 총 길이(예시는 `8`) |

따라서 `data.seconds = 8`은 **8초 비디오가 생성되었다는 의미가 아닙니다**. 입력과 출력의 합산 과금 길이입니다.

Alibaba Cloud 공식 과금: 「입력 비디오 길이 + 출력 비디오 길이」로 과금; 입력 이미지는 과금되지 않습니다. 자세한 내용은 [공식 과금 안내](https://www.alibabacloud.com/help/en/model-studio/wan-video-editing-guide)를 참조하세요.

## 일반적인 오류 해결

| 문제              | 설명                                                                                                                              |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `media`에 비디오 누락 | 최소 `{ "type": "video", "url": "..." }` 포함                                                                                       |
| 비디오 URL 접근 불가   | 로그인 필요 페이지, 권한 부족, 만료된 OSS URL 사용 금지; 공개 접근 가능해야 함                                                                              |
| JSON 형식 오류      | 불리언은 `true`/`false`로 작성, `**true**` 등으로 작성하지 마세요                                                                                |
| `video_url`만 전달 | 신규 연동은 `input.media` 사용; 게이트웨이는 구 `video_url`과 호환되지만 권장하지 않음                                                                    |
| Wan 2.1 매개변수 혼용 | `wan2.7-videoedit`는 `input.media` 사용; 구버전 `wan2.1-vace-plus`는 `input.function = video_repainting` + `input.video_url` 사용, 혼용 불가 |

## Python 최소 예제

```python theme={null}
import time
import uuid
import requests

BASE_URL = "https://api.gravitex.ai"
API_KEY = "sk-xxxxxxxx"

headers = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json",
    "X-Trace-ID": uuid.uuid4().hex,
}

payload = {
    "model": "wan2.7-videoedit",
    "prompt": "背景不变，把视频中的小羊换成黑色的",
    "duration": 4,
    "metadata": {
        "input": {
            "prompt": "背景不变，把视频中的小羊换成黑色的",
            "media": [
                {
                    "type": "video",
                    "url": "https://your-public-oss.example.com/input.mp4",
                }
            ],
        },
        "parameters": {
            "resolution": "720P",
            "prompt_extend": True,
            "watermark": False,
        },
    },
}

response = requests.post(
    f"{BASE_URL}/v1/video/generations",
    headers=headers,
    json=payload,
    timeout=30,
)
response.raise_for_status()
task = response.json()
task_id = task["id"]

while True:
    result = requests.get(
        f"{BASE_URL}/v1/video/generations/{task_id}",
        headers={
            "Authorization": f"Bearer {API_KEY}",
            "X-Trace-ID": uuid.uuid4().hex,
        },
        timeout=30,
    )
    result.raise_for_status()
    data = result.json()["data"]
    status = data["status"]
    print(status, data.get("progress", 0))

    if status == "completed":
        print("video_url:", data.get("video_url") or data.get("url"))
        break
    if status == "failed":
        raise RuntimeError(data.get("error", {}).get("message", "video generation failed"))

    time.sleep(10)
```
