Sematkan KorinAI di halaman HTML apa pun

Tambahkan widget chat KorinAI ke situs mana pun menggunakan skrip CDN tunggal. Tidak perlu framework.

Mulai Cepat

Tersedia Playground HTML siap pakai: Playground. Buka di browser untuk mencoba varian Floating vs Page dan salin kode embed yang dihasilkan.

Sertakan skrip

html
<!-- jsDelivr (disarankan) -->
<script src="https://cdn.jsdelivr.net/npm/@korinai/embed@latest/dist/embed.js"></script>
<!-- atau unpkg -->
<!-- <script src="https://unpkg.com/@korinai/embed@latest/dist/embed.js"></script> -->

Tambah elemen container

html
<div id="korin-floating-chat"></div>

Inisialisasi

Utamakan getAuthToken untuk token berumur pendek. Gunakan situs (origin) HTTPS.

html
<script>
  // window.KorinAI diekspos oleh build IIFE dari CDN
  window.KorinAI.init({
    target: "#korin-floating-chat",
    variant: "floating", // 'floating' | 'page'

    // Opsi provider
    baseUrl: "https://api.korinai.com",
    chatApi: "https://api.korinai.com/api/chat",
    language: "id",
    // authToken: "TOKEN_STATIS_ANDA",                // tidak direkomendasikan
    // getAuthToken: async () => "TOKEN_DINAMIS_ANDA", // direkomendasikan

    // Opsi bantu (opsional)
    ensureStyles: true,

    // Properti komponen (diteruskan)
    props: {
      title: "Chat dengan KorinAI",
      showFloatingButton: true,
      triggerIconSize: 28,
      // Bisa assign props PageChat
      variant: "flat",
      ui: { showAttach: true },
    },
  });

  // Jika perlu
  // window.KorinAI.unmount('#korin-floating-chat');
  // window.KorinAI.toggleFloatingChat(true);
</script>

Varian

  • Widget mengambang: variant: 'floating', mount ke elemen terposisi (mis. pojok kanan bawah).
  • Widget halaman penuh: variant: 'page', mount ke container konten biasa.

Anda bahkan bisa memasang keduanya:

html
<div id="korin-page-chat" style="min-height: 520px"></div>
<div
  id="korin-floating-chat"
  style="position: fixed; bottom: 24px; right: 24px"
></div>
<script>
  window.KorinAI.init({
    target: "#korin-page-chat",
    variant: "page",
    ensureStyles: false,
    baseUrl: "https://api.korinai.com",
    chatApi: "https://api.korinai.com/api/chat",
    language: "id",
    props: { variant: "flat" },
  });
  window.KorinAI.init({
    target: "#korin-floating-chat",
    variant: "floating",
    baseUrl: "https://api.korinai.com",
    chatApi: "https://api.korinai.com/api/chat",
    language: "id",
    props: { title: "Chat" },
  });
</script>

Catatan

  • Utamakan getAuthToken untuk token berumur pendek; hindari hardcode rahasia di HTML.
  • Layani skrip CDN melalui HTTPS dan dari origin tepercaya (jsDelivr atau unpkg).

Terjemahan

Anda dapat mengganti teks UI dengan memberikan objek translations (hanya kunci yang Anda perlukan):

html
<script>
  window.KorinAI.init({
    target: "#korin-floating-chat",
    baseUrl: "https://api.korinai.com",
    variant: "floating",
    language: "id",
    translations: {
      en: {
        startChat: "Start chat",
        thinking: "Thinking…",
        preparingExperience: "Setting things up for you…",
      },
      id: {
        startChat: "Mulai Obrolan",
        thinking: "Memproses…",
      },
    },
    props: { title: "Chat dengan KorinAI" },
  });
</script>

Untuk daftar lengkap kunci terjemahan, lihat tipe ChatTranslations di paket @korinai/libs.

Objek terjemahan chat default

Sumber kebenaran ada di packages/korin-libs/contexts/korinai-context.tsx sebagai KORIN_TRANSLATIONS.

