Chat, Image & Video API 对话、图像与视频 API

A guide for furniture-comp — connecting to our hosted chat, image and video models. furniture-comp 使用指南 — 接入我们托管的对话、图像与视频生成模型。

Status: test / evaluation deployment. Hostnames, capacity, and models below may change before this becomes a production offering. All five models are live today. Image editing and both video models were added on 2026-08-28 — if your Service Token predates that, ask your contact to extend it to the new endpoints. 当前状态:测试 / 评估阶段部署。下方的主机名、算力配置与模型在正式上线前可能会调整。五个模型均已 上线。图像编辑与两个视频模型于 2026-08-28 新增 —— 若您的 Service Token 早于该日期签发,请联系对接人为新接口开通权限。

What's available服务内容

Chat — Qwen3.8 27B & Nemotron 3 Ultra 550B 对话模型 — Qwen3.8 27B 与 Nemotron 3 Ultra 550B

Two general-purpose chat models, OpenAI-compatible, 262K token context window. Pick Qwen3.8 for anything involving images. 两款通用大语言对话模型,兼容 OpenAI 接口协议,支持 26.2 万 token 的上下文窗口。涉及图像的场景请选择 Qwen3.8。

text → text
Image generation — Qwen-Image 图像生成 — Qwen-Image

Text-to-image, OpenAI-compatible /v1/images/generations, strong text rendering including Chinese. 文生图模型,兼容 OpenAI 的 /v1/images/generations 接口,文字渲染效果出色,包括中文文字。

text → image
Image editing & composition — Qwen-Image-Edit-2511 图像编辑与合成 — Qwen-Image-Edit-2511

Send your own photos and a description of the change. Place a product into a room photo, swap a finish, or remove a background. Up to 12 input images per request; beyond 4 they are packed into 4. 上传您自己的图片并描述需要的修改。可将产品放入房间照片中、更换材质饰面或移除背景。单次请求最多 12 张输入图片,超过 4 张时会合并为 4 张。

up to 12 images + text → image
Video generation — Wan 2.2 T2V-A14B & Cosmos3-Super 视频生成 — Wan 2.2 T2V-A14B 与 Cosmos3-Super

Short clips from a text prompt. Wan 2.2 for cinematic product and lifestyle shots at 832×480; Cosmos3 for physical and industrial scenes at 1280×720. One API, two hostnames. A 5-second clip takes about two minutes. 根据文字提示生成短片。Wan 2.2 适合影视风格的产品与生活场景,分辨率 832×480;Cosmos3 适合物理与工业场景,分辨率 1280×720。同一套接口,两个主机名。生成一段 5 秒的片段约需两分钟。

text → video

You can use these two ways: through our hosted web chat (no code), or by calling the APIs directly from your own code. Every model is available over the API; the hosted chat covers chat, images and video. 您可以通过两种方式使用:通过我们托管的网页聊天界面(无需编写代码),或直接在您自己的代码中调用 API。所有模型均可通过 API 使用;托管聊天界面支持对话、图像与视频生成。

Option 1 — Hosted Web Chat 方式一 — 托管网页聊天 live已上线

The easiest way to try the models together — ask for an image or a short video in a normal chat, and it is generated and appears inline in the conversation. 最简单的体验方式 — 在正常对话中直接要求生成图像或短视频,系统会自动生成并显示在对话中。

URL:网址: https://chat.tfd-runai.com/

Login:登录: a shared account has been created for your team. Credentials are sent to you separately by your contact — not published on this page. 我们已为您的团队创建了一个共享账号,登录凭证将由您的对接人另行发送 — 不会公开在本页面上。

