DEV Community

Cover image for Hướng dẫn sử dụng Midjourney API với Apiframe
Lê Minh Paul
Lê Minh Paul

Posted on

Hướng dẫn sử dụng Midjourney API với Apiframe

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_idFetch để 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)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,
  },
});
Enter fullscreen mode Exit fullscreen mode

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 '
}
Enter fullscreen mode Exit fullscreen mode

Imagine (tạo ảnh)

Tạo 4 ảnh từ một prompt. Có thể chọn modefast hoặc turbo. Với production, khuyến nghị thêm webhook_urlwebhook_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);
Enter fullscreen mode Exit fullscreen mode

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"))
Enter fullscreen mode Exit fullscreen mode

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",
});
Enter fullscreen mode Exit fullscreen mode

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",
    },
)
Enter fullscreen mode Exit fullscreen mode

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"
});
Enter fullscreen mode Exit fullscreen mode

Python

requests.post(
    "https://api.apiframe.ai/pro/upscale",
    headers=HEADERS,
    json={
        "parent_task_id": "29e983ca-7e86-4017-a9e3-ef6fe9cd5f2a",
        "index": "1",
        "type": "subtle",
    },
)
Enter fullscreen mode Exit fullscreen mode

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ặc 2 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",
});
Enter fullscreen mode Exit fullscreen mode

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,
    },
)
Enter fullscreen mode Exit fullscreen mode

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>" }
  • 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/...
}
Enter fullscreen mode Exit fullscreen mode

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())
Enter fullscreen mode Exit fullscreen mode

Webhook (khuyến nghị cho production)

Khai báo webhook_urlwebhook_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();
});
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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_urlwebhook_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).
  • 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).
  • 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").
  • Fetch Many

    • Khi chạy nhiều task_id, ưu tiên Fetch Many để giảm số lần gọi mạng.

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)