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

# Gemini Omni 1.2 Flash 동영상 생성

> 텍스트·이미지 기반 생성, 여러 피사체 참조, 첫·마지막 프레임 보간, 동영상 편집·연장. 최대 4K, 24fps, 오디오 포함.

> [!NOTE]
>
> 텍스트·이미지 기반 동영상 생성은 3–15초의 정수를 지원하며 기본값은 10초입니다. 첫·마지막 프레임 보간과 연장 시 추가 구간은 최대 10초입니다. 편집에서는 `duration`을 무시하고 원본 영상 길이를 유지합니다. 동영상 입력의 기본 동작은 편집이며, 연장하려면 `"omni_reference_task_type": "extend"`를 명시해야 합니다.

```bash cURL theme={null}
curl --request POST \
  --url https://api.apimart.ai/v1/videos/generations \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '{
    "model": "gemini-omni-1.2-flash",
    "prompt": "A marble rolling fast on a chain reaction style track, continuous smooth shot.",
    "aspect_ratio": "16:9",
    "resolution": "720p",
    "duration": 15
  }'
```

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

base_url = "https://api.apimart.ai"
headers = {"Authorization": "Bearer <token>"}
payload = {
    "model": "gemini-omni-1.2-flash",
    "prompt": "A marble rolling fast on a chain reaction style track, continuous smooth shot.",
    "aspect_ratio": "16:9",
    "resolution": "720p",
    "duration": 15,
}
response = requests.post(
    f"{base_url}/v1/videos/generations",
    headers=headers, json=payload, timeout=30,
)
response.raise_for_status()
task_id = response.json()["data"][0]["task_id"]
print(task_id)

deadline = time.monotonic() + 600
while time.monotonic() < deadline:
    response = requests.get(
        f"{base_url}/v1/tasks/{task_id}", headers=headers, timeout=30,
    )
    response.raise_for_status()
    task = response.json()["data"]
    if task["status"] == "completed":
        print(task["result"]["videos"][0]["url"][0])
        break
    if task["status"] == "failed":
        raise RuntimeError(task["error"]["message"])
    time.sleep(5)
else:
    raise TimeoutError(f"Continue polling task {task_id}")
```

```javascript JavaScript theme={null}
const baseUrl = "https://api.apimart.ai";
const headers = {
  Authorization: "Bearer <token>",
  "Content-Type": "application/json",
};
const response = await fetch(`${baseUrl}/v1/videos/generations`, {
  method: "POST",
  headers,
  signal: AbortSignal.timeout(30_000),
  body: JSON.stringify({
    model: "gemini-omni-1.2-flash",
    prompt: "A marble rolling fast on a chain reaction style track, continuous smooth shot.",
    aspect_ratio: "16:9",
    resolution: "720p",
    duration: 15,
  }),
});
if (!response.ok) throw new Error(await response.text());
const taskId = (await response.json()).data[0].task_id;
console.log(taskId);