Model:模型: select Qwen/Qwen3.8-27B from the model picker at the top of the chat. It can generate images and short videos directly in the conversation — just ask, e.g. "Generate an image of a mid-century modern armchair with tapered wooden legs and a teal upholstered seat, on a plain white studio background." A video takes about two minutes, so expect a wait. nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B-NVFP4 is also in the picker and is the stronger writer, but it cannot yet continue a conversation that already contains an image — use it for text-only work. 在聊天界面顶部的模型选择器中选择 Qwen/Qwen3.8-27B。它可以直接在对话中生成图像与短视频 — 只需提出请求即可,例如:"帮我生成一张图片:中世纪现代风格扶手椅,木质锥形椅腿,青蓝色软包座椅,纯白影棚背景。"视频生成约需两分钟,请耐心等待。选择器中同时提供 nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B-NVFP4,其文字表达更强,但目前无法在包含图像的对话中继续回复,建议仅用于纯文字场景。

Option 2 — Direct API Access方式二 — 直接调用 API

Both endpoints speak the OpenAI API shape your existing client code already knows — integration is normally a base URL + auth header change. 两个接口均采用与 OpenAI API 相同的调用格式,与您现有的客户端代码兼容 — 通常只需更改 base URL 和认证请求头即可完成对接。

Authentication身份认证

Every API request needs two headers, from a Cloudflare Access Service Token issued to your team — request it from your contact rather than reusing another team's token. 每次 API 请求都需要携带两个请求头,其值来自 Cloudflare Access 为您的团队签发的 Service Token — 请向您的对接人申请专属令牌,不要复用其他团队的令牌。

CF-Access-Client-Id: <your-client-id>
CF-Access-Client-Secret: <your-client-secret>

Keep the secret out of shell history and process args — don't pass it as a curl -H command-line argument on a shared machine. Use a curl --config file created with umask 077, or your app's environment/secrets manager. 请勿将密钥暴露在 shell 历史记录或进程参数中 — 在共享机器上不要以 curl -H 命令行参数的形式传递密钥。建议使用 umask 077 创建的 curl --config 配置文件,或使用您应用的环境变量 / 密钥管理服务。

Every curl example on this page uses that config file. Create it once: 本页所有 curl 示例均使用该配置文件。只需创建一次:

umask 077
cat > ~/.cf-access-furniture-comp.curl <<'EOF'
header = "CF-Access-Client-Id: <your-client-id>"
header = "CF-Access-Client-Secret: <your-client-secret>"
EOF
chmod 600 ~/.cf-access-furniture-comp.curl

Each endpoint below is a separate Cloudflare Access application. You may be issued a different token per endpoint — if so, keep one config file per endpoint and point --config at the matching one. 下方每个接口都是独立的 Cloudflare Access 应用。您可能会为每个接口获得不同的令牌 — 若是如此,请为每个接口分别保存配置文件,并在 --config 中指向对应文件。

Chat Completions (Nemotron)对话补全接口(Nemotron) live已上线

Your team's Service Token is provisioned — this endpoint is ready to use. 您团队专属的 Service Token 已开通 — 该接口现已可用。

Base URL:基础地址: https://nemotron3-ultra.tfd-runai.com/v1

Model:模型: nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B-NVFP4

from openai import OpenAI

client = OpenAI(
    base_url="https://nemotron3-ultra.tfd-runai.com/v1",
    api_key="unused",  # auth is via the CF-Access-* headers below, not a bearer key
    default_headers={
        "CF-Access-Client-Id": "<your-client-id>",
        "CF-Access-Client-Secret": "<your-client-secret>",
    },
)

result = client.chat.completions.create(
    model="nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B-NVFP4",
    messages=[{"role": "user", "content": "Describe a mid-century modern armchair in one paragraph."}],
)
print(result.choices[0].message.content)

Image Generation (Qwen-Image)图像生成接口(Qwen-Image) live已上线

Your team's Service Token is provisioned — this endpoint is ready to use. 您团队专属的 Service Token 已开通 — 该接口现已可用。

Base URL:基础地址: https://qwen-image.tfd-runai.com

Model:模型: Qwen/Qwen-Image

Request fields请求参数 — POST /v1/images/generations

