Lewati ke konten
kenari.

Gambar & berkas sebagai input

Sebagian model bisa membaca gambar secara langsung. Kamu melampirkan gambar ke sebuah pesan, dan model menjawab pertanyaan tentang gambar tersebut dalam request yang sama. Dokumen bisa dipakai di model apa pun: kenari membaca PDF, berkas teks, atau berkas gambar lebih dulu dan memberi model teks serta gambar halamannya. Halaman ini membahas gambar di ketiga format chat dan dokumen di Chat completions dan Messages. Baca dokumen memuat batas dan engine-nya.

GET /v1/models mencantumkan apa yang diterima setiap model di modalities.input. Endpoint ini publik, jadi kamu bisa memfilternya tanpa key:

Terminal window
curl -s https://kenari.id/v1/models \
| jq -r '.data[] | select((.modalities.input // []) | index("image")) | .id'

Ganti "image" dengan "pdf" untuk mencari model yang membaca PDF sendiri.

Nilai di modalities.inputModel membaca
imageGambar.
pdfBerkas PDF, oleh model itu sendiri.
fileDokumen apa pun. Semua model chat mencantumkannya, karena kenari membaca dokumen terlampir untuk model apa pun.

Daftar itu juga bisa berisi audio dan video, yang tidak dibahas di halaman ini. Contoh di bawah memakai step-3-7-flash:free, yang membaca gambar dan gratis dipanggil.

Tambahkan part image_url di samping teksmu. url-nya berupa data URL atau alamat web.

import base64
import os
from openai import OpenAI
client = OpenAI(
base_url="https://kenari.id/v1",
api_key=os.environ["KENARI_API_KEY"],
)
with open("receipt.jpg", "rb") as file:
image = base64.b64encode(file.read()).decode()
response = client.chat.completions.create(
model="step-3-7-flash:free",
messages=[
{
"role": "user",
"content": [
{"type": "text", "text": "Berapa total di struk ini?"},
{"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{image}"}},
],
}
],
)
print(response.choices[0].message.content)

Alamat web bekerja dengan cara yang sama: {"type": "image_url", "image_url": {"url": "https://example.com/receipt.jpg"}}.

kenari tidak mengunduh gambar. Dengan alamat web, provider model yang mengambil gambar, dan tidak semua provider melakukannya. Jika provider tidak bisa, request gagal dengan 400 dan pesan remote image URL not supported by upstream. Data URL bekerja di setiap model yang membaca gambar, jadi pakai itu jika request harus jalan di mana saja.

Di /v1/messages, gambar adalah blok dengan source bertipe base64 atau url. Arahkan Anthropic SDK ke https://kenari.id, tanpa /v1.

import base64
import os
import anthropic
client = anthropic.Anthropic(
base_url="https://kenari.id",
api_key=os.environ["KENARI_API_KEY"],
)
with open("receipt.jpg", "rb") as file:
image = base64.b64encode(file.read()).decode()
message = client.messages.create(
model="step-3-7-flash:free",
max_tokens=1024,
messages=[
{
"role": "user",
"content": [
{"type": "image", "source": {"type": "base64", "media_type": "image/jpeg", "data": image}},
{"type": "text", "text": "Berapa total di struk ini?"},
],
}
],
)
print(next(block.text for block in message.content if block.type == "text"))

Source url berbentuk {"type": "url", "url": "https://example.com/receipt.jpg"}, dengan catatan yang sama soal alamat web di atas. Tipe source lain, seperti id berkas yang diunggah, diabaikan tanpa error, sehingga model menjawab tanpa gambar.

Di /v1/responses, gambar adalah part input_image yang image_url-nya berupa string, baik data URL maupun alamat web:

{
"model": "step-3-7-flash:free",
"input": [
{
"role": "user",
"content": [
{"type": "input_text", "text": "Berapa total di struk ini?"},
{"type": "input_image", "image_url": "data:image/jpeg;base64,/9j/4AAQ..."}
]
}
]
}

Di Chat completions, dokumen adalah part file. file_data berupa data URL. Ini berlaku di model apa pun: kenari membaca dokumen sebelum request dirutekan, jadi model tidak perlu bisa membaca berkas sendiri.

