ASAL AI

Chatbot AI Pertamamu

Bangun chatbot web dengan streaming jawaban real-time: Next.js, satu API route, satu komponen chat. Fondasi untuk semua project lain.

Next.jsTypeScriptAPI AI (OpenAI-compatible)≈ 45 menit

Kamu akan membangun chatbot yang jawabannya muncul kata demi kata (streaming) — persis seperti ChatGPT. Ini project fondasi: semua project lain di situs ini dibangun di atas polanya.

0. Prasyarat

  • Node.js terpasang, paham dasar React/Next.js.
  • API key dari provider apa pun yang kompatibel OpenAI (OpenAI, Gemini OpenAI-compat, GLM, dll).

1. Siapkan project dan kunci

npx create-next-app@latest chatbotku --typescript --app --src-dir
cd chatbotku

Buat file .env.local:

AI_BASE_URL=https://api.openai.com/v1
AI_API_KEY=sk-...
AI_MODEL=gpt-4o-mini

Penting: key hanya di server. Jangan pernah dipanggil dari komponen browser.

2. API route streaming

Buat src/app/api/chat/route.ts:

export async function POST(req: Request) {
  const { messages } = await req.json();

  const res = await fetch(
    `${process.env.AI_BASE_URL}/chat/completions`,
    {
      method: "POST",
      headers: {
        "content-type": "application/json",
        authorization: `Bearer ${process.env.AI_API_KEY}`,
      },
      body: JSON.stringify({
        model: process.env.AI_MODEL,
        messages,
        stream: true,
      }),
    }
  );

  return new Response(res.body, {
    headers: { "content-type": "text/plain; charset=utf-8" },
  });
}

Kita tidak mengubah data provider sama sekali — cukup meneruskan stream-nya.

3. Komponen chat yang membaca stream

Inti pola streaming di browser: baca potongan dari fetch, tambahkan ke state.

"use client";
import { useState } from "react";

export function Chat() {
  const [messages, setMessages] = useState<{role: string; content: string}[]>([]);
  const [input, setInput] = useState("");
  const [busy, setBusy] = useState(false);

  async function kirim() {
    const history = [...messages, { role: "user", content: input }];
    setMessages([...history, { role: "assistant", content: "" }]);
    setInput("");
    setBusy(true);

    const res = await fetch("/api/chat", {
      method: "POST",
      body: JSON.stringify({ messages: history }),
    });
    const reader = res.body!.getReader();
    const decoder = new TextDecoder();

    for (;;) {
      const { done, value } = await reader.read();
      if (done) break;
      const chunk = decoder.decode(value);
      setMessages((prev) => {
        const last = prev[prev.length - 1];
        return [...prev.slice(0, -1),
          { role: "assistant", content: last.content + chunk }];
      });
    }
    setBusy(false);
  }

  return (
    <div>
      {messages.map((m, i) => <p key={i}><b>{m.role}:</b> {m.content}</p>)}
      <input value={input} onChange={(e) => setInput(e.target.value)} />
      <button onClick={kirim} disabled={busy}>Kirim</button>
    </div>
  );
}

4. Tambahkan persona

Di API route, sisipkan system prompt sebelum messages dari user:

const withSystem = [
  { role: "system", content: "Kamu asisten ramah berbahasa Indonesia. Jawab singkat dan jelas." },
  ...messages,
];

Jalankan npm run dev — chatbot kamu hidup, dengan jawaban mengalir real-time.

5. Pola selesai. Tantangan lanjutan

  • Simpan riwayat percakapan di localStorage.
  • Batasi panjang riwayat (ingat materi context window).
  • Tambahkan tombol stop (pakai AbortController).
  • Rate limit sederhana di API route (lihat pola di situs ini — kita pakai window per-IP).