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

# Generación de Video HappyHorse 1.0

>  - Modelo de generación de video HappyHorse 1.0 de Alibaba Cloud Bailian (entrada unificada, enrutamiento automático de modelo único)
- Enrutamiento automático por parámetros: T2V (solo prompt) / I2V (first_frame_image) / R2V (image_urls) / EDIT (video_url)
- Soporta resoluciones 720P/1080P y cualquier duración entera de 3 a 15 segundos
- Facturado únicamente por resolución × duración (segundos), independientemente de la capacidad 

```bash cURL theme={null}
curl --request POST \
  --url https://gccai.heqingsong.uk/v1/videos/generations \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '{
    "model": "happyhorse-1.0",
    "prompt": "A little girl walking down the road, cinematic feel",
    "resolution": "1080P",
    "size": "16:9",
    "duration": 5,
    "seed": 42
  }'
```

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

url = "https://gccai.heqingsong.uk/v1/videos/generations"

payload = {
    "model": "happyhorse-1.0",
    "prompt": "A little girl walking down the road, cinematic feel",
    "resolution": "1080P",
    "size": "16:9",
    "duration": 5,
    "seed": 42
}

headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript JavaScript theme={null}
const url = "https://gccai.heqingsong.uk/v1/videos/generations";

const payload = {
  model: "happyhorse-1.0",
  prompt: "A little girl walking down the road, cinematic feel",
  resolution: "1080P",
  size: "16:9",
  duration: 5,
  seed: 42
};

const headers = {
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
};

fetch(url, {
  method: "POST",
  headers: headers,
  body: JSON.stringify(payload)
})
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error('Error:', error));
```

```go Go theme={null}
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net/http"
)

func main() {
    url := "https://gccai.heqingsong.uk/v1/videos/generations"

    payload := map[string]interface{}{
        "model":      "happyhorse-1.0",
        "prompt":     "A little girl walking down the road, cinematic feel",
        "resolution": "1080P",
        "size":       "16:9",
        "duration":   5,
        "seed":       42,
    }

    jsonData, _ := json.Marshal(payload)

    req, _ := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
    req.Header.Set("Authorization", "Bearer <token>")
    req.Header.Set("Content-Type", "application/json")

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()

    body, _ := ioutil.ReadAll(resp.Body)
    fmt.Println(string(body))
}
```

```java Java theme={null}
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.URI;

public class Main {
    public static void main(String[] args) throws Exception {
        String url = "https://gccai.heqingsong.uk/v1/videos/generations";

        String payload = """
        {
          "model": "happyhorse-1.0",
          "prompt": "A little girl walking down the road, cinematic feel",
          "resolution": "1080P",
          "size": "16:9",
          "duration": 5,
          "seed": 42
        }
        """;

        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create(url))
            .header("Authorization", "Bearer <token>")
            .header("Content-Type", "application/json")
            .POST(HttpRequest.BodyPublishers.ofString(payload))
            .build();

        HttpResponse<String> response = client.send(request,
            HttpResponse.BodyHandlers.ofString());

        System.out.println(response.body());
    }
}
```

```php PHP theme={null}
<?php

$url = "https://gccai.heqingsong.uk/v1/videos/generations";

$payload = [
    "model" => "happyhorse-1.0",
    "prompt" => "A little girl walking down the road, cinematic feel",
    "resolution" => "1080P",
    "size" => "16:9",
    "duration" => 5,
    "seed" => 42
];

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer <token>",
    "Content-Type: application/json"
]);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
?>
```

```ruby Ruby theme={null}
require 'net/http'
require 'json'
require 'uri'

url = URI("https://gccai.heqingsong.uk/v1/videos/generations")

payload = {
  model: "happyhorse-1.0",
  prompt: "A little girl walking down the road, cinematic feel",
  resolution: "1080P",
  size: "16:9",
  duration: 5,
  seed: 42
}

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = "Bearer <token>"
request["Content-Type"] = "application/json"
request.body = payload.to_json

response = http.request(request)
puts response.body
```

```swift Swift theme={null}
import Foundation

let url = URL(string: "https://gccai.heqingsong.uk/v1/videos/generations")!

let payload: [String: Any] = [
    "model": "happyhorse-1.0",
    "prompt": "A little girl walking down the road, cinematic feel",
    "resolution": "1080P",
    "size": "16:9",
    "duration": 5,
    "seed": 42
]