Field字段 Type类型 Notes说明
promptstring Required. Text description of the desired image.必填。所需图像的文字描述。
ninteger Number of images, 1–10. Default 1.生成图像数量,1–10,默认为 1。
sizestring "WIDTHxHEIGHT", e.g. "1024x1024". Omit for model default. "宽度x高度" 格式,如 "1024x1024",留空则使用模型默认值。
response_formatstring Only "b64_json" or "file" — "url" is not supported. Default "b64_json". 仅支持 "b64_json" 或 "file" — 不支持 "url"。默认值为 "b64_json"。
negative_promptstring Optional — things to avoid in the image.可选 — 指定图像中应避免出现的内容。
prompt_extendboolean Optional, defaults to true on this endpoint (it defaults to false on the image editing endpoint — see that section for why). We rewrite your prompt with a language model before generating, then return the rewritten text as actual_prompt. Send false to generate from your text exactly as written. 可选,在本接口默认为 true(在图像编辑接口则默认为 false,原因见该章节)。我们会先用语言模型改写您的提示词再生成图像,并在回应中以 actual_prompt 返回改写后的文字。若希望完全按原文生成,请传入 false。

About prompt extension关于提示词改写

Long specification-sheet prompts — product codes, centimetre dimensions, compass directions, lists of things to avoid — are hard for an image model to follow, and a phrase such as "no text" can act as a request rather than a prohibition. So before generating we rewrite your prompt into a single visual description: product codes and measurements become plain words, positions become camera-relative, and anything you forbade is simply left out of the description rather than named in it. The rewritten text comes back as actual_prompt in the response (and in the X-Actual-Prompt header), so you can always see exactly what was generated from. If the rewriter is unavailable for any reason, your original prompt is used unchanged — extension never blocks a generation.

A note on negative_prompt, so the response field is not misleading: what does the work here is the rewrite not mentioning the unwanted thing. We also return the list as actual_negative_prompt and pass it along, but paired with true_cfg_scale: 1.0, which leaves the image byte-for-byte identical to sending no negative at all — this model's fast 8-step mode is not trained for guidance. A negative_prompt that you send yourself is passed through untouched and takes effect normally; we then leave true_cfg_scale alone and do not substitute ours.
规格表式的长提示词 — 产品编号、公分尺寸、方位描述、以及一长串「不要出现什么」 — 对图像模型来说很难精确遵循; 而且像「不要文字」这样的句子,往往会被当成「请画上文字」的要求。因此在生成之前,我们会先把您的提示词改写成一段视觉描述: 产品编号与尺寸改成一般用语,位置改用相对于镜头的方位,您禁止出现的内容则「直接不写进描述里」, 而不是留在正面描述中被提及。改写后的文字会在回应中以 actual_prompt 返回(同时也放在 X-Actual-Prompt 回应标头中),因此您随时可以确认实际用来生成的是哪一段文字。 若改写服务暂时不可用,系统会直接使用您的原始提示词 — 改写永远不会阻断图像生成。

关于 negative_prompt 的说明,以免这个回应字段造成误解:真正发挥作用的,是改写时 根本不提那些不想要的东西。我们同时也会把该清单以 actual_negative_prompt 返回并一并送出, 但会搭配 true_cfg_scale: 1.0 — 这会让成像结果与「完全不给 negative」逐字节相同, 因为本模型的 8 步快速模式并未针对 guidance 训练。若是您自己传入的 negative_prompt, 我们会原封不动地转送并正常生效,此时我们不会改动 true_cfg_scale,也不会用我们的版本取代您的。

One trade-off, stated plainly. The rewriter removes quotation marks, because quoted text is what makes this model draw letters into the picture. If you actually want words rendered in the image — a sign, a label, a logo — send "prompt_extend": false for that request. Everything else on this page is unchanged: same URL, same fields, same client code. 有一个取舍,先说清楚。改写会移除引号,因为「加引号的文字」正是让这个模型把字画进画面的原因。 如果您就是希望画面中出现文字 — 招牌、标签、商标 — 请在该次请求中传入 "prompt_extend": false。 除此之外本页所有内容都不变:网址相同、字段相同、客户端代码不需要修改。

