ID ▾

Chinese LLM APITerjemahan

Dapatkan kunci API

Diperbarui

Terjemahan dan lokalisasi Tiongkok↔Inggris melalui API chat

Menerjemahkan string UI dan dokumen dengan model chat mudah untuk didemonstrasikan tetapi sulit untuk diproduksi. Kegagalannya bersifat rutin: placeholder yang diganti namanya, istilah glosarium diterjemahkan dengan tiga cara berbeda, balasan JSON dibungkus dalam prosa. Panduan ini memperlakukan terjemahan sebagai pipa dengan pemeriksaan di setiap tahap, menggunakan endpoint penyelesaian chat yang kompatibel dengan OpenAI.

Berpikir secara bertahap, bukan dalam satu prompt

Pekerjaan terjemahan produksi memiliki empat tahap: siapkan string, panggil model, validasi hasilnya, dan gabungkan kembali. Sebagian besar masalah kualitas berasal dari melewatkan tahap validasi. Seorang insinyur lokalisasi tidak akan pernah mengirimkan file terjemahan tanpa menjalankan linter placeholder, dan disiplin yang sama berlaku ketika penerjemah adalah model.

Endpoint adalah https://api.chinesellmapi.com/v1/chat/completions, id model uncensored, autentikasi bearer. Ini menangani kedua arah, Inggris ke Tiongkok dan Tiongkok ke Inggris, dan contoh di bawah ini menggunakan string sumber Inggris yang masuk ke Tiongkok Sederhana. Ganti arah dalam prompt sistem untuk arah sebaliknya.

Ingat jendela konteks token 100.000, max_tokens default 2.048 (naikkan untuk dokumen panjang, hingga 32.000), dan batas body permintaan 8 MB. Tidak ada dari ketiganya yang memengaruhi string UI, tetapi semuanya penting untuk dokumen utuh.

Injeksi glosarium

Nama merek, kata benda produk, dan istilah yang sensitif secara hukum memerlukan satu tampilan yang tetap. Mekanisme termurah adalah blok glosarium dalam prompt sistem, yang mencantumkan istilah sumber dan target yang diperlukan. Nyatakan aturan secara eksplisit: gunakan glosarium secara harfiah pada setiap infleksi istilah sumber. Jaga glosarium tetap pendek, karena setiap baris ditagih sebagai input pada setiap panggilan; beberapa lusin entri adalah hal yang normal, ribuan bukan.

import os
from openai import OpenAI

client = OpenAI(base_url="https://api.chinesellmapi.com/v1", api_key=os.environ["API_KEY"])

GLOSSARY = {
    "workspace": "工作区",
    "pull request": "合并请求",
    "seat": "席位",
    "billing cycle": "计费周期",
}

def build_system(glossary, target="Simplified Chinese"):
    rows = "\n".join(f"- {src} => {dst}" for src, dst in glossary.items())
    return (
        f"You are a software localization translator. Translate English UI strings into {target}.\n"
        "Rules:\n"
        "1. Use the glossary below verbatim whenever the source term appears, in any inflection.\n"
        "2. Copy placeholders such as {name}, %s, %d and {{count}} exactly, character for character.\n"
        "3. Copy HTML tags and attributes exactly; translate only the text between tags.\n"
        "4. Output the translation only, with no notes.\n\n"
        "Glossary:\n" + rows
    )

def translate(text):
    r = client.chat.completions.create(
        model="uncensored",
        messages=[
            {"role": "system", "content": build_system(GLOSSARY)},
            {"role": "user", "content": text},
        ],
        temperature=0.2,
        max_tokens=400,
    )
    return r.choices[0].message.content.strip()

print(translate("Invite {name} to the workspace before the next billing cycle."))

Jika glosarium Anda besar, filter per permintaan: sertakan hanya entri yang istilah sumbernya muncul dalam batch. Tes substring sederhana pada teks huruf kecil sudah cukup untuk versi pertama dan menjaga prompt tetap kecil. Atur suhu sekitar 0,2; variasi kreatif adalah bug pada salinan UI.