async function waitForTask(taskId) {
  const deadline = Date.now() + 600_000;
  while (Date.now() < deadline) {
    const response = await fetch(`${baseUrl}/v1/tasks/${taskId}`, {
      headers,
      signal: AbortSignal.timeout(30_000),
    });
    if (!response.ok) throw new Error(await response.text());
    const task = (await response.json()).data;
    if (task.status === "completed") return task.result.videos[0].url[0];
    if (task.status === "failed") throw new Error(task.error.message);
    await new Promise(resolve => setTimeout(resolve, 5000));
  }
  throw new Error(`Continue polling task ${taskId}`);
}
console.log(await waitForTask(taskId));
```

```json 200 theme={null}
{
  "code": 200,
  "data": [
    {
      "status": "submitted",
      "task_id": "task_01EXAMPLE"
    }
  ]
}
```

## 인증

**Authorization** `string` *required*

Bearer Token 인증을 사용합니다. [API Key 관리 페이지](https://apimart.ai/keys)에서 키를 받고 `Content-Type: application/json`으로 요청을 전송하세요.

## 요청 매개변수

**model** `string` *required*

`gemini-omni-1.2-flash`로 지정합니다.

**prompt** `string` *required*

필수 텍스트 지시문입니다. 텍스트 기반 동영상 생성에서는 장면을, 이미지 기반 생성·편집·연장에서는 동작, 스타일 또는 변경 사항을 설명합니다. 참조 이미지, 첫·마지막 프레임, 동영상 또는 `extend_from_task_id`를 제공해도 `prompt`는 필수입니다. 생략하면 HTTP 400을 반환합니다.

**duration** `integer` (default: 10)

텍스트·이미지 기반 동영상의 출력 길이로, `3`–`15`의 정수이며 기본값은 `10`입니다. 첫·마지막 프레임 보간과 연장은 `3`–`10`초만 지원합니다. 연장에서는 추가 구간의 길이를 지정하며, 반환되는 영상에는 원본과 추가 구간이 모두 포함됩니다. 편집에서는 `duration`을 무시하고 원본 영상 길이를 유지합니다. 허용 범위를 벗어난 매개변수는 작업을 `invalid_duration`으로 실패하게 합니다.

**resolution** `string` (default: 720p)

`360p` / `720p` / `1080p` / `4k`. 대소문자를 구분하지 않으며 `2160p`는 `4k`로 처리합니다. `1080p`와 `4k`는 업샘플링 출력입니다. 해상도는 출력 토큰 사용량과 선차감액에 영향을 줍니다. 다른 값은 `invalid_resolution`으로 작업이 실패합니다.

**aspect\_ratio** `string` (default: 16:9)

`16:9`(가로, 기본값)와 `9:16`(세로)만 지원합니다. 다른 값은 `16:9`로 처리합니다.

**image\_urls** `string[]`

참조 이미지 배열. 공개적으로 접근 가능한 HTTP(S) 이미지 직접 링크만 지원하며 Data URL과 Base64는 지원하지 않습니다. 한 장은 시작 화면, 여러 장은 피사체 참조로 사용합니다. 첫·마지막 프레임을 포함해 총 10장까지입니다. 캐릭터 참조는 최대 2명, 캐릭터별 최대 3장으로 총 6장 이하를 권장합니다.

**first\_frame\_image** `string`

첫 프레임 이미지. 단독으로 전달하면 이 이미지에서 시작하며, `last_frame_image`와 함께 전달하면 첫·마지막 프레임 보간을 수행합니다. 공개적으로 접근 가능한 HTTP(S) 이미지 직접 링크만 지원합니다.

**last\_frame\_image** `string`

마지막 프레임 이미지. `first_frame_image`가 없으면 `invalid_frame_images`로 실패합니다. 두 이미지의 비율을 같게 하고 `aspect_ratio`와 맞추세요. 공개적으로 접근 가능한 HTTP(S) 이미지 직접 링크만 지원합니다.

**image\_with\_roles** `object[]`

역할이 있는 이미지 배열로, 첫·마지막 프레임 필드를 직접 지정하는 방식과 같습니다. 둘 중 한 방식을 사용하세요. 실제 사용되는 모든 이미지는 총 10장 제한에 포함됩니다.

**배열 항목**

**url** `string` *required*

공개적으로 접근 가능한 HTTP(S) 이미지 직접 링크만 지원합니다.

**role** `string` *required*

`first_frame`은 첫 프레임, `last_frame`은 마지막 프레임입니다. 다른 역할은 참조 이미지로 처리합니다. 마지막 프레임에는 첫 프레임이 필요합니다.

**video\_urls** `string[]`

편집하거나 연장할 동영상 배열. 최대 1개, 길이는 15초 이하입니다. 공개적으로 접근 가능한 HTTP(S) 동영상 직접 링크만 지원하며 Data URL과 Base64는 지원하지 않습니다. 동영상 입력 시 기본 동작은 편집입니다.

**omni\_reference\_task\_type** `string` (default: auto)

작업 유형: `auto`(기본값, 입력에 따라 자동 판단) / `edit`(편집) / `extend`(연장) / `reference`(여러 이미지 참조). `text_to_video` / `image_to_video` / `reference_to_video`도 허용합니다. 생략하거나 `auto`로 설정하면 `video_urls`와 `extend_from_task_id`는 기본적으로 편집합니다. 연장하려면 `extend`를 명시해야 합니다.

**extend\_from\_task\_id** `string`

자신의 이전 생성 작업 ID를 참조해 다시 업로드하지 않고 영상을 재사용합니다. 기본은 편집입니다. `"omni_reference_task_type": "extend"`를 사용하면 끝에 최대 10초를 추가합니다.

## 기능과 제한

* 출력은 24fps이며 대화, 음악 또는 효과음을 포함합니다. 원하는 소리를 `prompt`에 설명할 수 있습니다.
* 오디오 입력, system prompt, `temperature`, 부정 프롬프트 매개변수는 지원하지 않습니다. 제외할 내용은 `prompt`에 직접 작성하세요.
* 상위 서비스의 지역 제한: EEA, 스위스, 영국에서는 업로드한 동영상의 편집·연장 및 미성년자가 포함된 이미지 편집을 지원하지 않습니다.
* 모든 출력에는 보이지 않는 SynthID 워터마크가 포함됩니다.

## 사용 예시

각 JSON을 `POST /v1/videos/generations`로 전송합니다. 예시 자료 URL과 작업 ID를 자신의 사용 가능한 값으로 바꾸세요.

### 15초 4K 세로 동영상

```json theme={null}
{
  "model": "gemini-omni-1.2-flash",
  "prompt": "Aerial shot over a misty mountain lake at sunrise, birds flying, slow forward camera move.",
  "aspect_ratio": "9:16",
  "resolution": "4k",
  "duration": 15
}
```

### 이미지 기반 생성과 여러 피사체 참조

```json theme={null}
{
  "model": "gemini-omni-1.2-flash",
  "prompt": "The cat playfully bats at the ball of yarn.",
  "image_urls": [
    "https://example.com/cat.png",
    "https://example.com/yarn.png"
  ],
  "duration": 12
}
```

### 첫·마지막 프레임 보간

```json theme={null}
{
  "model": "gemini-omni-1.2-flash",
  "prompt": "Smooth transition, camera slowly pushes in.",
  "first_frame_image": "https://example.com/start.jpg",
  "last_frame_image": "https://example.com/end.jpg",
  "aspect_ratio": "16:9",
  "duration": 8
}
```

### 이미지 역할로 프레임 지정

```json theme={null}
{
  "model": "gemini-omni-1.2-flash",
  "prompt": "A smooth cinematic transition from sunrise to a starry night.",
  "image_with_roles": [
    {
      "url": "https://example.com/sunrise.jpg",
      "role": "first_frame"
    },
    {
      "url": "https://example.com/night.jpg",
      "role": "last_frame"
    }
  ],
  "duration": 8
}
```

### 동영상 편집

```json theme={null}
{
  "model": "gemini-omni-1.2-flash",
  "prompt": "Make the violin invisible. Keep everything else the same.",
  "video_urls": [
    "https://example.com/clip.mp4"
  ]
}
```

편집 결과의 길이는 원본 영상을 따르며 `duration`은 적용되지 않습니다.

편집 지시는 짧고 명확하게 작성하세요. 일부만 변경할 때는 `Keep everything else the same`을 추가할 수 있습니다.

### 기존 작업 연장

```json theme={null}
{
  "model": "gemini-omni-1.2-flash",
  "prompt": "The camera continues panning across the mountains.",
  "extend_from_task_id": "task_01PREVIOUS",
  "omni_reference_task_type": "extend",
  "duration": 8
}
```

업로드한 영상을 연장하려면 `extend_from_task_id`를 `video_urls`로 바꾸고 `"omni_reference_task_type": "extend"`를 유지하세요. 반환되는 영상은 원본 뒤에 추가 구간을 붙인 전체 영상입니다. `duration`은 최대 10초의 추가 길이만 지정하며, 추가된 초에 대해서만 과금합니다. 예를 들어 5초 원본에 `duration: 4`를 지정하면 약 9초 영상을 반환합니다.

## 제출 응답과 작업 조회

제출 성공 시 HTTP 200을 반환하며 `data[0].task_id`에서 작업 ID를 읽습니다. [작업 조회 API](https://docs.apimart.ai/ko/api-reference/tasks/status.md)를 5–10초 간격으로 호출해 `completed` 또는 `failed`까지 확인하세요. 전체 대기 시간은 10분을 권장합니다. 클라이언트 시간이 초과되면 다시 제출하지 말고 기존 작업을 계속 조회하세요.

```bash theme={null}
curl --request GET \
  --url https://api.apimart.ai/v1/tasks/task_01EXAMPLE \
  --header 'Authorization: Bearer <token>'