import base64
import os
from openai import OpenAI
client = OpenAI(
base_url="https://kenari.id/v1",
api_key=os.environ["KENARI_API_KEY"],
)
with open("invoice.pdf", "rb") as file:
document = base64.b64encode(file.read()).decode()
response = client.chat.completions.create(
model="step-3-7-flash:free",
messages=[
{
"role": "user",
"content": [
{"type": "text", "text": "Apa nomor fakturnya?"},
{
"type": "file",
"file": {
"filename": "invoice.pdf",
"file_data": f"data:application/pdf;base64,{document}",
},
},
],
}
],
)
print(response.choices[0].message.content)

kenari mengirim ke model teks dari setiap halaman yang punya lapisan teks dan gambar dari setiap halaman yang tidak punya. Kamu bisa melampirkan beberapa dokumen dalam satu request. Tipe yang diterima adalah PDF, text/plain, text/markdown, text/csv, text/html, application/json, dan gambar. Batasnya sekitar 15 MB dan 100 halaman per dokumen, serta 20 halaman tanpa lapisan teks per request. Dokumen yang membuat request terlalu panjang untuk konteks model ditolak dengan 400 tanpa biaya, dan pesannya menyebut jumlah tokennya. Lihat Baca dokumen untuk batas dan engine-nya.

Kirim gambar sebagai part image_url kalau bisa. Gambar di part file dikirim ke model sebagai gambar, tetapi dengan engine native gambar ditolak dengan 400. Part file tanpa objek file juga ditolak.

Dua format lain berperilaku berbeda:

  • /v1/responses tidak menerima input_file dan menjawab 400.
  • Di /v1/messages, blok document dengan sumber base64 dibaca dengan cara yang sama seperti part file, di model apa pun. Blok document dengan sumber url hanya sampai ke model yang dilayani lewat API gaya Anthropic, dan untuk model lain dibuang tanpa error. Kirim PDF sebagai base64.

Dengan engine native, berkas dikirim apa adanya ke model. Ini butuh model yang membaca berkas sendiri. file di modalities.input tidak menunjukkan hal itu, karena semua model chat mencantumkannya, dan pdf menandai model yang membaca PDF sendiri. kenari memeriksa kemampuan model itu sendiri:

  • Model yang membaca PDF menerima berkas PDF.
  • Model yang membaca dokumen apa pun menerima dokumen apa pun.
  • Model lain: request ditolak dengan 400 sebelum ada biaya, karena dokumen akan sampai ke model yang tidak bisa membacanya.
"plugins": [{"id": "file-parser", "pdf": {"engine": "native"}}]

Penolakannya berbunyi seperti ini:

{
"error": {
"message": "model 'step-3-7-flash:free' does not read application/pdf file attachments. Send the file to a model that reads files, or add the file-parser plugin to read it with OCR (billed per page from your balance)",
"type": "bad_request",
"param": null,
"code": "bad_request"
}
}

Engine ocr berbayar membaca hasil pindaian atau tulisan tangan menjadi teks dengan OCR. Engine ini ditagih per halaman dari saldo dan tidak pernah termasuk paket. Lihat Baca dokumen.

Gambar dan berkas yang dibaca model ditagih sebagai token Input model tersebut, dengan tarif normalnya. Jumlah token bergantung pada model, jadi baca usage di response: usage.prompt_tokens di Chat completions, usage.input_tokens di Messages dan Responses. Di Messages, tambahkan field cache untuk mendapat seluruh prompt, seperti dijelaskan di Prompt caching. Paket yang mencakup model itu juga mencakup token ini, termasuk dokumen yang dibacakan kenari untukmu. Hanya engine ocr yang ditagih per halaman. Lihat Cara penagihan.

  • Seluruh body request dibatasi 32 MiB. Request yang lebih besar ditolak dengan 413. Base64 menambah sekitar sepertiga ukuran berkas.
  • kenari tidak mengubah ukuran gambar dan tidak menghitungnya. Batas ukuran dan jumlah gambar berasal dari model dan providernya.
  • kenari tidak mencocokkan gambar dengan modalities.input. Model yang tidak mencantumkan image bisa gagal dengan error atau menjawab tanpa melihat gambar, jadi pilih model dari daftarnya.
  • Sebuah percakapan mengirim ulang gambarnya di setiap request, dan setiap request ditagih untuk gambar itu lagi. Buang gambar dari riwayat setelah model selesai memakainya.