Putuskan juga panduan gaya bahasa untuk bahasa target di awal: alamat formal atau kasual, apakah memberi spasi antara karakter Mandarin dan kata atau angka Latin yang disisipkan, serta set tanda baca mana yang digunakan. Masukkan keputusan ini ke dalam system prompt agar setiap batch mewarisi aturan tersebut.

Mempertahankan placeholder dan markup tetap utuh

Placeholder rusak dengan cara yang dapat diprediksi: model menerjemahkan nama variabel, menghilangkan %s di akhir, atau menambahkan spasi di dalam kurung kurawal. Aturan prompt mengurangi kegagalan ini tetapi tidak menghilangkannya sepenuhnya, jadi verifikasi dalam kode. Ekstrak placeholder dan tag dari sumber dan target menggunakan ekspresi reguler, lalu bandingkan sebagai daftar yang diurutkan. Urutan dapat berubah secara sah antar bahasa, jadi bandingkan sebagai multiset alih-alih urutan.

import re

PLACEHOLDER = re.compile(r"\{\{?\w+\}?\}|%[sd]|</?[a-zA-Z][^>]*>")

def placeholders_ok(source: str, target: str) -> bool:
    # Same multiset of placeholders and tags, regardless of order.
    return sorted(PLACEHOLDER.findall(source)) == sorted(PLACEHOLDER.findall(target))

src = 'You have <b>{count}</b> unread messages in %s.'
bad = '你在 %s 中有 <b>{数量}</b> 条未读消息。'
good = '你在 %s 中有 <b>{count}</b> 条未读消息。'
print(placeholders_ok(src, bad), placeholders_ok(src, good))   # False True

Saat pemeriksaan gagal, coba lagi sekali dengan pasangan yang gagal dikutip kembali ke dalam prompt, misalnya pesan pengguna yang menyatakan bahwa output sebelumnya mengubah placeholder dan harus diperbaiki. Jika masih gagal, tandai string untuk ditinjau manusia daripada melakukan loop. Teks kaya format memerlukan perhatian ekstra: lebih baik menerjemahkan node teks dan membangun kembali markup sendiri, karena hal itu membuat kerusakan tag mustahil secara konstruksi.

Output terstruktur melalui instruksi

Pengelompokan string dalam satu permintaan memerlukan balasan yang dapat dibaca mesin. API menerima bidang penyelesaian obrolan standar; output terstruktur di sini berasal dari instruksi yang jelas daripada saklar penjamin skema, jadi tulis kontrak ke dalam prompt, sertakan id agar Anda dapat menyelaraskan hasil, dan parse secara defensif. Model terkadang membungkus JSON dalam pagar kode atau menambahkan kalimat ramah, jadi hapus pagar kode sebelum parsing dan anggap kesalahan parsing sebagai peristiwa yang dapat dicoba ulang.

import json
import os
import re
from openai import OpenAI

client = OpenAI(base_url="https://api.chinesellmapi.com/v1", api_key=os.environ["API_KEY"])

SYSTEM = (
    "Translate each item from English to Simplified Chinese. "
    "Reply with a JSON object only, no code fences, no commentary. "
    'Shape: {"items": [{"id": <number>, "zh": "<translation>"}]}. '
    "Keep the same ids, keep every placeholder and HTML tag unchanged."
)

def translate_batch(strings):
    payload = [{"id": i, "en": s} for i, s in enumerate(strings)]
    r = client.chat.completions.create(
        model="uncensored",
        messages=[
            {"role": "system", "content": SYSTEM},
            {"role": "user", "content": json.dumps(payload, ensure_ascii=False)},
        ],
        temperature=0.2,
        max_tokens=2000,
    )
    raw = r.choices[0].message.content.strip()
    raw = re.sub(r"^```(?:json)?|```$", "", raw, flags=re.M).strip()   # tolerate stray fences
    data = json.loads(raw)
    by_id = {item["id"]: item["zh"] for item in data["items"]}
    return [by_id[i] for i in range(len(strings))]

print(translate_batch(["Save changes", "Delete {count} files?", "Welcome back, <b>{name}</b>"]))

