Claude Opus 5 is now live on CometAPI →
Q

Happy Horse 1.0

Per Sekund:$0.112
Udgivet:May 31, 2026

Happy Horse 1.0 — en højkvalitets lyd- og videogenereringsmodel, der understøtter tekst-til-video- og billede-til-video-generering. Den kan generere synkroniserede visuelle elementer, lyd og læbebevægelser, hvilket gør den velegnet til kortfilm, annoncekreativer og produktpræsentationer.

Ny
Kommersiel brug

Playground for Happy Horse 1.0

Udforsk Happy Horse 1.0's Playground — et interaktivt miljø til at teste modeller og køre forespørgsler i realtid. Prøv prompts, juster parametre og iterer øjeblikkeligt for at fremskynde udvikling og validere use cases.

Tekniske specifikationer for HappyHorse-1.0

PunktHappyHorse-1.0
UdbyderAlibaba (offentligt rapporteret efter anonym benchmark-debut)
ModeltypeMultimodal AI-videogenerering
InputTekst, billede
OutputVideo + synkroniseret lyd
ArkitekturSamlet enkeltstrøms-Transformer
Parametre~15B
OpløsningNative 1080p-generering
GenereringstilstandSamlet lyd- og videogenerering
AfstøjningDestilleret inferens (~8 trin rapporteret)
SprogunderstøttelseFlersproget læbesynkronisering (7 sprog rapporteret)

Hvad er HappyHorse-1.0

HappyHorse-1.0 er en banebrydende AI-videogenereringsmodel, der er designet til at producere video og synkroniseret lyd i én samlet genereringspipeline i stedet for at sammenstykke flere modeller. Offentlige rapporter indikerer, at modellen dukkede op anonymt på benchmark-arenaer, før den senere blev knyttet til Alibabas AI-indsats.

I modsætning til konventionelle tekst-til-video-systemer, der først gengiver visuelle elementer og lægger lyd på bagefter, lægger HappyHorse vægt på indbygget synkronisering mellem bevægelse, tale, omgivelseslyd og timing.

Hovedfunktioner for HappyHorse-1.0

  • Samlet lyd + video-generering i ét gennemløb
  • Native 1080p-output i stedet for obligatorisk opskalering
  • Tekst-til-video- og billede-til-video-arbejdsgange
  • Hurtig destilleret genereringspipeline
  • Flersproget læbesynkronisering
  • Fokus på filmisk kamerabevægelse og scenekontinuitet

Benchmark-ydelse for HappyHorse-1.0

Offentlige benchmark-rapporter antyder:

  • Artificial Analysis Arena:
    • Tekst-til-video Elo: ~1330+
    • Billede-til-video Elo: ~1390+
  • Placeret som nr. 1 eller tæt på i offentlige rangliste-øjebliksbilleder i de tidlige udgivelsesperioder.

Fortolkning af benchmark: Dette er præferencebaserede ranglistescores og bør ikke opfattes som universelle kvalitetsplaceringer på tværs af alle produktionsarbejdsbelastninger.

HappyHorse-1.0 vs. lignende modeller

FunktionalitetHappyHorse-1.0Seedance 2.0Kling 3.0
Samlet lyd + videoJaJaDelvis
Native 1080pJaJaJa
Åben frigivelsesretningAnnonceretProprietærProprietær
Tekst→VideoJaJaJa
Billede→VideoJaJaJa
Flersproget læbesynkronisering7 rapporteretFlersprogetFlersproget

Hvordan bruger jeg HappyHorse-1.0 med CometAPI?

  1. Få API-legitimationsoplysninger.
  2. Vælg happyhorse-1.0.
  3. Send genereringsanmodninger med prompt + genereringsindstillinger.
  4. Hent det genererede medieoutput.

FAQ

Priser for Happy Horse 1.0