ts
export const KORIN_TRANSLATIONS = {
  en: {
    startChat: "Start Chat",
    closeChat: "Close Chat",
    newChat: "New Chat",
    chatHistory: "Chat History",
    loadingConversation: "Loading conversation...",
    noChatHistory: "No chat history yet",
    startConversation: "Start a conversation to see it here",
    previous: "Previous",
    next: "Next",
    page: "Page",
    of: "of",
    thinking: "Thinking...",
    usingTool: "Using {toolName}...",
    attachedFile: "Attached file",
    sharedLink: "Shared a link",
    failedToLoadHistory: "Failed to load chat history",
    tryAgainLater: "Please try again later",
    ai: "AI",
    helloImYourAIAssistant:
      "Hello! I'm your AI assistant. How can I help you today? ",
    preparingExperience:
      "Preparing your chat experience… Please ensure your API URL and API key are configured.",
    templates: "Templates",
    fileSizeError: "File size must be less than 10MB",
    fileTypeError: "File type not supported",
    uploadSuccess: "File uploaded successfully",
    uploadFailed: "Upload failed",
    dropFile: "Drop your file here",
    retry: "Retry",
    selectAgent: "Select Agent",
    attachFile: "Attach File",
    stopGenerating: "Stop generating",
    sendMessage: "Send message",
    noCredits: "No credits available",
    selectFile: "Select File",
  },
  id: {
    startChat: "Mulai Obrolan",
    closeChat: "Tutup Obrolan",
    newChat: "Obrolan Baru",
    chatHistory: "Riwayat Obrolan",
    loadingConversation: "Memuat percakapan...",
    noChatHistory: "Belum ada riwayat obrolan",
    startConversation: "Mulai percakapan untuk melihatnya di sini",
    previous: "Sebelumnya",
    next: "Selanjutnya",
    page: "Halaman",
    of: "dari",
    thinking: "Memproses...",
    usingTool: "Menggunakan {toolName}...",
    attachedFile: "Berkas terlampir",
    sharedLink: "Membagikan tautan",
    failedToLoadHistory: "Gagal memuat riwayat obrolan",
    tryAgainLater: "Silakan coba lagi nanti",
    ai: "AI",
    helloImYourAIAssistant:
      "Halo! Saya asisten AI Anda. Ada yang bisa saya bantu? 👋",
    preparingExperience:
      "Menyiapkan pengalaman chat Anda… Pastikan URL API dan kunci API Anda telah dikonfigurasi.",
    templates: "Template",
    fileSizeError: "Ukuran file harus kurang dari 10MB",
    fileTypeError: "Tipe file tidak didukung",
    uploadSuccess: "File berhasil diunggah",
    uploadFailed: "Gagal mengunggah",
    dropFile: "Letakkan file Anda di sini",
    retry: "Coba Lagi",
    selectAgent: "Pilih Agen",
    attachFile: "Lampirkan File",
    stopGenerating: "Hentikan pembuatan",
    sendMessage: "Kirim pesan",
    noCredits: "Kredit tidak tersedia",
    selectFile: "Pilih File",
  },
} as const;

