Claude Opus 5 is now live on CometAPI →
Q

Happy Horse 1.0

في الثانية:$0.112
تاريخ الإصدار:May 31, 2026

Happy Horse 1.0 — نموذج توليد سمعي-بصري عالي الجودة يدعم توليد الفيديو من النصوص والصور. يمكنه توليد مرئيات وصوت وحركات شفاه متزامنة، مما يجعله مناسبًا للأفلام القصيرة، والأعمال الإعلانية الإبداعية، وعروض المنتجات.

جديد
الاستخدام التجاري

Playground لـ Happy Horse 1.0

استكشف Playground الخاص بـ Happy Horse 1.0 — بيئة تفاعلية لاختبار النماذج وتشغيل الاستعلامات في الوقت الفعلي. جرب المطالبات، وضبط المعاملات، والتكرار فورًا لتسريع التطوير والتحقق من حالات الاستخدام.

المواصفات التقنية لـ HappyHorse-1.0

البندHappyHorse-1.0
ProviderAlibaba (أُفيد عنها علنًا بعد ظهور أولي مجهول في اختبارات القياس)
Model Typeتوليد فيديو متعدد الوسائط بالذكاء الاصطناعي
Inputsنص، صورة
Outputsفيديو + صوت متزامن
ArchitectureTransformer موحّد بتيار واحد
Parameters~15B
Resolutionتوليد بدقة 1080p أصلية
Generation Modeتوليد مشترك للصوت والفيديو
Denoisingاستدلال مُقطَّر (أُفيد عن ~8 خطوات)
Language Supportمزامنة الشفاه متعددة اللغات (أُفيد عن 7 لغات)

ما هو HappyHorse-1.0

HappyHorse-1.0 هو نموذج متقدم لتوليد الفيديو بالذكاء الاصطناعي، صُمّم لإنتاج الفيديو والصوت المتزامن ضمن خط توليد واحد بدلاً من تجميع عدة نماذج معًا. تشير التقارير العامة إلى أن النموذج ظهر مجهول الهوية في ساحات المقاييس القياسية قبل أن يُربط لاحقًا بجهود الذكاء الاصطناعي لدى Alibaba.

على خلاف أنظمة النص إلى فيديو التقليدية التي تُنتِج المرئيات أولاً ثم تُضيف الصوت لاحقًا، يركز HappyHorse على المزامنة الأصلية بين الحركة والكلام والأجواء والتوقيت.

الميزات الرئيسية لـ HappyHorse-1.0

  • توليد الصوت والفيديو معًا في خطوة واحدة
  • مخرجات بدقة 1080p أصلية بدلاً من الاعتماد الإجباري على الترقية
  • مسارات عمل من نص إلى فيديو ومن صورة إلى فيديو
  • خط توليد سريع قائم على الاستدلال المُقطَّر
  • مزامنة حركة الشفاه متعددة اللغات
  • تركيز على حركة كاميرا سينمائية واستمرارية المشاهد

أداء المقاييس القياسية لـ HappyHorse-1.0

تفيد التقارير العامة عن المقاييس بما يلي:

  • Artificial Analysis Arena:
    • تصنيف Elo للنص إلى فيديو: ~1330+
    • تصنيف Elo للصورة إلى فيديو: ~1390+
  • احتل المرتبة الأولى أو بالقرب منها في لقطات لوحات الصدارة العامة خلال فترات الإطلاق المبكرة.

تفسير المقاييس: هذه نتائج لوحات صدارة قائمة على التفضيلات، ولا ينبغي تفسيرها على أنها تصنيفات جودة عامة صالحة لجميع حالات الإنتاج.

HappyHorse-1.0 مقابل النماذج المماثلة

القدرةHappyHorse-1.0Seedance 2.0Kling 3.0
صوت + فيديو مشتركنعمنعمجزئي
1080p أصليةنعمنعمنعم
اتجاه الإصدار المفتوحمعلنملكيملكي
نص→فيديونعمنعمنعم
صورة→فيديونعمنعمنعم
مزامنة الشفاه متعددة اللغاتأُفيد عن 7متعدد اللغاتمتعدد اللغات

كيف أستخدم HappyHorse-1.0 مع CometAPI؟

  1. احصل على بيانات اعتماد API.
  2. حدّد happyhorse-1.0.
  3. أرسل طلبات التوليد مع الموجّه + خيارات التوليد.
  4. استرجع الوسائط المُولَّدة.

الأسئلة الشائعة

التسعير لـ Happy Horse 1.0

استكشف الأسعار التنافسية لـ Happy Horse 1.0، المصمم ليناسب الميزانيات المختلفة واحتياجات الاستخدام المتنوعة. تضمن خططنا المرنة أن تدفع فقط مقابل ما تستخدمه، مما يجعل من السهل التوسع مع نمو متطلباتك. اكتشف كيف يمكن لـ Happy Horse 1.0 تحسين مشاريعك مع الحفاظ على التكاليف قابلة للإدارة.

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).

نموذج الكود وواجهة برمجة التطبيقات لـ Happy Horse 1.0

احصل على أكواد نماذجية شاملة وموارد API لـ Happy Horse 1.0 لتبسيط عملية التكامل الخاصة بك. توفر وثائقنا التفصيلية إرشادات خطوة بخطوة، مما يساعدك على الاستفادة من الإمكانات الكاملة لـ Happy Horse 1.0 في مشاريعك.

#!/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);
}

إصدارات Happy Horse 1.0

قد تشمل الأسباب وراء احتواء Happy Horse 1.0 على لقطات متعددة عوامل محتملة مثل اختلاف المخرجات بعد التحديثات التي تتطلب اللقطات القديمة لضمان الاتساق، وتوفير فترة انتقالية للمطورين للتكيف والهجرة، وارتباط اللقطات المختلفة بنقاط النهاية العالمية أو الإقليمية لتحسين تجربة المستخدم. للاطلاع على الاختلافات التفصيلية بين الإصدارات، يرجى الرجوع إلى الوثائق الرسمية.

Version
happyhorse-1.0