Untuk pembangun··5 minit bacaan

Tutorial API Bigjpg: besarkan imej secara pukal dengan Python

Skrip yang terus boleh dijalankan untuk memuat naik imej, mencipta tugasan pembesaran, menyemak hasil dan memuat turunnya, termasuk kawalan keselarian dan pengendalian ralat supaya kerja 500 imej tidak berhenti separuh jalan.

Tutorial API Bigjpg: besarkan imej secara pukal dengan Python

Untuk beberapa keping imej, antara muka web sudah memadai. Kalau folder anda ada lima ratus fail, API lebih menyenangkan: empat endpoint, tiada pelayar, dan skrip boleh dijalankan berulang kali. Versi di bawah inilah yang kami berikan terus kepada rakan sekerja: muat naik, cipta, semak, muat turun, sekali dengan pengendalian kegagalan yang benar-benar berguna.

Sebelum mula

  • Akses API hanya untuk akaun berbayar. Kunci ada di halaman API selepas anda log masuk dengan pelan yang masih aktif.
  • Python 3 dengan requests dipasang. Tiada apa-apa lagi.
  • Pembesaran berjalan secara tak segerak pada worker kami, jadi skrip mencipta tugasan dahulu, kemudian menyemaknya. Kerja 500 imej mengambil masa selama tugasan paling perlahan dalam baris gilir anda, bukan jumlah keseluruhan imej.

Skrip

import json
import os
import time
import requests

API = "https://bigjpg.com"
KEY = "YOUR_API_KEY"
STYLE = "art"          # "art" untuk ilustrasi, "photo" untuk gambar foto
NOISE = "1"            # -1 tiada, 0 rendah, 1 sederhana, 2 tinggi, 3 tertinggi
X2 = "2"               # 1 = 2x, 2 = 4x, 3 = 8x, 4 = 16x
POLL_SECONDS = 8
MAX_RETRY = 1

HEADERS = {"X-API-KEY": KEY}


def upload(path):
    """Get a presigned URL, PUT the file, return its public URL."""
    name = path.split("/")[-1]
    r = requests.post(
        API + "/api/img_upload",
        headers=HEADERS,
        data={"filename": name, "filetype": "image/jpeg"},
        timeout=60,
    )
    info = r.json()
    if info.get("status") != "ok":
        raise RuntimeError("upload failed: " + str(info))

    with open(path, "rb") as image:
        r = requests.put(
            info["url"],
            data=image,
            headers={"Content-Type": "image/jpeg"},
            timeout=300,
        )
    if r.status_code != 200:
        raise RuntimeError("upload failed with HTTP %s" % r.status_code)
    return info["fileurl"]


def create(image_url):
    """Create an enlargement task, return its task id."""
    payload = {
        "style": STYLE,
        "noise": NOISE,
        "x2": X2,
        "input": image_url,
    }
    r = requests.post(
        API + "/api/task/",
        headers=HEADERS,
        data=json.dumps(payload),
        timeout=60,
    )
    data = r.json()
    if "tid" not in data:
        raise RuntimeError("task failed: " + str(data))
    return data["tid"]


def poll(tids):
    """Query up to 100 task ids at once. Returns task id -> result dict."""
    r = requests.get(API + "/api/task/" + ",".join(tids), timeout=60)
    return r.json()


def download(url, out):
    """Download a finished image, checking the transfer really succeeded."""
    r = requests.get(url, timeout=300)
    if r.status_code != 200:
        raise RuntimeError("download failed with HTTP %s" % r.status_code)
    with open(out, "wb") as f:
        f.write(r.content)
    return out


