Model multi-modal adalah model yang bisa memproses dan menghasilkan berbagai jenis data: teks, gambar, audio, juga dokumen seperti PDF. Arahnya gak selalu sama: gpt-6-luna dan semua model Claude menerima gambar tapi menjawab dengan teks, gpt-transcribe mengubah suara jadi teks, gpt-4o-mini-tts mengubah teks jadi suara. Bayangin kasir Toko Buku. Pelanggan datang menyodorkan HP: "Yang ini ada?", isinya foto sampul. Kasir melihat foto, mengenali bukunya, lalu mengecek stok di komputer. Model vision itu mata kasirnya; stok dan harga tetap dari database.
🧪 Tebakan cepat: foto sampul dari HP pelanggan berukuran 1200 × 1600 piksel. Seluruh prompt teks Asisten Toko Buku sekitar 1.200 token. Di Claude, foto itu jadi berapa token: sekitar 300, sekitar 2.500, atau sekitar 25.000? Tebak dulu, jawabannya ada di bagian "Gambar jadi token: hitung dulu".
Gambar masuk: request ke OpenAI dan Claude
Alurnya sama seperti pertanyaan teks: browser mengirim foto ke server-mu (POST /api/assistant/foto), server yang memanggil provider, karena API key cuma ada di server. Foto dikirim sebagai base64: byte file diubah jadi teks, kira-kira 4/3 kali ukuran aslinya. Bentuk request-nya beda per provider (dicek di dokumentasi masing-masing, 11 Oktober 2026):
// OpenAI, Responses API: input_image dengan data URL lengkap
const r = await openai.responses.create({
model: "gpt-6-luna",
input: [{ role: "user", content: [
{ type: "input_text", text: "Judul buku di sampul ini apa? Jawab judulnya saja." },
{ type: "input_image", image_url: `data:image/jpeg;base64,${b64}`, detail: "auto" },
] }],
});
// Claude, Messages API: blok image, base64 TANPA awalan "data:"
const m = await anthropic.messages.create({
model: "claude-haiku-5-5",
max_tokens: 100,
messages: [{ role: "user", content: [
{ type: "image", source: { type: "base64", media_type: "image/jpeg", data: b64 } },
{ type: "text", text: "Judul buku di sampul ini apa? Jawab judulnya saja." },
] }],
});
- OpenAI:
image_urlberisi URL gambar atau data URLdata:image/jpeg;base64,...; bisa jugafile_iddari Files API. Format PNG, JPEG, WEBP, GIF yang gak beranimasi.detailbernilailow,high,original, atauauto(default). - Claude:
source.typebisabase64,url, ataufile;datacuma base64-nya, jenisnya dimedia_type. Format JPEG, PNG, GIF, WebP, maksimal 10 MB per gambar (base64). Dokumentasinya menyarankan gambar ditaruh sebelum teks. - Model cuma mengembalikan judul. Server mencocokkan judul itu dengan tabel buku, lalu stok dan harga dibaca dari SQL: "Laskar Pelangi, stok 12, Rp89.000". Vision bisa salah baca (teks kecil, foto miring), jadi kalau judulnya gak cocok dengan buku mana pun, tanya balik pelanggan.
Gambar jadi token: hitung dulu
Gambar ditagih sebagai token input. Cara menghitungnya ditulis di dokumentasi:
- OpenAI (panduan "Images and vision"): gambar ditutup kotak 32 × 32 piksel (patch). Token = jumlah patch × pengali, dibulatkan ke atas. Untuk
gpt-6-astradan keluargagpt-5.6, detailhighpunya jatah 2.500 patch dan pengali 1,2.gpt-6-lunamenerima gambar tapi belum ada di tabel itu, jadi angka OpenAI di bawah adalah perkiraan dengan aturan tersebut; cek angka sebenarnya diusage.input_tokens. - Claude (halaman "Vision"): patch 28 × 28 piksel, token = ⌈lebar / 28⌉ × ⌈tinggi / 28⌉. Model Claude 4.7 ke atas (termasuk
claude-haiku-5-5) baru mengecilkan gambar kalau sisi panjangnya lewat 2.576 piksel atau tokennya lewat 4.784.
| Ukuran foto | OpenAI (patch × 1,2) | Claude |
|---|---|---|
| 1200 × 1600 (asli dari HP) | 38 × 50 = 1.900 patch → 2.280 token | 43 × 58 = 2.494 token |
| 768 × 1024 | 24 × 32 = 768 patch → 922 token | 28 × 37 = 1.036 token |
| 576 × 768 | 18 × 24 = 432 patch → 519 token | 21 × 28 = 588 token |
Foto asli di Claude jadi 2.494 token, dua kali seluruh prompt teks. Itu jawaban tebakannya. Dengan harga input $0,10 per 1 juta token (claude-haiku-5-5, juga gpt-6-luna), 1.000 foto asli = $0,25, setelah dikecilkan jadi 576 × 768 = $0,06. Di gpt-6-astra ($10 per 1 juta) bedanya $22,80 lawan $5,19. Untuk membaca judul sampul, 768 piksel sudah lebih dari cukup.
Kecilkan di browser sebelum upload
async function kecilkanFoto(file, sisiPanjang = 768) {
const bitmap = await createImageBitmap(file); // orientasi dari EXIF sudah diterapkan
const skala = Math.min(1, sisiPanjang / Math.max(bitmap.width, bitmap.height));
const canvas = document.createElement("canvas");
canvas.width = Math.round(bitmap.width * skala); // 1200 -> 576
canvas.height = Math.round(bitmap.height * skala); // 1600 -> 768
canvas.getContext("2d").drawImage(bitmap, 0, 0, canvas.width, canvas.height);
return new Promise((selesai) => canvas.toBlob(selesai, "image/jpeg", 0.85));
}
Math.min(1, ...)mencegah foto kecil diperbesar.toBlobmembuat file JPEG baru dari piksel. Upload lebih ringan, token lebih sedikit, dan server gak perlu menerima foto 4 MB.
Foto membawa lokasi: hapus EXIF
EXIF adalah blok metadata di dalam file JPEG (segmen APP1, penanda byte FF E1): merek kamera, waktu, dan sering kali koordinat GPS tempat foto diambil. Foto sampul yang dipotret di rumah membawa titik rumah pelanggan. Lab membuat JPEG sungguhan byte per byte: 362 byte, dengan blok EXIF 182 byte berisi GPS 6°12'37,2" S, 106°50'56,4" E (-6,210333, 106,849) dan waktu 2026:10:11 08:12:07.
function hapusExif(bytes) {
const hasil = [0xff, 0xd8]; // SOI: awal file JPEG
let i = 2;
while (i < bytes.length) {
const penanda = bytes[i + 1];
if (penanda === 0xda) { hasil.push(...bytes.slice(i)); break; } // SOS: data gambar sampai akhir
const panjang = (bytes[i + 2] << 8) | bytes[i + 3];
if (penanda !== 0xe1) hasil.push(...bytes.slice(i, i + 2 + panjang)); // APP1 (EXIF) dilewati
i += 2 + panjang;
}
return Uint8Array.from(hasil);
}
Hasilnya 180 byte, GPS-nya hilang, dan browser masih menggambarnya. Model gak membaca metadata (dokumentasi OpenAI dan Claude sama-sama bilang begitu), tapi file-nya lewat server-mu, tersimpan di storage, dan bisa tampil lagi, misalnya di ulasan. JPEG baru dari toBlob juga gak membawa EXIF (dicek di Chrome 155), tapi gak semua upload lewat canvas, jadi server tetap menghapusnya, misalnya dengan meng-encode ulang gambar.
Suara: dari dan ke teks
- Speech-to-text di server:
POST /v1/audio/transcriptionsdengangpt-transcribe, yang per Oktober 2026 disarankan OpenAI. File sampai 25 MB (mp3, mp4, mpeg, mpga, m4a, wav, webm), petunjuk bahasa lewatlanguages: ["id"], harganya $0,0045 per menit audio.whisper-1($0,006 per menit) dipakai kalau kamu butuh timestamp per kata atau terjemahan ke bahasa Inggris. - Text-to-speech di server:
POST /v1/audio/speechdengangpt-4o-mini-tts,voice(misalnyacoral), daninstructionsuntuk nada bicara; hasilnya MP3. Kebijakan OpenAI mewajibkan kamu memberi tahu pendengar bahwa suaranya buatan AI. - Di browser, gratis: Web Speech API.
speechSynthesismembacakan teks, ada di Chrome, Edge, Firefox, dan Safari; suaranya dari sistem operasi, jadi suara bahasa Indonesia tergantung perangkat.SpeechRecognition(mendengar) ada di Chrome dan Edge (tanpa awalan sejak Chrome 139), Safari sebagaiwebkitSpeechRecognition, dan Firefox baru di versi preview (data kompatibilitas MDN, Oktober 2026). Di Chrome, suaranya dikirim ke server pengenal suara kecualiprocessLocally = true.
const Pengenal = globalThis.SpeechRecognition ?? globalThis.webkitSpeechRecognition;
if (!Pengenal) tampilkanTombolRekam(); // rekam dengan MediaRecorder, kirim ke /api/transkripsi
speechSynthesis.speak(Object.assign(new SpeechSynthesisUtterance("Stok Laskar Pelangi 12."), { lang: "id-ID" }));
Dokumen PDF
Supplier mengirim daftar harga 12 halaman dalam PDF. OpenAI menerimanya sebagai { type: "input_file", filename: "harga.pdf", file_data: "data:application/pdf;base64,..." } (atau file_id, file_url); API mengambil teks dan gambar tiap halaman, dan tiap file harus di bawah 50 MB. Claude memakai { type: "document", source: { type: "base64", media_type: "application/pdf", data } }, maksimal 32 MB per request dan 600 halaman (100 kalau context window di bawah 1 juta token), sekitar 1.500 sampai 3.000 token teks per halaman ditambah token gambarnya. Minta hasilnya sebagai JSON dengan Structured Outputs (pelajaran AI-Powered Forms), lalu Bu Admin memeriksa sebelum katalog diperbarui.
Alt text: draf dari model, keputusan manusia
Model vision bisa menulis draf alt text dari foto produk: "Sampul buku oranye dengan pita judul gelap". Itu titik awal, bukan hasil akhir. Model bisa salah membaca judul, gak tahu konteks halaman, dan gak tahu gambar mana yang cuma hiasan (yang alt=""). Bu Admin membaca drafnya, membetulkannya jadi "Sampul novel Laskar Pelangi karya Andrea Hirata", baru disimpan. Sama untuk transkrip suara: tampilkan sebagai teks yang bisa dikoreksi.
⚠️ Jebakan yang sering ketemu
- Mengirim foto mentah. 1200 × 1600 = 2.494 token di Claude; dikecilkan ke 576 × 768 jadi 588. Kecilkan di browser, dan batasi ukuran upload di server.
- Format base64 tertukar. OpenAI butuh data URL lengkap (
data:image/jpeg;base64,...) diimage_url; Claude butuh base64 saja didataplusmedia_type. - Lupa EXIF. GPS rumah pelanggan ikut tersimpan. Hapus di client dan di server.
- Mengandalkan SpeechRecognition di semua browser. Firefox belum punya. Selalu sediakan input teks atau rekam lalu upload.
- Percaya mata model untuk stok, atau menayangkan alt text tanpa dibaca. Model membaca judul; stok dari SQL, alt text diperiksa manusia.
TL;DR: Model multi-modal memproses dan menghasilkan berbagai jenis data: teks, gambar, audio, PDF. Foto masuk lewat server-mu: OpenAI input_image dengan data URL di image_url (detail low, high, original, auto), Claude blok image dengan source base64 tanpa awalan plus media_type. Gambar dihitung per patch: OpenAI 32 px × 1,2 (perkiraan untuk gpt-6-luna, cek usage), Claude ⌈w/28⌉ × ⌈h/28⌉; foto 1200 × 1600 = 2.280 dan 2.494 token, dikecilkan ke 576 × 768 jadi 519 dan 588. Kecilkan dengan canvas sebelum upload, hapus EXIF (segmen APP1 berisi GPS) di client dan server. Suara: gpt-transcribe ($0,0045 per menit, languages: ["id"]), gpt-4o-mini-tts (beri tahu bahwa suaranya AI), atau Web Speech API di browser (speechSynthesis di mana-mana, SpeechRecognition belum di Firefox). PDF: input_file atau blok document, teks plus gambar tiap halaman. Model membaca, server memutuskan: stok dari SQL, alt text dan hasil ekstraksi diperiksa manusia.