Udforsk konkurrencedygtige priser for Happy Horse 1.0, designet til at passe til forskellige budgetter og brugsbehov. Vores fleksible planer sikrer, at du kun betaler for det, du bruger, hvilket gør det nemt at skalere, efterhånden som dine krav vokser. Opdag hvordan Happy Horse 1.0 kan forbedre dine projekter, mens omkostningerne holdes håndterbare.

Happyhorse Video Generation Pricing

Pricing (Per Second)

Model720p1080p
happyhorse-1.0$0.112$0.192

💡 Billed per second. Total cost = price per second × video duration (seconds).

Eksempelkode og API til Happy Horse 1.0

Få adgang til omfattende eksempelkode og API-ressourcer for Happy Horse 1.0 for at strømline din integrationsproces. Vores detaljerede dokumentation giver trin-for-trin vejledning, der hjælper dig med at udnytte det fulde potentiale af Happy Horse 1.0 i dine projekter.

#!/bin/bash

set -euo pipefail

if [[ -z "${COMETAPI_KEY:-}" ]]; then
  echo "Set COMETAPI_KEY before running this example."
  exit 0
fi

MODEL="happyhorse-1.0"
PROMPT='A miniature city built from cardboard and bottle caps comes alive at night. A tiny cardboard train rolls through the streets while warm lights glow from paper windows, physically realistic motion, detailed tabletop cinematography.'
VIDEO_SECONDS="3"
SIZE="1280x720"
BASE_URL="https://api.cometapi.com"
OUTPUT_DIR="./output"
POLL_INTERVAL_SECONDS=10
RETRY_DELAY_SECONDS=5
MAX_CREATE_ATTEMPTS=5

is_progress_complete() {
  local progress="$1"
  local normalized="${progress%%%}"

  if [[ -z "$normalized" ]]; then
    return 1
  fi

  [[ "$normalized" =~ ^[0-9]+([.][0-9]+)?$ ]] || return 1
  awk -v value="$normalized" 'BEGIN { exit !(value >= 100) }'
}

is_transient_status() {
  local status_code="$1"
  [[ "$status_code" == "429" || "$status_code" =~ ^5 ]]
}

