Tổng quan
Apiframe cung cấp các REST endpoint rõ ràng để điều khiển Midjourney AI từ ứng dụng của bạn. Quy trình chuẩn là: gửi tác vụ (Imagine, Vary, Upscale, Pan, Zoom) → nhận task_id
→ Fetch để lấy trạng thái/kết quả hoặc nhận Webhook nếu đã khai báo. Endpoint Imagine hỗ trợ mode
= fast
hoặc turbo
.
Bạn sẽ học được gì trong bài này?
- Xác thực (Authentication)
- Imagine (tạo ảnh)
- Vary (Strong/Subtle)
- Upscale (Subtle/Creative)
- Pan & Zoom
- Lấy kết quả (Polling vs Webhook)
- Ví dụ workflow đầy đủ bằng JavaScript (axios) và Python (requests)
- Best practices (bảo mật, xử lý lỗi, hiệu năng)
Xác thực (Authentication)
Mọi request cần header Authorization
đặt bằng API key của bạn (không phải dạng Bearer ...
). API key lấy từ Dashboard của Apiframe: https://app.apiframe.ai/dashboard/api-keys
Lưu ý URL nền tảng
- Nhóm endpoint tạo/gia công:
https://api.apiframe.ai/pro/...
- Nhóm endpoint truy vấn (Fetch):
https://api.apiframe.ai/...
JavaScript (axios) – cấu hình chung
import axios from "axios";
const API_KEY = process.env.APIFRAME_API_KEY;
export const mj = axios.create({
baseURL: "https://api.apiframe.ai/pro",
headers: {
"Content-Type": "application/json",
"Authorization": API_KEY, // KHÔNG dùng 'Bearer '
},
});
export const fetcher = axios.create({
baseURL: "https://api.apiframe.ai",
headers: {
"Content-Type": "application/json",
"Authorization": API_KEY,
},
});
Python (requests) – headers chung
import os
import requests
API_KEY = os.environ.get("APIFRAME_API_KEY")
HEADERS = {
"Content-Type": "application/json",
"Authorization": API_KEY, # KHÔNG dùng 'Bearer '
}
Imagine (tạo ảnh)
Tạo 4 ảnh từ một prompt
. Có thể chọn mode
là fast
hoặc turbo
. Với production, khuyến nghị thêm webhook_url
và webhook_secret
để nhận kết quả tự động.
JavaScript (axios)
const { data } = await mj.post("/imagine", {
prompt: "Một quán cà phê tối giản, ánh nắng ban mai, tông ấm, film grain",
mode: "fast", // hoặc "turbo"
webhook_url: "https://example.com/webhooks/apiframe",
webhook_secret: "whsec_123", // sẽ được gửi qua header 'x-webhook-secret'
});
console.log("Task ID:", data.task_id);
Python (requests)
res = requests.post(
"https://api.apiframe.ai/pro/imagine",
headers=HEADERS,
json={
"prompt": "Một quán cà phê tối giản, ánh nắng ban mai, tông ấm, film grain",
"mode": "turbo", # hoặc "fast"
"webhook_url": "https://example.com/webhooks/apiframe",
"webhook_secret": "whsec_123",
},
)
print("Task ID:", res.json().get("task_id"))
Vary (Strong/Subtle)
Tạo 4 biến thể mới dựa trên kết quả trước đó. Truyền parent_task_id
(chính là task_id
của tác vụ nguồn), index
("1"
–"4"
) để chọn ảnh, và type
= strong
hoặc subtle
.
JavaScript
await mj.post("/vary", {
parent_task_id: "29e983ca-7e86-4017-a9e3-ef6fe9cd5f2a",
index: "2",
type: "strong", // hoặc "subtle"
webhook_url: "https://example.com/webhooks/apiframe",
webhook_secret: "whsec_123",
});
Python
requests.post(
"https://api.apiframe.ai/pro/vary",
headers=HEADERS,
json={
"parent_task_id": "29e983ca-7e86-4017-a9e3-ef6fe9cd5f2a",
"index": "2",
"type": "subtle", # hoặc "strong"
"webhook_url": "https://example.com/webhooks/apiframe",
"webhook_secret": "whsec_123",
},
)
Upscale (Subtle/Creative)
Phóng lớn ảnh (thường ~2×). subtle
giữ nguyên tinh thần/chi tiết, creative
có xu hướng thêm chi tiết mới.
JavaScript
await mj.post("/upscale", {
parent_task_id: "29e983ca-7e86-4017-a9e3-ef6fe9cd5f2a",
index: "1",
type: "creative", // hoặc "subtle"
});
Python
requests.post(
"https://api.apiframe.ai/pro/upscale",
headers=HEADERS,
json={
"parent_task_id": "29e983ca-7e86-4017-a9e3-ef6fe9cd5f2a",
"index": "1",
"type": "subtle",
},
)
Pan & Zoom
Pan mở rộng khung theo hướng (thêm nội dung mới) trong khi Zoom “zoom out”/đổi bố cục.
-
Pan:
type
=up
/down
/left
/right
-
Zoom:
-
type
=1.5
hoặc2
tương ứng “zoom out 1.5x/2x” - Bất kỳ giá trị
(1, 2]
là “custom zoom” -
1
= “make square”
-
JavaScript (Pan)
await mj.post("/pan", {
parent_task_id: "29e983ca-7e86-4017-a9e3-ef6fe9cd5f2a",
index: "3",
type: "right",
});
Python (Zoom)
requests.post(
"https://api.apiframe.ai/pro/zoom",
headers=HEADERS,
json={
"parent_task_id": "29e983ca-7e86-4017-a9e3-ef6fe9cd5f2a",
"index": "1",
"type": 1.5,
},
)
Lấy kết quả (Polling vs Webhook)
Polling (truy vấn định kỳ)
Dùng Fetch để lấy trạng thái/kết quả theo task_id
:
-
POST https://api.apiframe.ai/fetch
với payload{ "task_id": "<id>" }
- Có Fetch Many để lấy hàng loạt
task_id
JavaScript – Fetch một lần
import axios from "axios";
const API_KEY = process.env.APIFRAME_API_KEY;
async function fetchOnce(taskId) {
const { data } = await axios.post(
"https://api.apiframe.ai/fetch",
{ task_id: taskId },
{
headers: {
"Content-Type": "application/json",
"Authorization": API_KEY,
},
}
);
return data; // data.status có thể là: pending/processing/finished/failed/...
}
Python – Fetch một lần
import os, requests
API_KEY = os.environ["APIFRAME_API_KEY"]
resp = requests.post(
"https://api.apiframe.ai/fetch",
headers={"Content-Type": "application/json", "Authorization": API_KEY},
json={"task_id": "29e983ca-7e86-4017-a9e3-ef6fe9cd5f2a"},
)
print(resp.json())
Webhook (khuyến nghị cho production)
Khai báo webhook_url
và webhook_secret
ngay trong request Imagine/Vary/… Apiframe sẽ POST cập nhật và kết quả tới URL của bạn, kèm header x-webhook-secret
để bạn xác thực.
Express (Node.js) – xác thực webhook
import express from "express";
const app = express();
app.use(express.json());
app.post("/webhooks/apiframe", (req, res) => {
const provided = req.headers["x-webhook-secret"];
if (provided !== process.env.APIFRAME_WEBHOOK_SECRET) {
return res.status(401).end();
}
// TODO: xử lý req.body (status updates / final result)
res.status(200).end();
});
Ví dụ workflow đầy đủ
JavaScript (axios)
import axios from "axios";
const API_KEY = process.env.APIFRAME_API_KEY;
const mj = axios.create({
baseURL: "https://api.apiframe.ai/pro",
headers: {
"Content-Type": "application/json",
"Authorization": API_KEY,
},
});
const fetcher = axios.create({
baseURL: "https://api.apiframe.ai",
headers: {
"Content-Type": "application/json",
"Authorization": API_KEY,
},
});
async function generateAndUpscale() {
// 1) Imagine (fast)
const imagine = await mj.post("/imagine", {
prompt: "Ảnh sản phẩm tối giản: ly gốm trên nền vải linen, ánh sáng tự nhiên",
mode: "fast",
});
const taskId = imagine.data.task_id;
// 2) Poll tới khi finished hoặc failed
let result;
for (let i = 0; i < 50; i++) {
const { data } = await fetcher.post("/fetch", { task_id: taskId });
if (data?.status === "finished") { result = data; break; }
if (data?.status === "failed") throw new Error("Generation failed");
await new Promise((r) => setTimeout(r, 2000)); // backoff 2s
}
if (!result) throw new Error("Timeout chờ kết quả imagine");
// 3) Upscale (creative) ảnh #1
const up = await mj.post("/upscale", {
parent_task_id: taskId,
index: "1",
type: "creative",
});
const upId = up.data.task_id;
// 4) Poll kết quả upscale
let final;
for (let i = 0; i < 50; i++) {
const { data } = await fetcher.post("/fetch", { task_id: upId });
if (data?.status === "finished") { final = data; break; }
if (data?.status === "failed") throw new Error("Upscale failed");
await new Promise((r) => setTimeout(r, 2000));
}
return final; // chứa URL ảnh cuối cùng
}
generateAndUpscale().then(console.log).catch(console.error);
Python (requests)
import os
import time
import requests
API_KEY = os.environ["APIFRAME_API_KEY"]
HEADERS = {"Content-Type": "application/json", "Authorization": API_KEY}
def post(url, payload):
return requests.post(url, headers=HEADERS, json=payload).json()
# 1) Imagine (turbo)
imagine = post("https://api.apiframe.ai/pro/imagine", {
"prompt": "Ảnh sản phẩm tối giản: ly gốm trên nền vải linen, ánh sáng tự nhiên",
"mode": "turbo"
})
task_id = imagine["task_id"]
# 2) Poll
for _ in range(50):
data = post("https://api.apiframe.ai/fetch", {"task_id": task_id})
if data.get("status") == "finished":
break
if data.get("status") == "failed":
raise RuntimeError("Generation failed")
time.sleep(2)
# 3) Pan sang phải ảnh #2
pan = post("https://api.apiframe.ai/pro/pan", {
"parent_task_id": task_id,
"index": "2",
"type": "right"
})
pan_id = pan["task_id"]
# 4) Poll kết quả pan
for _ in range(50):
out = post("https://api.apiframe.ai/fetch", {"task_id": pan_id})
if out.get("status") == "finished":
print(out)
break
if out.get("status") == "failed":
raise RuntimeError("Pan failed")
time.sleep(2)
Best Practices
-
Bảo mật & API keys
- Không bao giờ để API key ở frontend/mobile; luôn qua backend/proxy.
- Sử dụng biến môi trường, hệ thống secret manager.
- Header đúng định dạng:
Authorization: YOUR_API_KEY
(không dùng Bearer).
-
Webhook tin cậy
- Khai báo
webhook_url
vàwebhook_secret
trong request gốc. - Ở server, bắt buộc kiểm tra header
x-webhook-secret
để xác thực. - Ghi log request và triển khai idempotency (nếu cần).
- Khai báo
-
Xử lý lỗi & backoff
- Theo dõi trạng thái:
pending
,staged
,starting
,processing
,finished
,failed
,retry
/retrying
. - Retry với exponential backoff; dừng đúng lúc khi
failed
. - Đặt timeout tổng cho quy trình đợi (ví dụ 80–120 giây).
- Theo dõi trạng thái:
-
Chọn chế độ
-
turbo
cho yêu cầu độ trễ thấp. -
fast
cho đa số trường hợp tối ưu chi phí.
-
-
Chaining tác vụ
- Với Vary/Upscale/Pan/Zoom: luôn truyền
parent_task_id
(tác vụ nguồn) +index
("1"
–"4"
).
- Với Vary/Upscale/Pan/Zoom: luôn truyền
-
Fetch Many
- Khi chạy nhiều
task_id
, ưu tiên Fetch Many để giảm số lần gọi mạng.
- Khi chạy nhiều
Kết luận
Bạn đã có một hướng dẫn đầy đủ và thực dụng để tích hợp Midjourney qua Apiframe: bắt đầu từ Imagine (fast/turbo), tinh chỉnh bằng Vary / Upscale / Pan / Zoom, rồi thu kết quả với Fetch hoặc Webhook. Hãy chủ động thử nghiệm — so sánh strong vs subtle, creative vs subtle, pan theo nhiều hướng, cũng như tỉ lệ zoom linh hoạt — để xây dựng pipeline tạo ảnh phù hợp nhất cho sản phẩm của bạn.
Top comments (0)