var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("Bearer <token>", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = try? JSONSerialization.data(withJSONObject: payload)

let task = URLSession.shared.dataTask(with: request) { data, response, error in
    if let error = error {
        print("Error: \(error)")
        return
    }

    if let data = data, let responseString = String(data: data, encoding: .utf8) {
        print(responseString)
    }
}

task.resume()
```

```csharp C# theme={null}
using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

class Program
{
    static async Task Main(string[] args)
    {
        var url = "https://gccai.heqingsong.uk/v1/videos/generations";

        var payload = @"{
            ""model"": ""happyhorse-1.0"",
            ""prompt"": ""A little girl walking down the road, cinematic feel"",
            ""resolution"": ""1080P"",
            ""size"": ""16:9"",
            ""duration"": 5,
            ""seed"": 42
        }";

        using var client = new HttpClient();
        client.DefaultRequestHeaders.Add("Authorization", "Bearer <token>");

        var content = new StringContent(payload, Encoding.UTF8, "application/json");
        var response = await client.PostAsync(url, content);
        var result = await response.Content.ReadAsStringAsync();

        Console.WriteLine(result);
    }
}
```

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

```json 400 theme={null}
{
  "error": {
    "code": 400,
    "message": "Invalid request parameters",
    "type": "invalid_request_error"
  }
}
```

```json 401 theme={null}
{
  "error": {
    "code": 401,
    "message": "Invalid authentication credentials",
    "type": "authentication_error"
  }
}
```

```json 402 theme={null}
{
  "error": {
    "code": 402,
    "message": "Insufficient balance. Please top up your account",
    "type": "payment_required"
  }
}
```

```json 429 theme={null}
{
  "error": {
    "code": 429,
    "message": "Rate limit exceeded. Please try again later",
    "type": "rate_limit_error"
  }
}
```

```json 500 theme={null}
{
  "error": {
    "code": 500,
    "message": "Internal server error. Please try again later",
    "type": "server_error"
  }
}
```

## Autorización

**Authorization** `string` *required*

Todos los endpoints de la API requieren autenticación mediante Bearer Token

Obtenga su API Key:

Visite la [página de gestión de API Keys](https://gccai.heqingsong.uk/keys) para obtener su API Key

Añádala al encabezado de la solicitud:

```
Authorization: Bearer YOUR_API_KEY
```

## Enrutamiento de modos

`happyhorse-1.0` es la entrada unificada para Text-to-Video / Image-to-Video / Reference-Image-to-Video / Video Edit. El backend determina automáticamente el modo según los parámetros entrantes. **Todos los modos se facturan con la misma regla (solo resolución × segundos)**:

| Campos que envía | Se enruta a | Descripción del modo |
| - | - | - |
| Solo `prompt` | Text-to-Video (T2V) | Genera video únicamente a partir de texto |
| `prompt` + `first_frame_image` | Image-to-Video (I2V) | Anima desde una imagen del primer fotograma |
| `prompt` + `image_urls` (1–9 imágenes) | Reference-Image-to-Video (R2V) | Genera una nueva escena a partir de imágenes de referencia |
| `prompt` + `video_url` (opcional `image_urls` 0–5 como referencias de estilo / `audio_setting`) | Video Edit (EDIT) | Reescribe / re-estiliza un video fuente |

**Prioridad de enrutamiento** (de alta a baja): `video_url` > `first_frame_image` > `image_urls` > solo `prompt`.

**Reglas de exclusión mutua**: los tres campos de medios (`first_frame_image` / `image_urls` / `video_url`) son **mutuamente excluyentes por pares**. La única combinación válida es `video_url + image_urls` (modo EDIT + imágenes de referencia). Pasar dos campos mutuamente excluyentes devuelve 400 `mixed_media_not_allowed`.

## Parámetros de la solicitud

**model** `string` *required*

Nombre del modelo de generación de video, fijado como `happyhorse-1.0`

**nsfw\_check** `boolean` (default: false)

Indica si se debe moderar el contenido antes de enviar la tarea de vídeo.

* `true`: revisar los prompts y las imágenes de entrada con `omni-moderation-latest`
* `false` u omitido: no enviar una solicitud de moderación, sin coste ni latencia de moderación adicionales (predeterminado)

**prompt** `string`

Descripción del contenido del video, hasta 2500 caracteres; no puede contener tokens especiales

* **Modos T2V / R2V / EDIT**: obligatorio
* **Modo I2V**: opcional, pero recomendado para guiar el movimiento de cámara y las acciones

Ejemplo: `"A little girl walking down the road, cinematic feel"`

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

Imagen del primer fotograma, activa **I2V** (Image-to-Video). Admite URL o base64 (`data:image/<mime>;base64,<payload>`, el gateway la sube automáticamente a OSS)

Mutuamente excluyente con `image_urls` / `video_url`

> [!NOTE]
>
> **Requisitos de la imagen del primer fotograma:**
>
> * Formato: JPEG / JPG / PNG / BMP / WEBP
> * Lado corto: ≥ 300px
> * Proporción de aspecto: `1:2.5` a `2.5:1`
> * Tamaño del archivo: ≤ 10MB

**image\_urls** `array\<string\>`

Array de imágenes:

* **Modo R2V** (solo se proporciona `image_urls`): 1–9 imágenes, usadas como referencias de sujeto/estilo para generar una nueva escena
* **Modo EDIT** (proporcionado junto con `video_url`): 0–5 imágenes, usadas como referencia de estilo

Admite URL o base64

Mutuamente excluyente con `first_frame_image`; puede combinarse con `video_url`

> [!NOTE]
>
> **Requisitos de las imágenes de referencia:**
>
> * Formato: JPEG / JPG / PNG / BMP / WEBP
> * Lado corto: ≥ 720p recomendado
> * Proporción de aspecto: corto / largo ≥ 0.4
> * Tamaño del archivo: ≤ 10MB
> * Cantidad: R2V debe ser 1–9; EDIT hasta 5

**video\_url** `string`

URL del video fuente, activa **EDIT** (Video Edit). **No se admite Base64** — proporcione un enlace directo HTTP/HTTPS

Mutuamente excluyente con `first_frame_image`; puede combinarse con `image_urls` (≤ 5)

> [!NOTE]
>
> **Requisitos del video fuente:**
>
> * Duración: 3–60 segundos (> 15s será truncado automáticamente por el upstream de 0 a 15s)
> * Resolución: mínimo 480p, lado corto ≥ 360
> * Proporción de aspecto: `1:8` a `8:1`
> * Formato: MP4 / MOV (H.264 recomendado)
> * Tasa de fotogramas: > 8 fps
> * Tamaño del archivo: ≤ 100MB

> [!WARNING]
>
> **En modo EDIT, la duración del video generado coincide con la del video fuente** (limitada a los 15s truncados cuando la fuente es más larga). El parámetro `duration` no tiene efecto aquí. Para controlar la duración de salida, recorte el video fuente a la duración deseada antes de subirlo.

**audio\_setting** `string` (default: auto)

Configuración de audio, **solo efectiva en modo EDIT** (debe pasar `video_url`)

Opciones:

* `auto` - Genera audio automáticamente (por defecto)
* `origin` - Mantiene la pista de audio del video fuente

> [!WARNING]
>
> Pasar este campo fuera del modo EDIT devuelve 400 `audio_setting_only_for_edit`

**resolution** `string` (default: 1080P)

Resolución del video (afecta a la facturación)

Opciones:

* `720P` - Estándar
* `1080P` - Alta definición (por defecto)

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

Duración del video en segundos (afecta a la facturación)

Rango soportado: cualquier entero de `3` a `15`

Por defecto: `5`

> [!WARNING]
>
> **No tiene efecto en modo EDIT (cuando se proporciona `video_url`)**: la duración del video generado coincide con la del video fuente (facturada por los 15s truncados cuando la fuente es más larga que 15s). Para controlar la duración de salida, recorte primero el video fuente.

**size** `string` (default: 16:9)

Proporción de aspecto

Formatos soportados:

* `16:9` - Paisaje panorámico (por defecto)
* `9:16` - Retrato
* `1:1` - Cuadrado
* `4:3` - Paisaje
* `3:4` - Retrato

> [!WARNING]
>
> **Ignorado en modos I2V / EDIT** — la proporción de aspecto de salida se determina automáticamente por el medio de entrada (imagen del primer fotograma / video fuente)

**watermark** `boolean` (default: false)

Si se debe añadir una marca de agua al video generado

* `true`: añadir marca de agua
* `false`: no añadir marca de agua (por defecto)

**seed** `integer`

Semilla aleatoria usada para controlar la aleatoriedad del contenido generado

Rango de valores: `[0, 2147483647]`. Si se omite, se usa una semilla aleatoria.

> [!NOTE]
>
> * Para solicitudes idénticas, el modelo genera resultados diferentes al recibir valores de seed diferentes (por ejemplo, al omitir el seed)
> * Para solicitudes idénticas, el modelo genera resultados similares al recibir el mismo valor de seed, pero no se garantiza consistencia exacta

## Respuesta

**code** `integer`

Código de estado de la respuesta, 200 en caso de éxito

**data** `array`

Array de datos de la respuesta

**Elementos del array**

**status** `string`

Estado de la tarea, `submitted` al enviarse inicialmente

**task\_id** `string`

Identificador único de la tarea para consultar el estado y los resultados

## Casos de uso

### Caso 1: Texto a video T2V (Solicitud más simple)

```json theme={null}
{
  "model": "happyhorse-1.0",
  "prompt": "A little girl walking down the road, cinematic feel"
}
```

### Caso 2: Texto a video T2V (Parámetros completos)

```json theme={null}
{
  "model": "happyhorse-1.0",
  "prompt": "A coastal road at sunset, slow-motion camera push-in, cinematic feel",
  "resolution": "1080P",
  "size": "16:9",
  "duration": 8,
  "seed": 42
}
```

### Caso 3: Imagen a video I2V (first\_frame\_image)

```json theme={null}
{
  "model": "happyhorse-1.0",
  "prompt": "Bring the scene in the image to life",
  "first_frame_image": "https://example.com/first_frame.png",
  "resolution": "1080P",
  "duration": 5
}
```

### Caso 4: Referencia-Imagen a video R2V (múltiples referencias)

```json theme={null}
{
  "model": "happyhorse-1.0",
  "prompt": "The protagonist from image 1 runs through the scene from image 2, then picks up the prop from image 3. Keep a 3D cartoon style with smooth motion.",
  "image_urls": [
    "https://example.com/img_01.jpg",
    "https://example.com/img_02.png",
    "https://example.com/img_03.jpeg"
  ],
  "resolution": "1080P",
  "size": "16:9",
  "duration": 5
}
```

### Caso 5: Video Edit EDIT (mantener audio original + referencia de estilo)

```json theme={null}
{
  "model": "happyhorse-1.0",
  "prompt": "Convert the character in the video to a cartoon style, preserving the original motion",
  "video_url": "https://example.com/source.mp4",
  "image_urls": [
    "https://example.com/style_ref.jpg"
  ],
  "resolution": "1080P",
  "audio_setting": "origin",
  "seed": 42
}
```

### Caso 6: 720P para ahorrar costos

```json theme={null}
{
  "model": "happyhorse-1.0",
  "prompt": "Waves crashing on the beach at sunset",
  "resolution": "720P",
  "size": "16:9",
  "duration": 5
}
```

## Guía de selección de modo

| Requisito | Enfoque recomendado |
| - | - |
| Generar video solo a partir de texto | Pasar solo `prompt` (T2V) |
| Hacer que una imagen "cobre vida" (usarla como primer fotograma) | Pasar `first_frame_image` (I2V) |
| Generar una nueva escena a partir de un conjunto de imágenes de referencia | Pasar `image_urls` (1–9, R2V) |
| Reescribir / re-estilizar un video existente | Pasar `video_url` (EDIT), opcionalmente combinar con `image_urls` (0–5) como referencias de estilo |
| Ahorrar costos | Usar `resolution: "720P"` |

## Consejos de uso

1. **Lógica de entrada unificada**: los campos de entrada determinan el modo. Tenga en cuenta que los tres campos de medios (`first_frame_image` / `image_urls` / `video_url`) son mutuamente excluyentes por pares
2. **`size` solo efectivo en T2V/R2V**: en los modos I2V / EDIT, `size` se ignora — la proporción de aspecto de salida está determinada por el medio de entrada
3. **Duración**: de 5 a 10 segundos es el punto óptimo. Demasiado corta causa movimiento entrecortado; demasiado larga aumenta significativamente el tiempo de procesamiento upstream
4. **Calidad de la imagen del primer fotograma**: clara, bien compuesta, sujeto centrado — mejora significativamente la salida I2V
5. **Redacción del prompt**: describa movimiento / cámara / atmósfera (por ejemplo, "slow push-in, cinematic, warm tones") para obtener mejores resultados que con descripciones puramente estáticas de la escena
6. **Video de entrada EDIT**: > 15 segundos será truncado automáticamente por el upstream de 0 a 15s. Si necesita otros segmentos, recorte el video usted mismo primero

> [!NOTE]
>
> **Consultar resultados de la tarea**
>
> La generación de video es una tarea asíncrona que devuelve un `task_id` al enviarse. Use el endpoint [Obtener estado de la tarea](https://gccai.heqingsong.uk/es/api-reference/tasks/status.md) para consultar el progreso y los resultados de la generación.


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