Selalu validasi setelah parsing: id harus cocok, jumlah harus cocok, dan setiap item harus lulus pemeriksaan placeholder dari bagian sebelumnya. Lima puluh string per permintaan adalah batch awal yang masuk akal untuk teks UI pendek; tingkatkan hanya jika tingkat kelulusan pemeriksaan tetap tinggi.

Terjemahan batch di bawah batas laju

Setiap kunci dibatasi hingga 300 permintaan per menit. Pekerjaan lokalisasi dengan 50.000 string pada 20 string per permintaan adalah 2.500 permintaan, yang muat dalam waktu kurang dari sepuluh menit jika Anda membaginya secara merata. Skrip di bawah ini menggabungkan semafon untuk panggilan yang sedang berjalan dengan pacer berbasis kunci, dan melakukan back off pada 429 dan 503. Berbeda dengan kegagalan validasi, dua kesalahan tersebut bersifat sementara: 429 berarti perlambat, dan 503 dengan upstream_busy berarti coba lagi dalam beberapa detik. 402 berarti saldo telah habis, yang tidak dapat diperbaiki dengan coba ulang.

import asyncio
import os
import time
from openai import AsyncOpenAI, APIStatusError

client = AsyncOpenAI(
    base_url="https://api.chinesellmapi.com/v1",
    api_key=os.environ["API_KEY"],
    max_retries=0,
    timeout=90,
)

RATE = 240 / 60            # requests per second, below the 300/min cap
gate = asyncio.Lock()
next_slot = 0.0
slots = asyncio.Semaphore(6)

async def pace():
    global next_slot
    async with gate:
        now = time.monotonic()
        if next_slot > now:
            await asyncio.sleep(next_slot - now)
        next_slot = max(now, next_slot) + 1 / RATE

async def call(batch, attempt=0):
    async with slots:
        await pace()
        try:
            r = await client.chat.completions.create(
                model="uncensored",
                messages=[
                    {"role": "system", "content": "Translate to Simplified Chinese. Keep placeholders unchanged. One line per input line."},
                    {"role": "user", "content": "\n".join(batch)},
                ],
                max_tokens=1500,
                temperature=0.2,
            )
            return r.choices[0].message.content.splitlines()
        except APIStatusError as e:
            if e.status_code in (429, 503) and attempt < 4:
                await asyncio.sleep(2 ** attempt + 1)     # 1s, 3s, 5s, 9s
                return await call(batch, attempt + 1)
            raise

async def run(all_strings, size=20):
    chunks = [all_strings[i:i + size] for i in range(0, len(all_strings), size)]
    results = await asyncio.gather(*(call(c) for c in chunks))
    return [line for part in results for line in part]

if __name__ == "__main__":
    strings = [f"Item {n} was updated by {{user}}" for n in range(60)]
    out = asyncio.run(run(strings))
    print(len(out), out[0])

Versi ini membagi berdasarkan baris untuk kepraktisan, yang baik untuk string satu baris; untuk apa pun yang multi-baris, gunakan varian JSON dari bagian sebelumnya agar pemisah baris di dalam string tidak disalahartikan sebagai batas string.

Arah sebaliknya: teks sumber Tiongkok

Menerjemahkan Tiongkok ke Inggris memiliki mode kegagalan sendiri. Tiongkok secara bebas menjatuhkan subjek dan bentuk jamak, sehingga model harus menebaknya; berikan konteks. String seperti "已发送" bisa menjadi "Sent", "Has been sent" atau "You sent it", tergantung pada apakah itu menandai tombol, lencana status atau toast. Perbaikannya adalah bidang konteks di samping setiap string, yang disediakan oleh pengembang Anda dan diteruskan dalam batch JSON: di mana string muncul, panjang maksimumnya, dan apakah itu label atau kalimat.

Ukur batas panjang secara eksplisit. Teks UI bahasa Inggris sering kali lebih panjang daripada teks asli bahasa Mandarin, dan sebaliknya benar untuk target bahasa Mandarin, yang cenderung lebih pendek dalam karakter tetapi lebih lebar di layar karena setiap glif memiliki lebar penuh. Tetapkan anggaran karakter dalam prompt ketika tombol atau header tabel memiliki batas keras, dan verifikasi dalam kode setelah respons tiba.