create_task() {
  local attempt=1
  while (( attempt <= MAX_CREATE_ATTEMPTS )); do
    local response
    local status_code
    if ! response=$(curl -sS -w $'
%{http_code}' "${BASE_URL}/v1/videos"       -H "Authorization: Bearer $COMETAPI_KEY"       -F "model=${MODEL}"       -F "prompt=${PROMPT}"       -F "seconds=${VIDEO_SECONDS}"       -F "size=${SIZE}"); then
      if (( attempt == MAX_CREATE_ATTEMPTS )); then
        return 1
      fi
      echo "Create request failed, retrying..."
      sleep "$RETRY_DELAY_SECONDS"
      (( attempt += 1 ))
      continue
    fi

    status_code=$(echo "$response" | tail -n 1)
    CREATE_RESPONSE=$(echo "$response" | sed '$d')

    if [[ "$status_code" =~ ^2 ]]; then
      return 0
    fi

    if is_transient_status "$status_code" && (( attempt < MAX_CREATE_ATTEMPTS )); then
      echo "Create request returned ${status_code}, retrying..."
      sleep "$RETRY_DELAY_SECONDS"
      (( attempt += 1 ))
      continue
    fi

    echo "$CREATE_RESPONSE"
    return 1
  done
}

get_task() {
  local task_id="$1"
  while true; do
    local response
    local status_code
    if ! response=$(curl -sS -w $'
%{http_code}' "${BASE_URL}/v1/videos/${task_id}"       -H "Authorization: Bearer $COMETAPI_KEY"); then
      echo "Status request failed, retrying..."
      sleep "$RETRY_DELAY_SECONDS"
      continue
    fi

    status_code=$(echo "$response" | tail -n 1)
    TASK_RESPONSE=$(echo "$response" | sed '$d')

    if [[ "$status_code" =~ ^2 ]]; then
      return 0
    fi

    if is_transient_status "$status_code"; then
      echo "Status request returned ${status_code}, retrying..."
      sleep "$RETRY_DELAY_SECONDS"
      continue
    fi

    echo "$TASK_RESPONSE"
    return 1
  done
}

download_video() {
  local content_url="$1"
  local output_path="$2"

  while true; do
    if curl -fsS "$content_url"       -H "Authorization: Bearer $COMETAPI_KEY"       -o "$output_path"; then
      if [[ -s "$output_path" ]]; then
        return 0
      fi
      echo "Content download was empty, retrying..."
    else
      echo "Content request failed, retrying..."
    fi
    sleep "$RETRY_DELAY_SECONDS"
  done
}

create_task

TASK_ID=$(echo "$CREATE_RESPONSE" | jq -r '.id // .task_id // empty')

if [[ -z "$TASK_ID" ]]; then
  echo "$CREATE_RESPONSE" | jq .
  echo "No task id returned."
  exit 1
fi

echo "Task created: $TASK_ID"
echo "Initial status: $(echo "$CREATE_RESPONSE" | jq -r '.status // empty')"

while true; do
  get_task "$TASK_ID"

  STATUS=$(echo "$TASK_RESPONSE" | jq -r '.status // empty')
  NORMALIZED_STATUS=$(echo "$STATUS" | tr '[:upper:]' '[:lower:]')
  PROGRESS=$(echo "$TASK_RESPONSE" | jq -r '.progress // empty')
  SHOULD_DOWNLOAD=0

  if [[ "$NORMALIZED_STATUS" == "completed" || "$NORMALIZED_STATUS" == "success" ]]; then
    SHOULD_DOWNLOAD=1
  elif [[ "$NORMALIZED_STATUS" == "unknown" ]] && is_progress_complete "$PROGRESS"; then
    SHOULD_DOWNLOAD=1
  fi

  echo "Status: ${STATUS}, progress: ${PROGRESS}"

  if [[ "$SHOULD_DOWNLOAD" == "1" || "$NORMALIZED_STATUS" == "failed" || "$NORMALIZED_STATUS" == "error" ]]; then
    if [[ "$SHOULD_DOWNLOAD" != "1" ]]; then
      echo "$TASK_RESPONSE" | jq .
      exit 1
    fi

    VIDEO_URL=$(echo "$TASK_RESPONSE" | jq -r '.video_url // empty')
    CONTENT_URL="${BASE_URL}/v1/videos/${TASK_ID}/content"
    OUTPUT_PATH="${OUTPUT_DIR}/${TASK_ID}.mp4"

    mkdir -p "$OUTPUT_DIR"
    download_video "$CONTENT_URL" "$OUTPUT_PATH"

    echo "Video URL: ${VIDEO_URL}"
    echo "Content endpoint: ${CONTENT_URL}"
    echo "Saved to ${OUTPUT_PATH}"
    echo "File size: $(wc -c < "$OUTPUT_PATH" | tr -d ' ') bytes"
    break
  fi

  sleep "$POLL_INTERVAL_SECONDS"
done

cURL Code Example

#!/bin/bash

set -euo pipefail

if [[ -z "${COMETAPI_KEY:-}" ]]; then
  echo "Set COMETAPI_KEY before running this example."
  exit 0
fi

MODEL="happyhorse-1.0"
PROMPT='A miniature city built from cardboard and bottle caps comes alive at night. A tiny cardboard train rolls through the streets while warm lights glow from paper windows, physically realistic motion, detailed tabletop cinematography.'
VIDEO_SECONDS="3"
SIZE="1280x720"
BASE_URL="https://api.cometapi.com"
OUTPUT_DIR="./output"
POLL_INTERVAL_SECONDS=10
RETRY_DELAY_SECONDS=5
MAX_CREATE_ATTEMPTS=5

is_progress_complete() {
  local progress="$1"
  local normalized="${progress%%%}"

  if [[ -z "$normalized" ]]; then
    return 1
  fi

  [[ "$normalized" =~ ^[0-9]+([.][0-9]+)?$ ]] || return 1
  awk -v value="$normalized" 'BEGIN { exit !(value >= 100) }'
}

is_transient_status() {
  local status_code="$1"
  [[ "$status_code" == "429" || "$status_code" =~ ^5 ]]
}

create_task() {
  local attempt=1
  while (( attempt <= MAX_CREATE_ATTEMPTS )); do
    local response
    local status_code
    if ! response=$(curl -sS -w $'
%{http_code}' "${BASE_URL}/v1/videos"       -H "Authorization: Bearer $COMETAPI_KEY"       -F "model=${MODEL}"       -F "prompt=${PROMPT}"       -F "seconds=${VIDEO_SECONDS}"       -F "size=${SIZE}"); then
      if (( attempt == MAX_CREATE_ATTEMPTS )); then
        return 1
      fi
      echo "Create request failed, retrying..."
      sleep "$RETRY_DELAY_SECONDS"
      (( attempt += 1 ))
      continue
    fi

    status_code=$(echo "$response" | tail -n 1)
    CREATE_RESPONSE=$(echo "$response" | sed '$d')

    if [[ "$status_code" =~ ^2 ]]; then
      return 0
    fi

    if is_transient_status "$status_code" && (( attempt < MAX_CREATE_ATTEMPTS )); then
      echo "Create request returned ${status_code}, retrying..."
      sleep "$RETRY_DELAY_SECONDS"
      (( attempt += 1 ))
      continue
    fi

    echo "$CREATE_RESPONSE"
    return 1
  done
}

get_task() {
  local task_id="$1"
  while true; do
    local response
    local status_code
    if ! response=$(curl -sS -w $'
%{http_code}' "${BASE_URL}/v1/videos/${task_id}"       -H "Authorization: Bearer $COMETAPI_KEY"); then
      echo "Status request failed, retrying..."
      sleep "$RETRY_DELAY_SECONDS"
      continue
    fi

    status_code=$(echo "$response" | tail -n 1)
    TASK_RESPONSE=$(echo "$response" | sed '$d')

    if [[ "$status_code" =~ ^2 ]]; then
      return 0
    fi

    if is_transient_status "$status_code"; then
      echo "Status request returned ${status_code}, retrying..."
      sleep "$RETRY_DELAY_SECONDS"
      continue
    fi

    echo "$TASK_RESPONSE"
    return 1
  done
}

download_video() {
  local content_url="$1"
  local output_path="$2"

  while true; do
    if curl -fsS "$content_url"       -H "Authorization: Bearer $COMETAPI_KEY"       -o "$output_path"; then
      if [[ -s "$output_path" ]]; then
        return 0
      fi
      echo "Content download was empty, retrying..."
    else
      echo "Content request failed, retrying..."
    fi
    sleep "$RETRY_DELAY_SECONDS"
  done
}

create_task

TASK_ID=$(echo "$CREATE_RESPONSE" | jq -r '.id // .task_id // empty')

if [[ -z "$TASK_ID" ]]; then
  echo "$CREATE_RESPONSE" | jq .
  echo "No task id returned."
  exit 1
fi

echo "Task created: $TASK_ID"
echo "Initial status: $(echo "$CREATE_RESPONSE" | jq -r '.status // empty')"

while true; do
  get_task "$TASK_ID"

  STATUS=$(echo "$TASK_RESPONSE" | jq -r '.status // empty')
  NORMALIZED_STATUS=$(echo "$STATUS" | tr '[:upper:]' '[:lower:]')
  PROGRESS=$(echo "$TASK_RESPONSE" | jq -r '.progress // empty')
  SHOULD_DOWNLOAD=0

  if [[ "$NORMALIZED_STATUS" == "completed" || "$NORMALIZED_STATUS" == "success" ]]; then
    SHOULD_DOWNLOAD=1
  elif [[ "$NORMALIZED_STATUS" == "unknown" ]] && is_progress_complete "$PROGRESS"; then
    SHOULD_DOWNLOAD=1
  fi

  echo "Status: ${STATUS}, progress: ${PROGRESS}"

  if [[ "$SHOULD_DOWNLOAD" == "1" || "$NORMALIZED_STATUS" == "failed" || "$NORMALIZED_STATUS" == "error" ]]; then
    if [[ "$SHOULD_DOWNLOAD" != "1" ]]; then
      echo "$TASK_RESPONSE" | jq .
      exit 1
    fi

    VIDEO_URL=$(echo "$TASK_RESPONSE" | jq -r '.video_url // empty')
    CONTENT_URL="${BASE_URL}/v1/videos/${TASK_ID}/content"
    OUTPUT_PATH="${OUTPUT_DIR}/${TASK_ID}.mp4"

    mkdir -p "$OUTPUT_DIR"
    download_video "$CONTENT_URL" "$OUTPUT_PATH"

    echo "Video URL: ${VIDEO_URL}"
    echo "Content endpoint: ${CONTENT_URL}"
    echo "Saved to ${OUTPUT_PATH}"
    echo "File size: $(wc -c < "$OUTPUT_PATH" | tr -d ' ') bytes"
    break
  fi

  sleep "$POLL_INTERVAL_SECONDS"
done

Python Code Example

import json
import os
import time

import requests


MODEL = "happyhorse-1.0"
PROMPT = (
    "A miniature city built from cardboard and bottle caps comes alive at night. "
    "A tiny cardboard train rolls through the streets while warm lights glow from "
    "paper windows, physically realistic motion, detailed tabletop cinematography."
)
SECONDS = "3"
SIZE = "1280x720"
BASE_URL = "https://api.cometapi.com"
OUTPUT_DIR = "./output"
POLL_INTERVAL_SECONDS = 10
RETRY_DELAY_SECONDS = 5
MAX_CREATE_ATTEMPTS = 5
TERMINAL_STATUSES = {"completed", "failed", "error", "success"}
SUCCESS_STATUSES = {"completed", "success"}


try:
    COMETAPI_KEY = os.environ["COMETAPI_KEY"]
except KeyError:
    print("Set COMETAPI_KEY before running this example.")
    raise SystemExit(0)


headers = {"Authorization": f"Bearer {COMETAPI_KEY}"}


def is_progress_complete(progress):
    if isinstance(progress, (int, float)):
        return progress >= 100
    if isinstance(progress, str):
        try:
            return float(progress.rstrip("%")) >= 100
        except ValueError:
            return False
    return False


def is_transient_status(status_code):
    return status_code == 429 or 500 <= status_code < 600


def create_task():
    fields = {
        "model": (None, MODEL),
        "prompt": (None, PROMPT),
        "seconds": (None, SECONDS),
        "size": (None, SIZE),
    }
    for attempt in range(1, MAX_CREATE_ATTEMPTS + 1):
        try:
            response = requests.post(
                f"{BASE_URL}/v1/videos",
                headers=headers,
                files=fields,
                timeout=30,
            )
        except requests.RequestException as error:
            if attempt == MAX_CREATE_ATTEMPTS:
                raise
            print(f"Create request failed: {error}, retrying...")
            time.sleep(RETRY_DELAY_SECONDS)
            continue

        if response.ok:
            return response
        if not is_transient_status(response.status_code) or attempt == MAX_CREATE_ATTEMPTS:
            response.raise_for_status()
        print(f"Create request returned {response.status_code}, retrying...")
        time.sleep(RETRY_DELAY_SECONDS)
    raise SystemExit("Failed to create task.")


def get_task(task_id):
    while True:
        try:
            response = requests.get(
                f"{BASE_URL}/v1/videos/{task_id}",
                headers=headers,
                timeout=15,
            )
        except requests.RequestException as error:
            print(f"Status request failed: {error}, retrying...")
            time.sleep(RETRY_DELAY_SECONDS)
            continue

        if response.ok:
            return response
        if not is_transient_status(response.status_code):
            response.raise_for_status()
        print(f"Status request returned {response.status_code}, retrying...")
        time.sleep(RETRY_DELAY_SECONDS)


def download_video(content_url, output_path):
    while True:
        try:
            with requests.get(content_url, headers=headers, timeout=120, stream=True) as response:
                if response.ok:
                    with open(output_path, "wb") as output_file:
                        for chunk in response.iter_content(chunk_size=8192):
                            if chunk:
                                output_file.write(chunk)
                    return
                if not is_transient_status(response.status_code):
                    response.raise_for_status()
                print(f"Content request returned {response.status_code}, retrying...")
        except requests.RequestException as error:
            print(f"Content request failed: {error}, retrying...")
        time.sleep(RETRY_DELAY_SECONDS)


create_response = create_task()
create_result = create_response.json()

task_id = create_result.get("id") or create_result.get("task_id")
if not task_id:
    print(json.dumps(create_result, indent=2))
    raise SystemExit("No task id returned.")

print(f"Task created: {task_id}")
print(f"Initial status: {create_result.get('status')}")

while True:
    task_response = get_task(task_id)
    task = task_response.json()
    status = str(task.get("status") or "unknown")
    normalized_status = status.lower()
    progress = task.get("progress")
    should_download = normalized_status in SUCCESS_STATUSES or (
        normalized_status == "unknown" and is_progress_complete(progress)
    )

    print(f"Status: {status}, progress: {progress}")

    if should_download or normalized_status in TERMINAL_STATUSES:
        if not should_download:
            print(json.dumps(task, indent=2))
            raise SystemExit(1)

        content_url = f"{BASE_URL}/v1/videos/{task_id}/content"
        output_path = os.path.join(OUTPUT_DIR, f"{task_id}.mp4")
        os.makedirs(OUTPUT_DIR, exist_ok=True)
        download_video(content_url, output_path)

        print(f"Video URL: {task.get('video_url') or ''}")
        print(f"Content endpoint: {content_url}")
        print(f"Saved to {output_path}")
        print(f"File size: {os.path.getsize(output_path)} bytes")
        break

    time.sleep(POLL_INTERVAL_SECONDS)

JavaScript Code Example

import fs from "fs";
import path from "path";

const model = "happyhorse-1.0";
const prompt = "A miniature city built from cardboard and bottle caps comes alive at night. A tiny cardboard train rolls through the streets while warm lights glow from paper windows, physically realistic motion, detailed tabletop cinematography.";
const seconds = "3";
const size = "1280x720";
const api_key = process.env.COMETAPI_KEY;
const base_url = "https://api.cometapi.com";
const output_dir = "./output";
const poll_interval_ms = 10_000;
const retry_delay_ms = 5_000;
const max_create_attempts = 5;
const terminal_statuses = new Set(["completed", "failed", "error", "success"]);
const success_statuses = new Set(["completed", "success"]);

if (!api_key) {
  console.log("Set COMETAPI_KEY before running this example.");
  process.exit(0);
}

function is_progress_complete(progress) {
  if (typeof progress === "number") {
    return progress >= 100;
  }
  if (typeof progress === "string") {
    const numeric = Number(progress.replace(/%$/, ""));
    return Number.isFinite(numeric) && numeric >= 100;
  }
  return false;
}

function is_transient_status(status) {
  return status === 429 || status >= 500;
}

async function sleep(ms) {
  await new Promise((resolve) => setTimeout(resolve, ms));
}

async function fetch_with_retry(url, options, attempts, label) {
  for (let attempt = 1; attempt <= attempts; attempt += 1) {
    try {
      const response = await fetch(url, options);
      if (response.ok) {
        return response;
      }
      if (!is_transient_status(response.status) || attempt === attempts) {
        return response;
      }
      console.log(`${label} returned ${response.status}, retrying...`);
    } catch (error) {
      if (attempt === attempts) {
        throw error;
      }
      console.log(`${label} failed: ${error.message}, retrying...`);
    }
    await sleep(retry_delay_ms);
  }
  throw new Error(`${label} failed`);
}

async function fetch_status(task_id) {
  while (true) {
    try {
      const response = await fetch(`${base_url}/v1/videos/${task_id}`, { headers });
      if (response.ok) {
        return response;
      }
      if (!is_transient_status(response.status)) {
        return response;
      }
      console.log(`Status request returned ${response.status}, retrying...`);
    } catch (error) {
      console.log(`Status request failed: ${error.message}, retrying...`);
    }
    await sleep(retry_delay_ms);
  }
}

async function download_video(content_url, output_path) {
  while (true) {
    try {
      const response = await fetch(content_url, { headers });
      if (response.ok) {
        const video_buffer = Buffer.from(await response.arrayBuffer());
        fs.writeFileSync(output_path, video_buffer);
        return;
      }
      if (!is_transient_status(response.status)) {
        console.log(await response.text());
        process.exit(1);
      }
      console.log(`Content request returned ${response.status}, retrying...`);
    } catch (error) {
      console.log(`Content request failed: ${error.message}, retrying...`);
    }
    await sleep(retry_delay_ms);
  }
}

const form = new FormData();
form.set("model", model);
form.set("prompt", prompt);
form.set("seconds", seconds);
form.set("size", size);

const headers = { Authorization: `Bearer ${api_key}` };
const create_response = await fetch_with_retry(`${base_url}/v1/videos`, {
  method: "POST",
  headers,
  body: form,
}, max_create_attempts, "Create request");

if (!create_response.ok) {
  console.log(await create_response.text());
  process.exit(1);
}

const create_result = await create_response.json();
const task_id = create_result.id || create_result.task_id;

if (!task_id) {
  console.log(JSON.stringify(create_result, null, 2));
  process.exit(1);
}

console.log(`Task created: ${task_id}`);
console.log(`Initial status: ${create_result.status}`);

while (true) {
  const task_response = await fetch_status(task_id);

  if (!task_response.ok) {
    console.log(await task_response.text());
    process.exit(1);
  }

  const task = await task_response.json();
  const status = String(task.status || "unknown");
  const normalized_status = status.toLowerCase();
  const progress = task.progress;
  const should_download = success_statuses.has(normalized_status) || (
    normalized_status === "unknown" && is_progress_complete(progress)
  );

  console.log(`Status: ${status}, progress: ${progress}`);

  if (should_download || terminal_statuses.has(normalized_status)) {
    if (!should_download) {
      console.log(JSON.stringify(task, null, 2));
      process.exit(1);
    }

    const content_url = `${base_url}/v1/videos/${task_id}/content`;
    const output_path = path.join(output_dir, `${task_id}.mp4`);
    fs.mkdirSync(output_dir, { recursive: true });
    await download_video(content_url, output_path);

    console.log(`Video URL: ${task.video_url || ""}`);
    console.log(`Content endpoint: ${content_url}`);
    console.log(`Saved to ${output_path}`);
    console.log(`File size: ${fs.statSync(output_path).size} bytes`);
    break;
  }

  await sleep(poll_interval_ms);
}

Versioner af Happy Horse 1.0

Årsagen til, at Happy Horse 1.0 har flere øjebliksbilleder kan omfatte potentielle faktorer såsom variationer i output efter opdateringer, der kræver ældre øjebliksbilleder for konsistens, at give udviklere en overgangsperiode til tilpasning og migration, og at forskellige øjebliksbilleder svarer til globale eller regionale slutpunkter for at optimere brugeroplevelsen. For detaljerede forskelle mellem versioner, henvises der til den officielle dokumentation.

Version
happyhorse-1.0