Two things prompt extension does not do. It does not remove the small badge in the bottom-right corner — that is the image generator's own built-in signature, present on every frame it produces, and a negative prompt does not touch it. And it does not make every frame publishable: it substantially improves the odds, but the model still occasionally produces furniture with broken geometry — a chair rail ending in mid-air, a cushion passing through an arm. Please look at the image before it reaches your own client, and regenerate with a different seed if it is wrong. That is a property of this class of model, not of our endpoint. 有两件事是提示词改写做不到的。第一,它不会移除右下角的小标记 — 那是图像生成模型本身内建的签章,它产出的每一张图都有,负面提示词也无法去除。 第二,它无法保证每一张图都能直接交件:改写能明显提高成功率,但模型仍有可能画出结构错误的家具 — 例如扶手横杆断在半空、坐垫穿过扶手。请在把图交给您的客户之前先看过,若有问题请换一个 seed 重新生成。这是这类模型的特性,并非本接口的限制。

curl -s https://qwen-image.tfd-runai.com/v1/images/generations \
  --config ~/.cf-access-furniture-comp.curl \
  -H 'Content-Type: application/json' \
  -d '{
        "prompt": "A minimalist wooden dining chair, natural oak finish, plain white studio background",
        "size": "1024x1024",
        "n": 1
      }' | jq -r '.data[0].b64_json' | base64 -d > chair.png
curl -s https://qwen-image.tfd-runai.com/v1/images/generations \
  --config ~/.cf-access-furniture-comp.curl \
  -H 'Content-Type: application/json' \
  -d '{
        "prompt": "极简风格木质餐椅,天然橡木色,纯白影棚背景",
        "size": "1024x1024",
        "n": 1
      }' | jq -r '.data[0].b64_json' | base64 -d > chair.png

Image Editing & Composition (Qwen-Image-Edit)图像编辑与合成接口(Qwen-Image-Edit) live已上线

Send one or more of your own images plus a description of the change. This is the same endpoint for a simple edit ("remove the background") and for compositing several images together — the model is given "Picture 1", "Picture 2" and so on internally, so your prompt can refer to each one. 上传一张或多张您自己的图片,并描述需要的修改。简单编辑(如"移除背景")与多图合成使用的是同一个接口 — 模型内部会将图片依次标记为"图 1""图 2",因此您可以在提示词中分别引用它们。

Base URL:基础地址: https://qwen-image-edit.tfd-runai.com

Model:模型: Qwen/Qwen-Image-Edit-2511

Send ONE photo per product, and choose it carefully. Which photo you send matters more to the result than the prompt, the guidance value or the step count. Send one clean front three-quarter view: the front of the product facing the camera, the whole piece in frame, on a plain background. 每件产品只上传一张照片,并且要慎选。您选择哪一张照片,比提示词、guidance 数值或步数都更能决定成品好坏。请上传一张干净的正面四分之三视角照片:产品正面朝向镜头、整件入镜、背景单纯。

Never send a rear view or a top-down view. Those angles leak into the result instead of adding detail — the model reproduces the pose it was shown, so a sofa photographed from behind comes back facing away from the camera, which is useless as an advertisement. 切勿上传背面或俯视角度的照片。这类角度不会补充细节,反而会「渗入」成品 — 模型会重现它看到的姿态,因此用背面照片生成出来的沙发,成品同样会背对镜头,无法作为广告使用。

More angles do not help. We measured it. On the two real products we measured — five catalogue views each — scored on one question: would you run this image as an advertisement for that product? Four input photos scored 0 of 4 usable; a single photo scored 3 of 4. Four inputs also cost about three times the latency of one (67.9 s against 22.2 s). That is two products, not a survey, but the direction was consistent across both. Send several images only when they are different things — a product plus a room to place it in — and upload them in the order your prompt refers to. 多送几个角度并不会更好,这是实测结果。在我们实测的两件真实产品上(各五张型录照片),以同一个问题评分 — 这张图能不能直接当作该产品的广告?送四张输入照片得到 0/4 可用;只送一张得到 3/4。四张输入的耗时也约为一张的三倍(67.9 秒对 22.2 秒)。这是两件产品的结果,并非大规模统计,但两件的方向一致。只有当图片是「不同的东西」时才上传多张 — 例如一件产品加上一个要放进去的房间 — 并请依照提示词引用的顺序上传。

