跳转至正文
Interactions API
通过 Interactions API 接入视频模型
视频示例
本示例为所选模型 inferway/minimax-h3-768p 的 Interactions API 流程:后台创建、轮询、下载。
前置条件:bash、curl、jq;Python 示例仅需标准库;TypeScript 示例需要带 fetch 的 Node。设置 INFERWAY_API_KEY 环境变量;可选地用 INFERWAY_IDEMPOTENCY_KEY 恢复之前的创建。
- 创建:向 /interactions 发送顶层 JSON 体(op=create,mode=background,duration_seconds 与 prompt),并带上持久的 Idempotency-Key。
- 轮询:用 op=get 与返回的 interaction_id 有界地轮询;failed/cancelled/expired/recovery_required 是终止错误。
- 下载:成功且 result.download_url 非空后,用一次不带 API 头部的独立 HTTPS 请求下载,不跟随重定向。
轮询达到上限时任务可能仍在运行:保留 interaction ID 与 Idempotency-Key 稍后恢复;下载 URL 过期后再次调用 get 获取新的 URL。
隐私层级:retained_7d。视频产物按所选模型的策略保存,并非聊天那样的零保留。
#!/usr/bin/env bash
# Inferway video generation via the Interactions API.
# Prerequisites: bash, curl, jq.
# Required env: INFERWAY_API_KEY.
# Optional env: INFERWAY_IDEMPOTENCY_KEY — resume a previous create with this
# key; otherwise a fresh key is generated.
# On success the video is saved to ./inferway-video.mp4.
set -u
API_BASE="https://api.inferway.ai/v1"
MODEL="inferway/minimax-h3-768p"
PROMPT="A drone shot along a coastline at dawn."
DURATION_SECONDS=5
SAVE_PATH=inferway-video.mp4
workdir=$(mktemp -d) || exit 1
cleanup() { rm -rf "$workdir"; }
trap cleanup EXIT HUP INT TERM
if [ -z "${INFERWAY_API_KEY:-}" ]; then
echo "error: INFERWAY_API_KEY is required" >&2
exit 1
fi
idempotency_key="${INFERWAY_IDEMPOTENCY_KEY:-}"
if [ -z "$idempotency_key" ]; then
if command -v uuidgen >/dev/null 2>&1; then
idempotency_key=$(uuidgen | tr 'A-Z' 'a-z') || exit 1
elif command -v uuid >/dev/null 2>&1; then
idempotency_key=$(uuid | tr -d '-') || exit 1
else
idempotency_key="iv-$(date +%s%N)-$$"
fi
fi
echo "Idempotency-Key: $idempotency_key"
interactions_url="$API_BASE/interactions"
response_headers=$workdir/headers
response_body=$workdir/body
create_body_file=$workdir/create-body.json
jq -cn \
--arg model "$MODEL" \
--argjson durationSeconds "$DURATION_SECONDS" \
--arg prompt "$PROMPT" \
'{op: "create", model: $model, mode: "background", duration_seconds: $durationSeconds, prompt: $prompt}' \
> "$create_body_file" || exit 1
attempt=0
while :; do
attempt=$((attempt + 1))
rc=0
curl -sS --connect-timeout 30 --max-time 30 \
-D "$response_headers" \
--data-binary @"$create_body_file" \
-H "Authorization: Bearer $INFERWAY_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $idempotency_key" \
"$interactions_url" > "$response_body" 2> "$workdir/curl-err" || rc=$?
if [ "$rc" -ne 0 ]; then
if [ "$attempt" -ge 5 ]; then
echo "error: create request failed on the 5th attempt: $(cat "$workdir/curl-err")" >&2
exit 1
fi
sleep $((1 << (attempt - 1)))
continue
fi
status=$(head -n 1 "$response_headers" | tr -d '\r' | awk '{print $2}')
case "$status" in
200|202)
id=$(jq -er '.id | select(type == "string" and length > 0)' "$response_body" 2>/dev/null) || {
echo "error: accepted response has no usable id" >&2
exit 1
}
echo "task id: $id"
break
;;
429|5[0-9][0-9])
if jq -e '((.error? // {}) | (type == "object") and .retryable == false) or (.retryable? == false)' "$response_body" >/dev/null 2>&1; then
echo "error: server reported a non-retryable failure (status $status)" >&2
jq -c . "$response_body" >&2 || true
exit 1
fi
if [ "$attempt" -ge 5 ]; then
echo "error: create request failed with status $status on the 5th attempt" >&2
exit 1
fi
retry_after=$(sed -n '1,/^$/s/^Retry-After:[[:space:]]*//Ip' "$response_headers" | head -n 1 | tr -d '\r' | tr -d '[:space:]')
if printf '%s' "${retry_after:-}" | grep -Eq '^[0-9]+$'; then
if [ "$retry_after" -gt 30 ]; then
echo "error: server asked to wait $retry_after s (ceiling 30 s); resume later with:" >&2
echo " INFERWAY_IDEMPOTENCY_KEY=$idempotency_key" >&2
exit 1
else
sleep "$retry_after"
fi
else
sleep $((1 << (attempt - 1)))
fi
continue
;;
*)
if jq -e '((.error? // {}) | (type == "object") and .retryable == false) or (.retryable? == false)' "$response_body" >/dev/null 2>&1; then
echo "error: server reported a non-retryable failure (status $status)" >&2
else
echo "error: create request failed with status $status" >&2
fi
jq -c . "$response_body" >&2 || true
exit 1
;;
esac
done
# --- Poll at most 30 times, 5 s apart, 30 s per request ---------------------
download_url=""
poll=0
while [ "$poll" -lt 30 ]; do
poll=$((poll + 1))
: > "$response_headers"
rc=0
curl -sS --connect-timeout 30 --max-time 30 \
-D "$response_headers" \
--data-binary "$(jq -cn --arg id "$id" '{op: "get", interaction_id: $id}')" \
-H "Authorization: Bearer $INFERWAY_API_KEY" \
-H "Content-Type: application/json" \
"$interactions_url" > "$response_body" 2> "$workdir/curl-err" || rc=$?
status=$(head -n 1 "$response_headers" | tr -d '\r' | awk '{print $2}')
if [ "$rc" -ne 0 ] || [[ ! "$status" =~ ^2[0-9][0-9]$ ]] || ! jq -e . "$response_body" >/dev/null 2>&1; then
echo "polling stopped (status=${status:-n/a}); the job may still be running." >&2
echo "resume later with:" >&2
echo " task id: $id" >&2
echo " INFERWAY_IDEMPOTENCY_KEY=$idempotency_key" >&2
exit 1
fi
state=$(jq -r '.state // empty' "$response_body")
case "$state" in
failed|cancelled|expired|recovery_required)
echo "error: task $id ended in state '$state'" >&2
exit 1
;;
succeeded)
candidate=$(jq -er '.result? | select(type == "object") | .download_url? | select(type == "string" and length > 0)' "$response_body" 2>/dev/null) || candidate=""
if [ -n "$candidate" ]; then
download_url="$candidate"
break
fi
;;
esac
if [ "$poll" -lt 30 ]; then
sleep 5
fi
done
if [ -z "$download_url" ]; then
echo "wait limit reached (30 polls); the job may still be running." >&2
echo "resume later with:" >&2
echo " task id: $id" >&2
echo " INFERWAY_IDEMPOTENCY_KEY=$idempotency_key" >&2
exit 1
fi
case "$download_url" in
https://*) ;;
*)
echo "error: refusing to download a non-HTTPS URL" >&2
exit 1
;;
esac
# --- Download: separate request, no API headers, no redirects ---------------
rc=0
curl -sS --connect-timeout 30 --max-time 30 \
-D "$response_headers" -o "$workdir/video" \
"$download_url" || rc=$?
if [ "$rc" -ne 0 ]; then
echo "error: download failed (network/timeout)" >&2
exit 1
fi
status=$(head -n 1 "$response_headers" | tr -d '\r' | awk '{print $2}')
case "$status" in
2??) ;;
3??)
echo "error: download redirected (status $status); refusing to follow redirects" >&2
exit 1
;;
*)
echo "error: download failed with status $status" >&2
exit 1
;;
esac
mv "$workdir/video" "$SAVE_PATH" || exit 1
echo "SAVED $SAVE_PATH"