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

| Prop | Tipe | Deskripsi | | ----------------------- | ------------------------- | --------------------------------------------------------------- | | target | Element \| string | Elemen atau selector CSS tempat mount. | | variant | 'floating' \| 'page' | Varian UI yang dirender. Default: 'floating'. | | props | Record<string, unknown> | Props yang diteruskan ke komponen yang dirender. Default: {}. | | ensureStyles | boolean | Sisipkan styling/posisi minimum agar terlihat. Default: true. | | debugOverlay | boolean | Tampilkan badge kecil “mounted” untuk debug. Default: false. | | stylesheetHref | string \| string[] | Muat stylesheet eksternal bila perlu. | | verbose | boolean | Log detail ke console. Default: false. | | baseUrl | string | Base URL API untuk provider. | | chatApi | string | Endpoint Chat API. | | configLanguage | string | Field bahasa konfigurasi provider (lanjutan). | | minimumCreditsWarning | string | Ambang peringatan kredit rendah. | | authToken | string | Token statis. Utamakan getAuthToken. | | language | string | Properti bahasa untuk provider. | | getAuthToken | () => Promise<string> | Pengambil token async. | | translations | ChatTranslations | Peta i18n opsional untuk menimpa teks bawaan. |

Props FloatingChat

| Prop | Tipe | Deskripsi | | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- | | title | string | Judul chat di header. | | triggerIcon | ReactNode | Konten pemicu kustom (mengganti ikon default). | | triggerIconSize | number | Ukuran ikon pemicu (px). Default: 28. | | branding | { logoLightUrl?, logoDarkUrl?, logoSize?: {width:number; height:number}, headerLogoSize?: {width:number; height:number}, showHeaderLogo? } | Opsi branding untuk UI. | | buttonClassName | string | Kelas tambahan untuk wrapper tombol mengambang. | | chatWindowClassName | string | Kelas tambahan untuk kontainer jendela chat. | | open | boolean | State terbuka terkontrol. Pasangkan dengan onOpenChange. | | defaultOpen | boolean | State terbuka awal (uncontrolled). Default: false. | | onOpenChange | (open: boolean) => void | Dipanggil saat state open berubah. | | showFloatingButton | boolean | Apakah tombol pemicu mengambang ditampilkan. Default: true. | | className | string | Kelas CSS tambahan untuk kontainer luar. | | title | string | Teks judul header. | | showCloseButton | boolean | Tampilkan tombol tutup. Default: false. | | onClose | () => void | Dipanggil saat tombol tutup diklik. | | hideHistory | boolean | Sembunyikan daftar riwayat. Default: false. | | pageSize | number | Ukuran halaman riwayat. Default: 10. | | defaultRoomId | string | Room id awal. | | showRoomName | boolean | Tampilkan nama room saat ini. Default: true. | | onRoomChange | (roomId: string) => void | Notifikasi perubahan room. | | onSend | ({ text: string, roomId: string }) => void | Dipanggil saat kirim pesan. | | headerRightSlot | ReactNode | Konten kustom di kanan header. | | variant | 'card' \| 'flat' | Gaya visual. Default: 'flat'. | | chatInputVariant | 'default' \| 'compact' | Preset kerapatan input. | | throttleMs | number | Throttle ketik/kirim pengguna. Default: 0. | | requestHeaders | Record<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

| Prop | Tipe | Deskripsi | | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | | className | string | Kelas CSS tambahan untuk kontainer luar. | | title | string | Teks judul header. | | showCloseButton | boolean | Tampilkan tombol tutup. Default: false. | | onClose | () => void | Dipanggil saat tombol tutup diklik. | | hideHistory | boolean | Sembunyikan daftar riwayat. Default: false. | | pageSize | number | Ukuran halaman riwayat. Default: 10. | | defaultRoomId | string | Room id awal. | | showRoomName | boolean | Tampilkan nama room saat ini. Default: true. | | onRoomChange | (roomId: string) => void | Notifikasi perubahan room. | | onSend | ({ text: string, roomId: string }) => void | Dipanggil saat kirim pesan. | | headerRightSlot | ReactNode | Konten kustom di kanan header. | | variant | 'card' \| 'flat' | Gaya visual. Default: 'flat'. | | chatInputVariant | 'default' \| 'compact' | Preset kerapatan input. | | throttleMs | number | Throttle ketik/kirim pengguna. Default: 0. | | requestHeaders | Record<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>