Expect to pick from candidates, but keep one request under ~100 seconds. The model re-renders your product rather than pasting it in, so results vary from seed to seed — ask for several in one request and choose the best. The wait scales roughly in proportion to the number of candidates, and this hostname is subject to the same ~100 s edge limit as the video endpoints below: a request that takes longer to return fails with a 524 before your image arrives, even though the image itself was generated. Nothing here is guaranteed to fit: a single edit is typically 20-30 s, but we have measured 175 s for one image when the cluster is busy, which would 524 on its own. n=2 usually fits and is the most we would send over this hostname; n=3 (about 77 s with the GPUs to itself) is for callers inside our cluster, which do not pass through the edge. Treat a 524 as "retry", not as a failed prompt — the request was cut off in transit, so the same call may well succeed a moment later. 请预期需要从多张候选图中挑选,但单次请求请控制在约 100 秒以内。模型是「重新绘制」您的产品,而不是把它贴上去,因此不同 seed 的结果会有差异 — 建议在单次请求中取得多张候选图再从中挑选。耗时大致与候选张数成正比;而本主机名与下方的视频接口一样,受到约 100 秒的边缘超时限制:超过这个时间才返回的请求会收到 524 错误,即使图片其实已经生成完成。这里没有任何组合是保证不会超时的:单张编辑通常为 20-30 秒,但在集群繁忙时我们曾实测到单张 175 秒 — 光是这一张就会触发 524。n=2 通常来得及,也是我们建议透过这个主机名发送的上限;n=3(GPU 无竞争时约 77 秒)适用于集群内部的调用端,因为它们不经过边缘节点。收到 524 请视为「重试」,而不是提示词失败 — 该请求只是在传输途中被切断,稍后以相同内容重发往往就会成功。

Images are sent as repeated multipart image fields — this endpoint takes form fields, not JSON. 图片以多个 multipart image 字段重复上传 — 该接口接收表单字段,而非 JSON。

curl -s https://qwen-image-edit.tfd-runai.com/v1/images/edits \
  --config ~/.cf-access-furniture-comp.curl \
  -F "image=@armchair.png" \
  -F "image=@living-room.png" \
  -F 'prompt=Place the armchair from the first image into the room from the second image, near the window, matching the room lighting' \
  -F "n=1" | jq -r '.data[0].b64_json' | base64 -d > composite.png
curl -s https://qwen-image-edit.tfd-runai.com/v1/images/edits \
  --config ~/.cf-access-furniture-comp.curl \
  -F "image=@armchair.png" \
  -F "image=@living-room.png" \
  -F 'prompt=将第一张图中的扶手椅放入第二张图的房间内,靠近窗户,光照与房间保持一致' \
  -F "n=1" | jq -r '.data[0].b64_json' | base64 -d > composite.png

Video Generation (Wan 2.2 / Cosmos3)视频生成接口(Wan 2.2 / Cosmos3) live已上线

Two models, one identical API — pick by hostname. Neither is OpenAI-shaped: requests are multipart form fields, and a finished video comes back as raw video/mp4 bytes, not JSON with a b64_json field. 两个模型使用完全相同的接口 — 通过主机名区分。二者均不遵循 OpenAI 格式:请求采用 multipart 表单字段,生成完成的视频以原始 video/mp4 字节返回,而非包含 b64_json 字段的 JSON。

Host主机名 Model模型 Best for适用场景
wan22-t2v.tfd-runai.com Wan-AI/Wan2.2-T2V-A14B Cinematic product and lifestyle clips. 832×480.影视风格的产品与生活场景短片。832×480。
cosmos3-super.tfd-runai.com nvidia/Cosmos3-Super Physical / industrial scenes, e.g. assembly. 1280×720.物理与工业场景,如装配流程。1280×720。