def main(paths):
    pending = {}
    attempts = {}
    for path in paths:
        try:
            tid = create(upload(path))
        except Exception as e:
            print("skipped", path, e)
            continue
        pending[tid] = path
        attempts[tid] = 0
        print("queued", path, tid)

    while pending:
        for tid, info in poll(list(pending)[:100]).items():
            if info.get("status") == "success":
                out = os.path.splitext(pending[tid])[0] + "_bigjpg.jpg"
                try:
                    download(info["url"], out)
                except Exception as e:
                    print("download failed", pending[tid], e)
                    pending.pop(tid)
                    continue
                print("done", pending.pop(tid), "->", out)

            elif info.get("status") == "error":
                # Cuba sekali lagi, kalau gagal lepaskan fail ini.
                attempts[tid] += 1
                if attempts[tid] <= MAX_RETRY:
                    requests.post(API + "/api/task/" + tid, headers=HEADERS, timeout=60)
                    print("retrying", pending[tid])
                else:
                    print("giving up on", pending.pop(tid))

        if pending:
            time.sleep(POLL_SECONDS)


if __name__ == "__main__":
    import sys
    main(sys.argv[1:])

Apa setiap panggilan lakukan

PanggilanTujuanCatatan
POST /api/img_uploadKembalikan URL muat naik bertandatangan dan URL imej awamMuat naik fail dengan PUT menggunakan Content-Type yang sama, kemudian guna fileurl sebagai input tugasan
POST /api/task/Cipta tugasan pembesaranKembalikan tid, minute anggaran dan remaining_api_calls
GET /api/task/{ids}Status satu atau banyak tugasanid dipisahkan koma, sehingga 100 setiap permintaan
POST /api/task/{ids}Cuba semula tugasan yang gagalHanya tugasan berstatus error kembali ke baris gilir

Keselarian dan adab

  • Semak dengan jarak yang lebih longgar. Pembesaran tidak serta-merta; 5–10 saat antara semakan sudah cukup, dan bertanya 100 id sekali gus mengekalkan bilangan permintaan.
  • Hadkan muat naik. Dua hingga empat muat naik serentak adalah siling yang munasabah untuk satu mesin. Perlukan daya pemprosesan lebih, jalankan lebih banyak instans, bukan lebih banyak benang setiap instans.
  • Cuba semula dengan kelewatan bertambah. Ralat rangkaian bukan kegagalan tugasan. Ulang panggilan HTTP sehingga tiga kali dengan jeda yang makin panjang sebelum fail dianggap rosak.
  • Perhatikan remaining_api_calls. Setiap tugasan yang dicipta melaporkannya; hentikan gelung pada ambang rendah daripada mengetahui hadnya melalui dinding ralat.
  • Simpan pemetaan. Kekalkan fail yang mengandungi tid, nama input, tetapan dan nama output. Bila kerja berjalan sepanjang malam, fail itu satu-satunya cara mengetahui apa yang sudah siap.

Ralat yang pasti anda temui

  • valid_api_key_required — header tiada atau kunci tidak dikenali. Periksa nama header dan pastikan pelan kunci itu belum tamat tempoh.
  • requires_vip — akaun percuma atau sudah tamat. API untuk pelan berbayar yang aktif.
  • month_limit — kuota bulanan habis. Baki dilaporkan pada setiap tugasan, jadi anda boleh berhenti sebelum itu.
  • param_error — style mesti art atau photo, noise -1 hingga 3, x2 1 hingga 4.
  • input_url_error — input mesti URL imej http atau https yang boleh diakses awam. URL peribadi bertandatangan akan tamat tempoh; muat naik dahulu, kemudian hantar URL awam yang dikembalikan.

Kos satu kelompok

Satu imej dikira satu kredit pada 2x, 4x dan 8x; pada 16x dikira dua. Jadi 500 imej pada 4x bermakna 500 kredit, dan kerja yang sama pada 16x menjadi 1000. Oleh sebab 4x memang faktor yang betul untuk kebanyakan gambar foto, pilihan yang lebih murah biasanya juga yang lebih elok — sebabnya ada dalam panduan faktor.

Rujukan lengkap endpoint, termasuk parameter dan semua status ralat, ada di halaman API. Kalau ada bahagian skrip yang tidak sepadan dengan respons anda, halaman itu versi yang kami kemas kini.

← Semua artikel