← Blog

Panduan Lengkap Z-Image-Base API: Aplikasi Praktis CFG + Negative Prompt

Tutorial Lengkap Z-Image-Base API: Penyetelan Parameter CFG, Penggunaan negative_prompt, Panduan Gambar Referensi, Kontrol Kekuatan. Dilengkapi contoh kode Python/cURL.

By Dora 9 min read
Panduan Lengkap Z-Image-Base API: Aplikasi Praktis CFG + Negative Prompt

Halo, saya Dora. Sungguh mengejutkan bahwa sebuah gangguan kecil mendorong saya untuk mencoba Z-Image-Base API. Saya punya sekumpulan gambar referensi, beberapa teks yang membutuhkan tampilan konsisten, dan tidak cukup waktu untuk terus-menerus mengawasi prompt. Saya terus melihat orang-orang mengubah pengaturan secara manual dan memposting hasil satu kali yang bagus. Itu mungkin cukup untuk demo. Pekerjaan saya membutuhkan sesuatu yang bisa saya jalankan dua kali seminggu tanpa kejutan. Jadi, selama beberapa sesi pada Januari–Februari 2026, saya menyambungkan Z-Image-Base, memperhatikan di mana ia memberikan hambatan, dan mencatat apa yang benar-benar membuatnya terasa andal.

Ini bukan tur setiap parameter. Ini adalah bagian-bagian yang terus saya sentuh, ditambah penyesuaian kecil yang mengurangi beban mental. Jika Anda dikelilingi oleh alat AI dan hanya ingin satu yang berperilaku konsisten, tulisan ini mungkin bermanfaat.

Konfigurasi Dasar API

Mendapatkan API Key WaveSpeed

Saya mendaftar dan mengambil API key dari dasbor WaveSpeed. Tidak ada yang mengejutkan di sana. Satu catatan kecil: izin kunci dibatasi berdasarkan proyek. Berguna dalam alur kerja bersama, tetapi artinya Anda perlu memberi nama proyek dengan jelas sejak awal. Saya membuat proyek khusus untuk eksperimen gambar agar log dan kuota tidak bercampur dengan produksi.

Jika Anda merotasi kunci (saya melakukannya, setiap bulan), Z-Image-Base menanganinya dengan bersih. Saya menukar rahasia di variabel lingkungan, menjalankan skrip lagi, dan tidak melihat sisa state autentikasi. Begitulah seharusnya, tetapi saya masih merasa sedikit lega ketika berhasil pada percobaan pertama.

Struktur URL Endpoint

Basisnya terlihat seperti pengaturan REST standar dengan pemilih model:

  • Basis: https://api.wavespeed.ai
  • Path berversi: /v1/images
  • Pemilih model: model: "Z-Image-Base"

Dalam praktiknya, saya mengirim permintaan POST ke /v1/images/generations untuk proses berbasis prompt saja, dan /v1/images/edits ketika saya menyertakan gambar referensi. Saya lebih suka path yang jelas daripada query string yang padat, dan ini sesuai dengan cara berpikir saya. Jika perutean Anda berbeda, nama model tetap penting: Z-Image-Base tampak sedikit lebih konservatif dibanding model-model yang lebih flamboyan, dan itu saya sukai.

Pengaturan Header Autentikasi

Tidak ada yang rumit di sini, tetapi ejaan yang tepat sangat penting:

  • Authorization: Bearer YOUR_WAVESPEED_API_KEY
  • Content-Type: application/json untuk prompt saja
  • Content-Type: multipart/form-data saat mengunggah gambar

Saya menyimpan kunci di .env dan memuatnya saat runtime. Memang membosankan, tapi ini mencegah commit yang tidak disengaja. Juga: jika Anda membuat skrip dari CI, tetapkan kunci sebagai rahasia yang disembunyikan dan hindari mencatat permintaan secara penuh. Sudah jelas, tapi layak disebutkan. Satu baris log yang tersesat bisa menghantui Anda. Satu baris log yang tersesat bisa menghantui Anda. Menurut praktik keamanan terbaik WaveSpeed, kunci API harus disimpan di variabel lingkungan, tidak pernah diekspos di kode frontend, dan dirotasi secara rutin.

Penjelasan Detail Parameter Inti

prompt - Metode Penulisan Prompt Langsung

Saya tidak terlalu memikirkan gaya prompt. Dengan Z-Image-Base, prompt langsung yang sederhana bekerja lebih baik daripada prosa yang rumit. Saya menulis niat terlebih dahulu, lalu batasan:

  • “Foto produk bergaya editorial berupa cangkir keramik di atas meja linen, cahaya pagi yang lembut.”
  • Kemudian spesifikasi: “Tampilan 35mm, pewarnaan netral, tanpa teks, latar belakang bersih.”

Saya menghindari kata kerja kecuali membutuhkan gerakan. Model ini stabil ketika saya tetap konkret: material, cahaya, kesan lensa, jenis latar belakang. Ia menyimpang ketika saya menambahkan nuansa. Jika saya menulis “minimalisme nyaman,” saya mendapat kekacauan lilin. Ketika saya menulis “cahaya lembut, satu sumber difus, tanpa lilin,” ia mematuhi.