Untuk dokumen sumber bahasa Mandarin dengan nama orang dan tempat, tentukan konvensi romanisasi di awal, seperti Hanyu Pinyin tanpa tanda nada, dan tambahkan nama yang berulang ke glossary. Tanpa itu, orang yang sama dapat muncul dengan dua ejaan dalam satu dokumen, yang merupakan inkonsistensi yang akan diperhatikan oleh reviewer terlebih dahulu.

Pengambilan sampel dan tinjauan sebelum Anda menggabungkan

Pemeriksaan otomatis menangkap kesalahan struktural, bukan kesalahan terjemahan. Tambahkan langkah manusia ringan: ambil sampel persentase tetap dari setiap batch, misalnya setiap string kedua puluh, ditambah setiap string yang memerlukan upaya ulang, dan kirimkan kepada peninjau dwibahasa. Lacak tingkat edit peninjau per batch. Jika meningkat, perketat prompt, kecilkan ukuran batch, atau tambahkan entri glosarium untuk istilah yang sedang dikoreksi.

Simpan prompt, versi glosarium, dan pengaturan batch di samping setiap file output. Ketika istilah berubah dalam glosarium, Anda dapat kemudian menerjemahkan ulang hanya string yang mengandungnya, alih-alih menjalankan ulang seluruh korpus. Hash konten sederhana dari string sumber ditambah versi glosarium berfungsi sebagai kunci cache, dan ini berarti string yang tidak berubah tidak memerlukan biaya apa pun pada eksekusi berikutnya.

Akhirnya, pertahankan set regresi string yang rumit: yang memiliki placeholder bersarang, bentuk jamak, HTML yang disisipkan, dan kata benda majemuk panjang. Jalankan setiap kali Anda mengubah prompt, dan bandingkan output secara berdampingan sebelum menerapkan perubahan.

Mengestimasi biaya untuk eksekusi lokalisasi

Asumsi, dinyatakan secara jelas: 30.000 string sumber, 12 kata bahasa Inggris masing-masing, diterjemahkan dalam batch 20. Ambil kira-kira 20 token input per string ditambah 300 token prompt sistem tetap per permintaan, dan kira-kira 35 token output per string. Itu memberikan 1.500 permintaan, kira-kira 1,05 juta token input dan kira-kira 1,05 juta token output. Pada $0,25 per juta token input dan $1,00 per juta token output, jalankanan ini menelan biaya kira-kira $0,26 ditambah $1,05, sekitar $1,31. Anggap ini sebagai estimasi orde magnitudo dan ganti asumsi dengan angka dari log usage Anda sendiri.

Kredit uji coba adalah $0,50 selama tujuh hari, yang cukup untuk memvalidasi pipa pada sampel beberapa ribu string. Lanjutkan dengan quickstart aplikasi untuk kontrol skrip dan penanganan UTF-8, atau lihat halaman harga untuk tarif saat ini.

Tanya jawab

Dapatkah API menerjemahkan dalam kedua arah?

Ya. Tiongkok ke Inggris dan Inggris ke Tiongkok sama-sama bekerja melalui endpoint chat yang sama; Anda memilih arah dalam prompt sistem.

Bagaimana cara mencegah model mengubah placeholder seperti {name}?

Nyatakan aturan dalam prompt, lalu verifikasi dalam kode dengan membandingkan daftar placeholder antara sumber dan target, mencoba lagi atau menandai ketidakcocokan.

Apakah ada sakelar mode JSON?

Output terstruktur diperoleh melalui instruksi. Tentukan bentuk yang tepat dalam prompt, hapus pagar kode yang tersesat, lalu parse dan validasi hasilnya.

Seberapa cepat Anda dapat menjalankan batch besar?

Setiap kunci memungkinkan 300 permintaan per menit. Atur permintaan secara merata dan tunggu jika menerima respons 429 atau 503.

Kunci Anda hanya selangkah lagi dari satu formulir

Buat akun, salin kunci, ubah URL dasar. Itu adalah seluruh penyiapan.

Dapatkan kunci API