curl --request POST \
--url https://apis.viggle.ai/v1/images \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: multipart/form-data' \
--form 'prompt=<string>' \
--form model=qwen \
--form aspect_ratio=1:1 \
--form resolution=1K \
--form n=1 \
--form seed=1073741823 \
--form reference_image=@example-file \
--form 'reference_image_url=<string>'import requests
url = "https://apis.viggle.ai/v1/images"
files = { "reference_image": ("example-file", open("example-file", "rb")) }
payload = {
"prompt": "<string>",
"model": "qwen",
"aspect_ratio": "1:1",
"resolution": "1K",
"n": "1",
"seed": "1073741823",
"reference_image_url": "<string>"
}
headers = {"Authorization": "Bearer <token>"}
response = requests.post(url, data=payload, files=files, headers=headers)
print(response.text)const form = new FormData();
form.append('prompt', '<string>');
form.append('model', 'qwen');
form.append('aspect_ratio', '1:1');
form.append('resolution', '1K');
form.append('n', '1');
form.append('seed', '1073741823');
form.append('reference_image', '<string>');
form.append('reference_image_url', '<string>');
const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
options.body = form;
fetch('https://apis.viggle.ai/v1/images', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://apis.viggle.ai/v1/images",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"prompt\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"model\"\r\n\r\nqwen\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"aspect_ratio\"\r\n\r\n1:1\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"resolution\"\r\n\r\n1K\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"n\"\r\n\r\n1\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"seed\"\r\n\r\n1073741823\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"reference_image\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"reference_image_url\"\r\n\r\n<string>\r\n-----011000010111000001101001--",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: multipart/form-data"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://apis.viggle.ai/v1/images"
payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"prompt\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"model\"\r\n\r\nqwen\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"aspect_ratio\"\r\n\r\n1:1\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"resolution\"\r\n\r\n1K\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"n\"\r\n\r\n1\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"seed\"\r\n\r\n1073741823\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"reference_image\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"reference_image_url\"\r\n\r\n<string>\r\n-----011000010111000001101001--")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://apis.viggle.ai/v1/images")
.header("Authorization", "Bearer <token>")
.body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"prompt\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"model\"\r\n\r\nqwen\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"aspect_ratio\"\r\n\r\n1:1\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"resolution\"\r\n\r\n1K\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"n\"\r\n\r\n1\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"seed\"\r\n\r\n1073741823\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"reference_image\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"reference_image_url\"\r\n\r\n<string>\r\n-----011000010111000001101001--")
.asString();require 'uri'
require 'net/http'
url = URI("https://apis.viggle.ai/v1/images")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request.body = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"prompt\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"model\"\r\n\r\nqwen\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"aspect_ratio\"\r\n\r\n1:1\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"resolution\"\r\n\r\n1K\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"n\"\r\n\r\n1\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"seed\"\r\n\r\n1073741823\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"reference_image\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"reference_image_url\"\r\n\r\n<string>\r\n-----011000010111000001101001--"
response = http.request(request)
puts response.read_body{
"id": "<string>",
"status": "queued",
"model": "<string>",
"progress": 50,
"images": [
{
"url": "<string>",
"width": 2,
"height": 2,
"seed": 1
}
],
"created_at": "2023-11-07T05:31:56Z",
"completed_at": "2023-11-07T05:31:56Z",
"error": {
"code": "UNAUTHENTICATED",
"message": "<string>",
"retryable": true,
"request_id": "<string>",
"details": {},
"remediation": {
"action": "<string>",
"retry_after_ms": 1
}
}
}{
"error": {
"code": "UNAUTHENTICATED",
"message": "<string>",
"retryable": true,
"request_id": "<string>",
"details": {},
"remediation": {
"action": "<string>",
"retry_after_ms": 1
}
}
}{
"error": {
"code": "UNAUTHENTICATED",
"message": "<string>",
"retryable": true,
"request_id": "<string>",
"details": {},
"remediation": {
"action": "<string>",
"retry_after_ms": 1
}
}
}{
"error": {
"code": "UNAUTHENTICATED",
"message": "<string>",
"retryable": true,
"request_id": "<string>",
"details": {},
"remediation": {
"action": "<string>",
"retry_after_ms": 1
}
}
}{
"error": {
"code": "UNAUTHENTICATED",
"message": "<string>",
"retryable": true,
"request_id": "<string>",
"details": {},
"remediation": {
"action": "<string>",
"retry_after_ms": 1
}
}
}{
"error": {
"code": "UNAUTHENTICATED",
"message": "<string>",
"retryable": true,
"request_id": "<string>",
"details": {},
"remediation": {
"action": "<string>",
"retry_after_ms": 1
}
}
}{
"error": {
"code": "UNAUTHENTICATED",
"message": "<string>",
"retryable": true,
"request_id": "<string>",
"details": {},
"remediation": {
"action": "<string>",
"retry_after_ms": 1
}
}
}{
"error": {
"code": "UNAUTHENTICATED",
"message": "<string>",
"retryable": true,
"request_id": "<string>",
"details": {},
"remediation": {
"action": "<string>",
"retry_after_ms": 1
}
}
}生成图片
用文字描述生成 1–6 张 PNG,可选最多 8 张参考图。
curl --request POST \
--url https://apis.viggle.ai/v1/images \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: multipart/form-data' \
--form 'prompt=<string>' \
--form model=qwen \
--form aspect_ratio=1:1 \
--form resolution=1K \
--form n=1 \
--form seed=1073741823 \
--form reference_image=@example-file \
--form 'reference_image_url=<string>'import requests
url = "https://apis.viggle.ai/v1/images"
files = { "reference_image": ("example-file", open("example-file", "rb")) }
payload = {
"prompt": "<string>",
"model": "qwen",
"aspect_ratio": "1:1",
"resolution": "1K",
"n": "1",
"seed": "1073741823",
"reference_image_url": "<string>"
}
headers = {"Authorization": "Bearer <token>"}
response = requests.post(url, data=payload, files=files, headers=headers)
print(response.text)const form = new FormData();
form.append('prompt', '<string>');
form.append('model', 'qwen');
form.append('aspect_ratio', '1:1');
form.append('resolution', '1K');
form.append('n', '1');
form.append('seed', '1073741823');
form.append('reference_image', '<string>');
form.append('reference_image_url', '<string>');
const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
options.body = form;
fetch('https://apis.viggle.ai/v1/images', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://apis.viggle.ai/v1/images",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"prompt\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"model\"\r\n\r\nqwen\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"aspect_ratio\"\r\n\r\n1:1\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"resolution\"\r\n\r\n1K\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"n\"\r\n\r\n1\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"seed\"\r\n\r\n1073741823\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"reference_image\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"reference_image_url\"\r\n\r\n<string>\r\n-----011000010111000001101001--",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: multipart/form-data"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://apis.viggle.ai/v1/images"
payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"prompt\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"model\"\r\n\r\nqwen\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"aspect_ratio\"\r\n\r\n1:1\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"resolution\"\r\n\r\n1K\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"n\"\r\n\r\n1\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"seed\"\r\n\r\n1073741823\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"reference_image\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"reference_image_url\"\r\n\r\n<string>\r\n-----011000010111000001101001--")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://apis.viggle.ai/v1/images")
.header("Authorization", "Bearer <token>")
.body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"prompt\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"model\"\r\n\r\nqwen\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"aspect_ratio\"\r\n\r\n1:1\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"resolution\"\r\n\r\n1K\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"n\"\r\n\r\n1\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"seed\"\r\n\r\n1073741823\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"reference_image\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"reference_image_url\"\r\n\r\n<string>\r\n-----011000010111000001101001--")
.asString();require 'uri'
require 'net/http'
url = URI("https://apis.viggle.ai/v1/images")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request.body = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"prompt\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"model\"\r\n\r\nqwen\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"aspect_ratio\"\r\n\r\n1:1\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"resolution\"\r\n\r\n1K\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"n\"\r\n\r\n1\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"seed\"\r\n\r\n1073741823\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"reference_image\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"reference_image_url\"\r\n\r\n<string>\r\n-----011000010111000001101001--"
response = http.request(request)
puts response.read_body{
"id": "<string>",
"status": "queued",
"model": "<string>",
"progress": 50,
"images": [
{
"url": "<string>",
"width": 2,
"height": 2,
"seed": 1
}
],
"created_at": "2023-11-07T05:31:56Z",
"completed_at": "2023-11-07T05:31:56Z",
"error": {
"code": "UNAUTHENTICATED",
"message": "<string>",
"retryable": true,
"request_id": "<string>",
"details": {},
"remediation": {
"action": "<string>",
"retry_after_ms": 1
}
}
}{
"error": {
"code": "UNAUTHENTICATED",
"message": "<string>",
"retryable": true,
"request_id": "<string>",
"details": {},
"remediation": {
"action": "<string>",
"retry_after_ms": 1
}
}
}{
"error": {
"code": "UNAUTHENTICATED",
"message": "<string>",
"retryable": true,
"request_id": "<string>",
"details": {},
"remediation": {
"action": "<string>",
"retry_after_ms": 1
}
}
}{
"error": {
"code": "UNAUTHENTICATED",
"message": "<string>",
"retryable": true,
"request_id": "<string>",
"details": {},
"remediation": {
"action": "<string>",
"retry_after_ms": 1
}
}
}{
"error": {
"code": "UNAUTHENTICATED",
"message": "<string>",
"retryable": true,
"request_id": "<string>",
"details": {},
"remediation": {
"action": "<string>",
"retry_after_ms": 1
}
}
}{
"error": {
"code": "UNAUTHENTICATED",
"message": "<string>",
"retryable": true,
"request_id": "<string>",
"details": {},
"remediation": {
"action": "<string>",
"retry_after_ms": 1
}
}
}{
"error": {
"code": "UNAUTHENTICATED",
"message": "<string>",
"retryable": true,
"request_id": "<string>",
"details": {},
"remediation": {
"action": "<string>",
"retry_after_ms": 1
}
}
}{
"error": {
"code": "UNAUTHENTICATED",
"message": "<string>",
"retryable": true,
"request_id": "<string>",
"details": {},
"remediation": {
"action": "<string>",
"retry_after_ms": 1
}
}
}multipart/form-data 提交 prompt,可附带参考图。接口是异步的:立即返回 queued 状态、ID 以 img_ 开头的 Image 对象,之后用查询图片轮询,直到 status 为 ready 或 failed。不带参考图时为文生图,带至少一张参考图时由参考图引导生成。
1K 每张 1 积分($0.01),2K 每张 2 积分($0.02)。一个任务共 n × 单价,例如 2K、n=3 为 6 积分。创建时一次性预扣,任务失败全额退回。aspect_ratio、seed 和参考图不影响价格。详见计费与保留期限。请求参数
使用multipart/form-data。
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
prompt | string | 是 | — | 描述文字,最多 4000 个字符(按 Unicode 字符计,中文一字算一个),不能全是空白。 |
model | string | 否 | qwen | 目前只支持 qwen。 |
aspect_ratio | string | 否 | 1:1 | 1:1、16:9、9:16、4:3、3:4、3:2、2:3。与 resolution 一起决定输出尺寸,见输出尺寸。 |
resolution | string | 否 | 1K | 1K 或 2K,不区分大小写。决定输出尺寸档位和单价:1K 每张 1 积分,2K 每张 2 积分。 |
n | integer | 否 | 1 | 生成张数,1–6。 |
seed | integer | 否 | 随机 | 0–2147483647。第 i 张(从 0 计)使用 (seed + i) mod 2147483648;不传则服务端随机选择。每张图都会返回实际使用的 seed。 |
reference_image | file,可重复 | 否 | — | 参考图上传,单张不超过 24 MiB。重复该字段可上传多张。 |
reference_image_url | string,可重复 | 否 | — | 可公开访问的 http(s) 图片地址,限制同上。重复该字段可传多个。 |
2K 就会变成较小的一档,见下一节。
参考图限制
- 单张不超过 24 MiB,长边与短边之比不超过 8。
- 支持 JPEG、PNG、WebP、GIF、BMP、TIFF、HEIC。
- 长边 ≥ 3840 或短边 ≥ 2160 的图会先等比缩小到 1920 × 1080 以内(竖图为 1080 × 1920)。
reference_image_url必须可公开访问,在创建请求处理期间下载。
输出尺寸
输出尺寸由aspect_ratio 和 resolution 唯一确定,都是模型的固定尺寸档,请求什么就得到什么。单位:像素(宽 × 高)。
aspect_ratio | 1K | 2K(文生图) | 2K(带参考图) |
|---|---|---|---|
1:1 | 1024 × 1024 | 2048 × 2048 | 1536 × 1536 |
16:9 | 1376 × 768 | 2720 × 1536 | 2048 × 1152 |
9:16 | 768 × 1376 | 1536 × 2720 | 1152 × 2048 |
4:3 | 1184 × 896 | 2368 × 1760 | 1760 × 1344 |
3:4 | 896 × 1184 | 1760 × 2368 | 1344 × 1760 |
3:2 | 1248 × 832 | 2496 × 1664 | 1888 × 1248 |
2:3 | 832 × 1248 | 1664 × 2496 | 1248 × 1888 |
1K 与文生图相同;2K 文生图约为 2048² 像素面积,带参考图约为 1536²,价格不变。响应里每张图的 width / height 就是实际尺寸。
响应参数
返回200 OK 和 queued 状态的 Image 对象,结构与查询图片相同。此时 progress 为 0,images 为空,completed_at 和 error 为 null。
{
"id": "img_b16a190d-2d44-41a0-8056-ef68183c3b9e",
"status": "queued",
"model": "qwen",
"progress": 0,
"images": [],
"created_at": "2026-10-12T08:20:00Z",
"completed_at": null,
"error": null
}
常见错误
| 错误 | 原因 |
|---|---|
400 INVALID_REQUEST | 参数不合法(message 说明是哪一项),或请求体不是 multipart/form-data。此时不会创建任务,也不会上传任何文件。 |
401 UNAUTHENTICATED | 缺少或无效的 API 密钥。 |
402 INSUFFICIENT_CREDITS | 余额不足以支付 n × 单价,message 给出所需积分。任务不会开始生成。 |
429 RATE_LIMITED | 同一密钥并发创建过多,稍后重试。 |
500 INTERNAL_ERROR | 服务端内部错误,可重试。 |
503 SERVICE_BUSY | 服务暂时不可用,可重试。 |
{"error": {"code", "message", "retryable", "request_id", "details", "remediation"}},详见错误与恢复。任务受理后再失败时,失败原因在 Image 对象的 error 字段中,见查询图片。
User-Agent。实测 Python urllib 的默认 User-Agent 会被 apis.viggle.ai 前端拦截,返回非 JSON 的错误页。即使不带参考图,请求体也必须是 multipart/form-data,application/x-www-form-urlencoded 会返回 400。使用 Python requests 时,请像下方示例一样通过 files= 传字段,不要只用 data=。示例
curl -X POST https://apis.viggle.ai/v1/images \
-H "Authorization: Bearer $VIGGLE_API_KEY" \
-F prompt="A watercolor fox reading a book under a maple tree" \
-F aspect_ratio=16:9 \
-F resolution=1K \
-F n=2
import os, requests
fields = {"prompt": "A watercolor fox reading a book under a maple tree", "aspect_ratio": "16:9", "resolution": "1K", "n": "2"}
response = requests.post(
"https://apis.viggle.ai/v1/images",
headers={"Authorization": f"Bearer {os.environ['VIGGLE_API_KEY']}"},
files={name: (None, value) for name, value in fields.items()}, # 强制使用 multipart/form-data
)
response.raise_for_status()
image = response.json()
const form = new FormData();
form.append("prompt", "A watercolor fox reading a book under a maple tree");
form.append("aspect_ratio", "16:9");
form.append("resolution", "1K");
form.append("n", "2");
const response = await fetch("https://apis.viggle.ai/v1/images", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.VIGGLE_API_KEY}` },
body: form,
});
const image = await response.json();
body := &bytes.Buffer{}; w := multipart.NewWriter(body)
w.WriteField("prompt", "A watercolor fox reading a book under a maple tree"); w.WriteField("aspect_ratio", "16:9"); w.WriteField("resolution", "1K"); w.WriteField("n", "2"); w.Close()
req, _ := http.NewRequest("POST", "https://apis.viggle.ai/v1/images", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("VIGGLE_API_KEY")); req.Header.Set("Content-Type", w.FormDataContentType())
resp, err := http.DefaultClient.Do(req); if err != nil { panic(err) }; defer resp.Body.Close()
带参考图
上传文件和给 URL 可以混用,两个字段都可以重复:curl -X POST https://apis.viggle.ai/v1/images \
-H "Authorization: Bearer $VIGGLE_API_KEY" \
-F prompt="The same fox, now in winter, snow falling" \
-F aspect_ratio=1:1 \
-F resolution=2K \
-F [email protected] \
-F reference_image_url=https://example.com/style.jpg
import os, requests
with open("fox.png", "rb") as fox:
response = requests.post(
"https://apis.viggle.ai/v1/images",
headers={"Authorization": f"Bearer {os.environ['VIGGLE_API_KEY']}"},
data={
"prompt": "The same fox, now in winter, snow falling",
"aspect_ratio": "1:1",
"resolution": "2K",
"reference_image_url": ["https://example.com/style.jpg"],
},
files=[("reference_image", ("fox.png", fox, "image/png"))],
)
response.raise_for_status()
image = response.json()
import { openAsBlob } from "node:fs";
const form = new FormData();
form.append("prompt", "The same fox, now in winter, snow falling");
form.append("aspect_ratio", "1:1");
form.append("resolution", "2K");
form.append("reference_image", await openAsBlob("fox.png"), "fox.png");
form.append("reference_image_url", "https://example.com/style.jpg");
const response = await fetch("https://apis.viggle.ai/v1/images", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.VIGGLE_API_KEY}` },
body: form,
});
const image = await response.json();
@viggle/sdk
需使用包含 images 资源的 @viggle/sdk 版本。
import { Viggle } from "@viggle/sdk";
const viggle = new Viggle({ apiKey: process.env.VIGGLE_API_KEY! });
const image = await viggle.images.create({
prompt: "A watercolor fox reading a book under a maple tree",
aspectRatio: "16:9",
resolution: "1K",
n: 2,
});
// image.id、image.status("queued");之后用 viggle.images.get(image.id) 轮询
下一步
使用返回的id 调用查询图片轮询结果。
快速入门:Viggle Image
查询图片
授权
服务端 SDK 使用项目 API 密钥,Remote MCP 使用 OAuth 访问令牌。不要在浏览器代码中暴露项目密钥。
请求头
可选的调用者自定义关联 ID,最长 128 字符。服务会在响应头返回实际使用的值,便于追踪和支持排查。
1 - 128可选来源标签,最长 128 字符,用于识别 SDK、集成、产品入口或内部工作流。
1 - 128请求体
POST /v1/images 的请求体,仅支持 multipart/form-data。不带参考图时为文生图,带至少一张参考图时为参考图生成。aspect_ratio 与 resolution 共同选定模型的一个固定输出尺寸(宽 × 高,单位像素);带参考图时,2K 会变成较小的一档:
| aspect_ratio | 1K | 2K(文生图) | 2K(带参考图) |
|---|---|---|---|
| 1:1 | 1024×1024 | 2048×2048 | 1536×1536 |
| 16:9 | 1376×768 | 2720×1536 | 2048×1152 |
| 9:16 | 768×1376 | 1536×2720 | 1152×2048 |
| 4:3 | 1184×896 | 2368×1760 | 1760×1344 |
| 3:4 | 896×1184 | 1760×2368 | 1344×1760 |
| 3:2 | 1248×832 | 2496×1664 | 1888×1248 |
| 2:3 | 832×1248 | 1664×2496 | 1248×1888 |
reference_image 上传与 reference_image_url 地址可任意混用,合计最多 8 张。模型先收到上传的文件,再收到 URL,各自保持发送顺序。
描述文字,最多 4000 个字符(按 Unicode 字符计,中文一字算一个),不能全是空白。
1 - 4000图片模型,目前只支持 qwen。
qwen 输出宽高比,与 resolution 一起决定输出尺寸。
1:1, 16:9, 9:16, 4:3, 3:4, 3:2, 2:3 输出尺寸档位,不区分大小写;同时决定单价,1K 每张 1 积分,2K 每张 2 积分。带参考图时 2K 约为 1536² 像素面积,文生图约为 2048²。
1K, 2K 生成张数。任务预扣 n × 单价。
1 <= x <= 6第 i 张(从 0 计)使用 (seed + i) mod 2147483648。不传则服务端随机选择,每张图都会返回实际使用的 seed。
0 <= x <= 2147483647参考图上传,可重复该字段。单张不超过 24 MiB,长边与短边之比不超过 8;支持 JPEG、PNG、WebP、GIF、BMP、TIFF、HEIC。与 reference_image_url 合计最多 8 张。
8可公开访问的 http(s) 参考图地址,在创建请求处理期间下载,可重复该字段。限制与 reference_image 相同,并计入同一个 8 张上限。
8响应
图片生成任务已受理并进入排队。
图片生成任务(img_ 前缀),创建接口与查询接口返回同一结构。状态只会向前推进:queued → processing → ready 或 failed,不会出现 cancelled。ready 前 images 始终为空,ready 后按请求顺序列出全部 n 张。一个任务要么 n 张全部生成,要么整体失败,不会只返回部分图片。
图片任务公开 ID,以 img_ 开头。
1任务状态,ready 和 failed 为终态。
queued, processing, ready, failed 使用的模型,目前为 qwen。
已完成张数占比:queued 为 0,processing 为 0–99,ready 为 100,failed 为 null。
0 <= x <= 100ready 前为空;ready 后按请求顺序列出全部 n 张。
Show child attributes
Show child attributes
创建时间,RFC 3339。
结束时间,ready 或 failed 时有值,之前为 null。
失败原因,只在 status 为 failed 时有值。code 为 SERVICE_BUSY(可重试:生成服务繁忙或暂时不可用,或任务 15 分钟内未完成)、TASK_FAILED(可重试:其他生成或上传失败)或 INVALID_REQUEST(不可重试:模型拒绝了请求,例如参考图无法使用)。
Show child attributes
Show child attributes