negative_prompt - Mengecualikan Elemen yang Tidak Diinginkan

Awalnya saya ragu menggunakan negative prompt, tapi akhirnya menjadi pagar pengaman saya. Saya menyimpan baseline pendek yang selalu saya gunakan kembali:

  • “no text, no watermark, no extra hands, no extra limbs, no logo, no signature, no border”

Menambahkan ini memangkas waktu pembersihan. Tidak memperbaiki setiap kasus tepi (cincin terkadang masih muncul di cangkir), tetapi cukup menurunkan tingkat keanehan sehingga saya berhenti melakukan render ulang untuk batch kecil. Ketika saya membutuhkan sudut produk yang ketat, saya menambahkan “no dramatic perspective, no tilt” dan mendapat foto yang lebih lurus.

guidance_scale (CFG) - Mengontrol Tingkat Kepatuhan Prompt

Parameter ini lebih berpengaruh dari yang saya kira. Catatan saya:

  • 5–6: santai, sedikit lebih banyak tekstur dan improvisasi
  • 7–8: andal: yang saya gunakan untuk sebagian besar proses
  • 9+: kepatuhan literal, tetapi terkadang pencahayaan rapuh dan warna lebih datar

Ketika saya memiliki gambar referensi yang bagus, saya menurunkan CFG ke 6–7 dan mendapat kontras mikro yang lebih indah. Tanpa referensi, 7.5 adalah median saya. Menurut dokumentasi teknis Z-Image, model ini mendukung Classifier-Free Guidance (CFG) penuh, memberikan presisi untuk rekayasa prompt yang kompleks. Di atas 9 terasa seperti meminta teman yang teliti untuk lebih berhati-hati lagi—tidak salah, hanya sedikit tidak bernyawa.

image + strength - Panduan Gambar Referensi

Pasangan ini yang melakukan pekerjaan berat. Saya melampirkan satu JPG referensi dan menyetel strength untuk mengontrol seberapa jauh model mengikutinya:

  • 0.25–0.35: sentuhan ringan: mempertahankan palet dan nuansa
  • 0.45–0.6: kepatuhan solid: komposisi tetap dekat
  • 0.7+: hampir menyalin: berguna untuk variasi dengan perubahan gaya kecil

Saya tidak menyangka 0.5 menjadi titik optimal, tapi memang begitu. Cukup struktur untuk mempertahankan tata letak, cukup kebebasan untuk penyesuaian pencahayaan. Kekuatan yang lebih tinggi membuatnya keras kepala: jika sumber memiliki bayangan di tempat yang salah, model menempel padanya. Saya mulai menyesuaikan prompt dengan “shadow on camera-left” dan menurunkan strength sebagai gantinya. Lebih sedikit percobaan ulang dengan cara itu.

Satu catatan praktis: saya mengubah ukuran input referensi menjadi 1024 pada sisi terpanjang sebelum diunggah. Dimensi yang konsisten memberi saya crop dan kecepatan yang lebih dapat diprediksi. Ini juga menghemat sedikit bandwidth selama banyak iterasi.

Implementasi Kode

Tes Cepat dengan cURL

Ketika saya menyambungkan endpoint baru, saya mulai dengan cURL hanya untuk melihat bentuk respons dan kode error.

curl -X POST \
  https://api.wavespeed.ai/v1/images/generations \
  -H "Authorization: Bearer $WAVESPEED_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "Z-Image-Base",
    "prompt": "Editorial-style product photo of a ceramic mug on a linen table, soft morning light. 35mm look, neutral color grading, no text, uncluttered background.",
    "negative_prompt": "no text, no watermark, no extra hands, no extra limbs, no logo, no signature, no border",
    "guidance_scale": 7.5,
    "size": "1024x1024"
  }'

Saya mendapatkan kembali payload JSON dengan array gambar (base64 atau URL, tergantung opsi). Jika Anda lebih memilih URL langsung, tetapkan target output atau flag penyimpanan jika API mendukungnya. Saya menggunakan base64 saat pengujian dan mendekode secara lokal.

Contoh Python Lengkap

Ini mendekati apa yang saya jalankan pada pekerjaan batch Selasa pagi. Sederhana, dengan cukup struktur untuk percobaan ulang.

import os
import base64
import requests

API_KEY = os.getenv("WAVESPEED_API_KEY")
BASE_URL = "https://api.wavespeed.ai/v1"

headers = {
    "Authorization": f"Bearer {API_KEY}",
}


def generate_image(prompt, negative_prompt, guidance_scale=7.5, size="1024x1024"):
    url = f"{BASE_URL}/images/generations"
    
    payload = {
        "model": "Z-Image-Base",
        "prompt": prompt,
        "negative_prompt": negative_prompt,
        "guidance_scale": guidance_scale,
        "size": size,
    }
    
    response = requests.post(
        url,
        headers={**headers, "Content-Type": "application/json"},
        json=payload,
        timeout=60
    )
    response.raise_for_status()
    
    data = response.json()
    b64_string = data["data"][0]["b64_json"]
    return base64.b64decode(b64_string)