Pemecahan masalah

  • Gaya/posisi aneh: setel ensureStyles: true atau sertakan embed.css dari CDN.
  • Error autentikasi: utamakan getAuthToken dan pastikan issuer, scope, serta kedaluwarsa token benar.
  • Tidak ada pesan: periksa baseUrl, chatApi (seharusnya https://api.korinai.com/api/chat), dan Network Console.
  • Banyak mount: Anda bisa memanggil KorinAI.init dua kali (target berbeda). Gunakan KorinAI.unmount(target) untuk melepas.

Referensi

Gunakan opsi paling penting berikut; detail lengkap tipe tersedia di paket sumber @korinai/embed (TypeScript types):

  • target: elemen atau selector CSS tempat mount.
  • variant: 'floating' atau 'page'.
  • props: properti yang diteruskan ke komponen.
  • baseUrl, chatApi, language.
  • authToken atau getAuthToken (disarankan).
  • translations untuk menimpa teks UI.

InitOptions

PropTipeDeskripsi
targetElement | stringElemen atau selector CSS tempat mount.
variant'floating' | 'page'Varian UI yang dirender. Default: 'floating'.
propsRecord<string, unknown>Props yang diteruskan ke komponen yang dirender. Default: {}.
ensureStylesbooleanSisipkan styling/posisi minimum agar terlihat. Default: true.
debugOverlaybooleanTampilkan badge kecil “mounted” untuk debug. Default: false.
stylesheetHrefstring | string[]Muat stylesheet eksternal bila perlu.
verbosebooleanLog detail ke console. Default: false.
baseUrlstringBase URL API untuk provider.
chatApistringEndpoint Chat API.
configLanguagestringField bahasa konfigurasi provider (lanjutan).
minimumCreditsWarningstringAmbang peringatan kredit rendah.
authTokenstringToken statis. Utamakan getAuthToken.
languagestringProperti bahasa untuk provider.
getAuthToken() => Promise<string>Pengambil token async.
translationsChatTranslationsPeta i18n opsional untuk menimpa teks bawaan.

Props FloatingChat

PropTipeDeskripsi
titlestringJudul chat di header.
triggerIconReactNodeKonten pemicu kustom (mengganti ikon default).
triggerIconSizenumberUkuran ikon pemicu (px). Default: 28.
branding{ logoLightUrl?, logoDarkUrl?, logoSize?: {width:number; height:number}, headerLogoSize?: {width:number; height:number}, showHeaderLogo? }Opsi branding untuk UI.
buttonClassNamestringKelas tambahan untuk wrapper tombol mengambang.
chatWindowClassNamestringKelas tambahan untuk kontainer jendela chat.
openbooleanState terbuka terkontrol. Pasangkan dengan onOpenChange.
defaultOpenbooleanState terbuka awal (uncontrolled). Default: false.
onOpenChange(open: boolean) => voidDipanggil saat state open berubah.
showFloatingButtonbooleanApakah tombol pemicu mengambang ditampilkan. Default: true.
classNamestringKelas CSS tambahan untuk kontainer luar.
titlestringTeks judul header.
showCloseButtonbooleanTampilkan tombol tutup. Default: false.
onClose() => voidDipanggil saat tombol tutup diklik.
hideHistorybooleanSembunyikan daftar riwayat. Default: false.
pageSizenumberUkuran halaman riwayat. Default: 10.
defaultRoomIdstringRoom id awal.
showRoomNamebooleanTampilkan nama room saat ini. Default: true.
onRoomChange(roomId: string) => voidNotifikasi perubahan room.
onSend({ text: string, roomId: string }) => voidDipanggil saat kirim pesan.
headerRightSlotReactNodeKonten kustom di kanan header.
variant'card' | 'flat'Gaya visual. Default: 'flat'.
chatInputVariant'default' | 'compact'Preset kerapatan input.
throttleMsnumberThrottle ketik/kirim pengguna. Default: 0.
requestHeadersRecord<string,string>Header ekstra untuk panggilan API. Default: {}.
requestBody{ requesterId?, participantEmail?, participantId?, roomId?, gallery_id?, file_caption?, file_url?, extra_context?, requesterEmail?, messageId?, secrets?: Array<{key:string; value:string}> }Field body tambahan untuk panggilan API. Default: {}.
ui{ showStop?, showAttach?, showActions?, showAgentSelector?, defaultAgentUsername? }Toggle fitur UI.
branding{ logoLightUrl?, logoDarkUrl?, logoSize?: {width:number; height:number}, showHeaderLogo?, headerLogoSize?: {width:number; height:number} }Branding header dan konten.

Props PageChat

PropTipeDeskripsi
classNamestringKelas CSS tambahan untuk kontainer luar.
titlestringTeks judul header.
showCloseButtonbooleanTampilkan tombol tutup. Default: false.
onClose() => voidDipanggil saat tombol tutup diklik.
hideHistorybooleanSembunyikan daftar riwayat. Default: false.
pageSizenumberUkuran halaman riwayat. Default: 10.
defaultRoomIdstringRoom id awal.
showRoomNamebooleanTampilkan nama room saat ini. Default: true.
onRoomChange(roomId: string) => voidNotifikasi perubahan room.
onSend({ text: string, roomId: string }) => voidDipanggil saat kirim pesan.
headerRightSlotReactNodeKonten kustom di kanan header.
variant'card' | 'flat'Gaya visual. Default: 'flat'.
chatInputVariant'default' | 'compact'Preset kerapatan input.
throttleMsnumberThrottle ketik/kirim pengguna. Default: 0.
requestHeadersRecord<string,string>Header ekstra untuk panggilan API. Default: {}.
requestBody{ requesterId?, participantEmail?, participantId?, roomId?, gallery_id?, file_caption?, file_url?, extra_context?, requesterEmail?, messageId?, secrets?: Array<{key:string; value:string}> }Field body tambahan untuk panggilan API. Default: {}.
ui{ showStop?, showAttach?, showActions?, showAgentSelector?, defaultAgentUsername? }Toggle fitur UI.
branding{ logoLightUrl?, logoDarkUrl?, logoSize?: {width:number; height:number}, showHeaderLogo?, headerLogoSize?: {width:number; height:number} }Branding header dan konten.

API Publik

  • KorinAI.init(options) → { unmount(): void; el: Element }
  • KorinAI.unmount(target)
  • KorinAI.toggleFloatingChat(open?: boolean)
  • Global varian: window.KorinAI.floating, window.KorinAI.page berisi __open, reload(newOptions?), dan bidang diagnostik seperti __version?, __verbose?.

Contoh:

html
<script>
  const { unmount } = window.KorinAI.init({
    target: "#korin-floating-chat",
    variant: "floating",
    baseUrl,
    chatApi,
  });
  // Kemudian
  window.KorinAI.toggleFloatingChat(true);
  unmount();
  // Muat ulang varian floating dengan properti baru saat runtime
  window.KorinAI.floating.reload({ props: { showFloatingButton: false } });
</script>