```

예상 소요 시간: 360p 15초 영상은 약 30초, 4K 15초 영상은 약 5분입니다. 실제 완료 여부는 작업 상태로 확인하세요.

```json theme={null}
{
  "code": 200,
  "data": {
    "id": "task_01EXAMPLE",
    "status": "completed",
    "progress": 100,
    "result": {
      "videos": [
        {
          "url": [
            "https://cdn.example.com/gemini_omni_video.mp4"
          ]
        }
      ]
    }
  }
}
```

조회 응답의 `data`가 작업 객체입니다. `data.result.videos[0].url`은 배열이며 첫 링크는 `data.result.videos[0].url[0]`입니다. 바로 다운로드하거나 재생할 수 있고, 장기 보관은 별도 저장소를 사용하세요. `data.cost`는 최종 결제 금액(USD)입니다.

| 상태 | 처리 |
| - | - |
| `pending` / `processing` | 계속 조회하며 `data.progress`로 진행률을 확인합니다. |
| `completed` | 동영상 링크를 읽고 저장합니다. |
| `failed` | `data.error.message`를 확인합니다. 실패 작업은 과금하지 않습니다. |

## 과금과 선차감

토큰 기준으로 과금하며 해상도는 초당 출력 토큰 수에 영향을 줍니다. 텍스트·이미지 기반 생성에서는 `duration`이 출력 길이를 지정합니다. 편집에서는 이 값을 무시하고 원본 길이를 유지하며, 연장에서는 추가 구간 길이만 지정합니다. 실제 요금은 [APIMart 가격 페이지](https://apimart.ai/pricing)를 확인하세요.

제출 시 해상도와 `max(10, duration)`초를 기준으로 선차감하며, 동영상 입력이 있으면 15초로 계산합니다. 선차감액은 최종 요금이 아닙니다. 성공 후 실제 사용량에 따라 차액을 정산하며 최종 금액은 `data.cost`에서 확인합니다.

연장은 추가된 초에 대해서만 과금합니다. 실패는 과금하지 않습니다. 선차감액을 충당할 잔액이 없으면 HTTP 402를 반환합니다.

## 오류 처리

매개변수 오류(`invalid_*` / `unsupported_*`)는 작업을 즉시 `failed`로 변경하며 과금하지 않습니다. 제출에 성공해도 작업 상태를 조회해야 합니다.

| 오류 / 상태 | 원인과 처리 |
| - | - |
| `invalid_duration` | `duration`이 3–15 범위를 벗어나거나 보간·연장이 10초를 초과했습니다. 허용 범위의 정수를 사용하세요. |
| `invalid_task_type` | 지원하지 않는 `omni_reference_task_type` 값입니다. `auto` / `edit` / `extend` / `reference`를 사용하세요. `text_to_video` / `image_to_video` / `reference_to_video`도 허용합니다. |
| `invalid_resolution` | `360p` / `720p` / `1080p` / `4k`를 사용하세요. `2160p`도 허용합니다. |
| `invalid_frame_images` | 마지막 프레임만 제공했습니다. 첫 프레임을 추가하세요. |
| `unsupported_image_count` | 첫·마지막 프레임을 포함해 10장을 초과했습니다. 이미지 수를 줄이세요. |
| `unsupported_video_count` | 입력 영상이 1개를 초과했습니다. 15초 이하 영상 1개만 사용하세요. |
| `HTTP 400` | 필수 매개변수 `prompt`가 없습니다. 자료를 제공해도 텍스트 지시문을 전달해야 합니다. |
| `HTTP 401` | 키가 유효하지 않습니다. Authorization을 확인하세요. |
| `HTTP 402` | 선차감 잔액이 부족합니다. 충전하거나 해상도를 낮추세요. |
| `HTTP 429` | 요청 한도를 초과했습니다. 대기 시간을 늘려 재시도하세요. |
| `status: failed` | 상위 서비스 오류 또는 콘텐츠 정책 거절입니다. `data.error.message`를 읽고 요청을 수정하세요. |

## 자주 묻는 질문

### 이미지나 동영상을 제공해도 `prompt`가 필요한가요?

네. 이미지 기반 동영상 생성, 첫·마지막 프레임 보간, 편집, 연장, `extend_from_task_id`를 통한 영상 재사용 등 모든 모드에서 `prompt`가 필수입니다. 생략하면 HTTP 400을 반환합니다.

### Base64 이미지나 동영상을 직접 전송할 수 있나요?

지원하지 않습니다. `image_urls`, `first_frame_image`, `last_frame_image`, `image_with_roles[].url`, `video_urls`는 공개적으로 접근 가능한 HTTP(S) 직접 링크만 지원합니다. `data:image/...`, `data:video/...` 또는 원시 Base64 문자열을 전송하면 안 됩니다.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.