if __name__ == "__main__":
    prompt = (
        "Editorial-style product photo of a ceramic mug on a linen table, soft morning light. "
        "35mm look, neutral color grading, no text, uncluttered background."
    )
    negative_prompt = (
        "no text, no watermark, no extra hands, no extra limbs, "
        "no logo, no signature, no border"
    )

    try:
        image_bytes = generate_image(prompt, negative_prompt)
        with open("output.png", "wb") as f:
            f.write(image_bytes)
        print("Saved output.png")
    except requests.HTTPError as e:
        print("HTTP error:", e.response.text if e.response else str(e))
    except Exception as e:
        print("Error:", str(e))

Saya menambahkan timeout 60 detik setelah satu pekerjaan macet pada Wi-Fi yang tidak stabil. Blok exception-nya blunt, tetapi dalam produksi saya memetakan kode status (429, 503) ke backoff.

Contoh JavaScript/Node.js

Untuk Node, saya menggunakan fetch dengan helper kecil. Ide yang sama: jaga autentikasi tetap sederhana, tampilkan error dengan jelas.

import fs from 'node:fs/promises';
import fetch from 'node-fetch';

const API_KEY = process.env.WAVESPEED_API_KEY;
const BASE_URL = 'https://api.wavespeed.ai/v1';

async function generateImage({
  prompt,
  negativePrompt,
  guidanceScale = 7.5,
  size = '1024x1024',
}) {
  const response = await fetch(`${BASE_URL}/images/generations`, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      model: 'Z-Image-Base',
      prompt,
      negative_prompt: negativePrompt,
      guidance_scale: guidanceScale,
      size,
    }),
  });

  if (!response.ok) {
    const errorText = await response.text();
    throw new Error(`HTTP ${response.status}: ${errorText}`);
  }

  const json = await response.json();
  const base64String = json.data[0].b64_json;
  return Buffer.from(base64String, 'base64');
}

(async () => {
  try {
    const prompt = 
      'Editorial-style product photo of a ceramic mug on a linen table, soft morning light. ' +
      '35mm look, neutral color grading, no text, uncluttered background.';

    const negativePrompt = 
      'no text, no watermark, no extra hands, no extra limbs, ' +
      'no logo, no signature, no border';

    const imageBuffer = await generateImage({ prompt, negativePrompt });
    
    await fs.writeFile('node-output.png', imageBuffer);
    console.log('Saved node-output.png');
  } catch (err) {
    console.error('Error:', err.message);
  }
})();

Setelah ini berjalan, saya berhenti memikirkan tentang plumbing-nya, dan itulah tujuannya. Z-Image-Base API tidak menghalangi saya.

Mode Asinkron vs Sinkron

Saya mencoba kedua mode. Sinkron cocok untuk gambar tunggal atau pemeriksaan cepat. Latensi rata-rata berada di angka beberapa detik untuk output berukuran 1024. Ketika saya mengantrekan 8–12 render, saya beralih ke asinkron agar skrip saya tidak memblokir pada setiap satu proses.

Pola async-nya dapat diprediksi: kirim pekerjaan, dapatkan id, polling endpoint status, lalu ambil hasilnya ketika state: "succeeded". Saya menetapkan interval polling 2–3 detik dan batas waktu 2 menit. Pada jaringan yang tidak stabil, async menyelamatkan saya dari timeout karena saya bisa melanjutkan polling tanpa mengirim ulang pekerjaan. Detail kecil, perbedaan besar saat menggunakan Wi-Fi di perjalanan.

Jika alur kerja Anda bersifat interaktif (sesuaikan, lihat, sesuaikan), sinkron lebih nyaman. Jika bersifat batch atau terjadwal, async membuat pipeline lebih lancar dan gagal dengan lebih elegan.

Penanganan Error

Dua pola membantu saya membuat error menjadi tidak membosankan.

  • Batas rate (429): Saya menggunakan exponential backoff dengan jitter. Mulai dari ~500ms, batas atas ~20 detik, dan berhenti setelah 5–6 percobaan. Dengan pekerjaan async, saya cukup mencoba ulang panggilan status daripada mengantrekan ulang render kecuali API mengatakan pekerjaan tersebut hilang.
  • Error validasi (400/422): Ini biasanya berasal dari jenis konten yang tidak cocok atau ukuran yang tidak didukung. Ketika saya melihat 422 pada pengeditan gambar, hampir selalu nama field form-data saya yang salah (image vs reference_image). Saya menambahkan pemeriksaan skema kecil sebelum permintaan untuk mencegah hal ini.

Satu catatan lagi: saya mencatat model, guidance_scale, size, dan hash dari prompt. Ketika sesuatu yang aneh lolos, saya bisa mereproduksinya dengan tepat. Itulah perbedaan antara mengangkat bahu dan memperbaiki.

Apakah Z-Image-Base gagal lebih jarang dibanding model lain? Sulit dikatakan. Yang saya perhatikan adalah ketika ia gagal, pesannya cukup spesifik sehingga saya tidak membuang waktu untuk menebak-nebak. Itu ergonomi yang baik.