Use the job API, not /v1/videos/sync. A 5-second clip takes about two minutes, and requests held open longer than ~100 seconds are cut off before the video is ready. The job API below submits, polls, then downloads — every call returns immediately, so nothing is held open. 请使用任务式接口,不要使用 /v1/videos/sync。生成一段 5 秒的视频约需两分钟,而持续保持超过约 100 秒的连接会在视频生成完成前被中断。下方的任务式接口采用提交 → 轮询 → 下载的流程,每次调用都会立即返回,不会长时间占用连接。

Always send seconds. If you leave it out the request still succeeds and returns a valid MP4 that is one frame long. Nothing in the response indicates a problem. 请务必传入 seconds 参数。若省略该参数,请求仍会成功,并返回一个仅有一帧的有效 MP4 文件,且响应中不会有任何异常提示。

Request fields请求参数 — POST /v1/videos

Field字段 Type类型 Notes说明
promptstring Required. Text description of the clip.必填。视频内容的文字描述。
secondsstring Clip length, sent as a string of digits. See the warning above — always send it. 视频长度,以数字字符串形式传入。参见上方提示 — 请务必传入。
sizestring "WIDTHxHEIGHT". Omit for the model's native size. "宽度x高度" 格式,留空则使用模型原生分辨率。
num_inference_stepsinteger Quality vs time. 12 is our tested default; generation time scales roughly linearly with this. 画质与耗时的平衡参数。12 为我们验证过的默认值;生成时间大致与该值成正比。
negative_promptstring Optional — things to avoid in the clip.可选 — 指定视频中应避免出现的内容。
import time, requests

HOST = "https://wan22-t2v.tfd-runai.com"
HEADERS = {
    "CF-Access-Client-Id": "<your-client-id>",
    "CF-Access-Client-Secret": "<your-client-secret>",
}
form = {                                  # multipart form fields, not JSON
    "prompt": (None, "A walnut lounge chair slowly rotating on a plain studio backdrop"),
    "seconds": (None, "5"),               # never omit this
    "size": (None, "832x480"),
    "num_inference_steps": (None, "12"),
}

job = requests.post(f"{HOST}/v1/videos", files=form, headers=HEADERS, timeout=30).json()
vid = job["id"]

while True:                               # each poll returns in well under a second
    st = requests.get(f"{HOST}/v1/videos/{vid}", headers=HEADERS, timeout=30).json()
    if st["status"] == "completed":
        break
    if st["status"] == "failed":
        raise RuntimeError(st.get("error"))
    time.sleep(10)

r = requests.get(f"{HOST}/v1/videos/{vid}/content", headers=HEADERS, timeout=120)
open("chair.mp4", "wb").write(r.content)
import time, requests

HOST = "https://wan22-t2v.tfd-runai.com"
HEADERS = {
    "CF-Access-Client-Id": "<your-client-id>",
    "CF-Access-Client-Secret": "<your-client-secret>",
}
form = {                                  # 使用 multipart 表单字段,而非 JSON
    "prompt": (None, "胡桃木休闲椅在纯色影棚背景前缓慢旋转"),
    "seconds": (None, "5"),               # 请务必传入该参数
    "size": (None, "832x480"),
    "num_inference_steps": (None, "12"),
}

job = requests.post(f"{HOST}/v1/videos", files=form, headers=HEADERS, timeout=30).json()
vid = job["id"]

while True:                               # 每次轮询均在一秒内返回
    st = requests.get(f"{HOST}/v1/videos/{vid}", headers=HEADERS, timeout=30).json()
    if st["status"] == "completed":
        break
    if st["status"] == "failed":
        raise RuntimeError(st.get("error"))
    time.sleep(10)

r = requests.get(f"{HOST}/v1/videos/{vid}/content", headers=HEADERS, timeout=120)
open("chair.mp4", "wb").write(r.content)

status is one of queued, in_progress, completed, failed. The progress field jumps straight from 0 to 100 on completion, so drive any progress display from elapsed time instead. status 的取值为 queued、in_progress、 completed、failed 之一。progress 字段会在完成时直接从 0 跳到 100,因此进度显示请改用已耗时来估算。

Known limits (test deployment)已知限制(测试阶段)