🎓

AI Web App Course

reankh.org · Google AI Studio · Supabase

ទំនាក់ទំនង Admin · ទទួល Code

លោក ហុន ម៉ុម · @mrhonmom

មាតិការ

🎓

AI Course · reankh.org

🏁 ផ្នែកទី ១

សៀវភៅសិក្សា AI Web App

វគ្គនេះ អ្នកនឹងរៀនបង្កើត Website ដែលមាន AI ពិតៗ — មានប្រព័ន្ធ Login, Chat ជាមួយ Gemini AI, Save ទិន្នន័យ, ហើយ Deploy ដាក់ Online។ មិនចាំបាច់មានបទពិសោធន៍ Programming ច្រើនទេ — AI Studio នឹងជួយ Generate Code ឲ្យ!

🤖

Gemini AI

Chat · Vision

🔐

Supabase Auth

Login ពិត

💾

Database

Save History

🚀

Deploy Vercel

Online ១០០%

🔄 វិធីធ្វើការ (Workflow) របស់វគ្គនេះ

ចូល Google AI Studio

សរសេរ Prompt ប្រាប់ AI ថាចង់ធ្វើអ្វី → AI Generate Code ឲ្យ

Copy Code ពី AI Studio

យក Code ដែល AI Generate → Paste ក្នុង VS Code

Run & Test ក្នុង VS Code

ប្រើ Terminal ក្នុង VS Code → npm run dev → មើលលទ្ធផល

Deploy ដាក់ Online

Push Code ទៅ GitHub → Vercel Deploy ស្វ័យប្រវត្តិ

📌 Goal: Website ពិត · Login · AI Chat · Save ទិន្នន័យ · Deploy Online ឃើញពី Internet
💻 ផ្នែកទី ២

ដំឡើង Software & គណនី

មុននឹងចាប់ផ្ដើម ត្រូវ Install Software ទាំង ៤ នេះ និង Create Account ១ ចំនួន

① Install Software

🟦

Visual Studio Code (VS Code)

កម្មវិធីសរសេរ Code — ដូច Word ប៉ុន្តែសម្រាប់ Programming

🌐 code.visualstudio.com → Download → Install
🟩

Node.js (v20 ឬ v22)

ជា Engine សម្រាប់ Run JavaScript Code — ត្រូវការ npm ផង

🌐 nodejs.org → Download LTS → Install

✅ ពិនិត្យ: បើក Terminal វាយ node -v → ត្រូវឃើញ v20.x ឬ v22.x

🐱

Git

ប្រព័ន្ធ Save & Upload Code ទៅ GitHub

🌐 git-scm.com → Download → Install (Next Next Next Finish)

✅ ពិនិត្យ: វាយ git --version ក្នុង Terminal

② Create Accounts

🤖 Google AI Studio

aistudio.google.com — ប្រើ Gmail ចូល

➜ ទៅ Get API Key → Create API Key

🐱 GitHub

github.com — ចុះឈ្មោះ ១ ដង

➜ ប្រើ Email + Password

▲ Vercel

vercel.com — Login ជាមួយ GitHub

➜ Free tier គ្រប់គ្រាន់

🔷 Supabase

supabase.com — ប្រើ Project ដែលមានហើយ

➜ Copy URL + Anon Key ពី Settings → API

③ ដំឡើង Gemini Extension ក្នុង VS Code

1

បើក VS Code → ចុចរូបភាព Extensions ខាងឆ្វេង (ឬ Ctrl+Shift+X)

2

Search ថា "Gemini Code Assist" → ចុច Install

3

ចុចរូប Gemini ខាងឆ្វេង → Sign in with Google → Login ជាមួយ Gmail

4

ឥឡូវ Gemini AI នៅក្នុង VS Code ហើយ — អាចសួរ Code ណាក៏បាន!

💡 Gemini ក្នុង VS Code ជួយ Auto-complete Code, ពន្យល់ Error, ហើយ Generate Code ដោយ Chat ដូច AI Studio
🤖 ផ្នែកទី ៣

របៀបប្រើ Google AI Studio

AI Studio ជា Tool ដ៏ទន់ខ្លាំង — ប្រាប់វា ចង់ធ្វើអ្វី → វា Generate Code ឲ្យ Complete

① Get API Key

1

ចូល aistudio.google.com → Login ជាមួយ Gmail

2

ចុច "Get API key" ខាងឆ្វេងលើ → "Create API key"

3

Copy Key ចេញ (ចាប់ផ្ដើម AIzaSy...) → Save ទុក

⚠️ API Key ហាមចែករំលែក! ប្រើជា .env.local variable ប៉ុណ្ណោះ

② Generate Code ពី AI Studio

វិធីល្អបំផុតគឺ ប្រាប់ AI ឲ្យ Generate Code ពេញ ហើយ Copy Paste ទៅ VS Code

✏️ ឧទាហរណ៍ Prompt ល្អ:

"Create a Next.js 14 app router page at app/chat/page.js that has a chat UI with Gemini AI. It should have a text input, send button, and display messages. Use Tailwind CSS for styling. The API route should be at app/api/chat/route.js using @google/generative-ai package with model gemini-2.0-flash."

1

ចូល AI Studio → ចុច "New Prompt""Chat"

2

Select Model: Gemini 2.0 Flash (លឿន + ខ្លាំង)

3

វាយ Prompt ពន្យល់ Code ដែលចង់បាន → ចុច Send

4

AI Generate Code → ចុច Copy → Paste ក្នុង VS Code File

5

បើមាន Error → Copy Error Message → Paste ត្រឡប់ក្នុង AI Studio → សួរ "Fix this error"

💡 Tips: ប្រាប់ AI Studio ឲ្យ Generate ទាំង Frontend (page.js) និង Backend (route.js) ជាមួយគ្នា — Code នឹង Match គ្នាល្អ
📁 ផ្នែកទី ៤

បង្កើត Project & Run ដំបូង

ជំហានទាំងនេះ Run ម្ដង ១ ប៉ុណ្ណោះ — ដើម្បីបង្កើត Folder Project

① បើក Terminal

Windows:

ចុច Windows Key → វាយ cmd → Enter — ឬបើក VS Code → Menu Terminal → New Terminal

Mac:

ចុច Cmd+Space → វាយ Terminal → Enter — ឬបើក VS Code → Menu Terminal → New Terminal

💡 ល្អបំផុត: ប្រើ Terminal ក្នុង VS Code ដោយផ្ទាល់ — ចុច Ctrl + ` (backtick) ឬ Menu Terminal → New Terminal

② ជ្រើស Folder ដែលចង់ Store Project

1

ក្នុង Terminal វាយ Command ទៅ Folder ដែលចង់ Store:

# Windows — ទៅ Desktop
cd C:\Users\YourName\Desktop

# Mac — ទៅ Desktop
cd ~/Desktop
2

បង្កើត Folder ថ្មី (ហៅថា my-projects):

mkdir my-projects
cd my-projects

③ Create Next.js Project

Command នេះ Create Project ស្វ័យប្រវត្តិ — Download ខ្លួន Next.js + Tailwind + Setup ទាំងអស់

npx create-next-app@latest ai-webapp --js --tailwind --app --no-src-dir --no-eslint

👉 វានឹងសួរ Question ចំនួន ២-៣ — ចុច Enter ទាំងអស់ (Default)

👉 រង់ចាំ Download ២-៣ នាទី (Internet ចាំបាច់)

👉 ឃើញ Success! → Project Created!

④ ចូល Folder Project & Install Packages

cd ai-webapp
npm install @google/generative-ai @supabase/supabase-js

👉 Command ដំបូង: ចូល Folder Project | Command ទី២: Install Library Gemini + Supabase

⑤ បើក VS Code ក្នុង Project Folder

code .

👉 code . មានន័យថា "បើក VS Code ក្នុង Folder បច្ចុប្បន្ន" — VS Code នឹងបើកស្វ័យប្រវត្តិ

⑥ បង្កើត File .env.local

ក្នុង VS Code → បង្កើត File ថ្មី ហៅថា .env.local ក្នុង Root Folder (ជាប់ package.json)

NEXT_PUBLIC_GEMINI_API_KEY=AIzaSy_YOUR_KEY_HERE
NEXT_PUBLIC_SUPABASE_URL=https://YOUR_PROJECT_ID.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
GEMINI_API_KEY=AIzaSy_YOUR_KEY_HERE

Gemini API Key:

AI Studio → Get API Key → Create API Key → Copy

Supabase URL + Key:

Supabase Dashboard → Settings → API → Copy

⑦ Run Project ដំបូង!

npm run dev

👉 ឃើញ Local: http://localhost:3000 → បើក Chrome → ចូល localhost:3000

⚠️ .env.local ហាម Push ទៅ GitHub — Add ក្នុង .gitignore (Next.js Auto-Add ហើយ)

📁 Project Structure (ទ្រង់ទ្រាយ Folder)

ai-webapp/
├── app/
│   ├── layout.js          ← Template ទូទៅ (Header/Footer)
│   ├── page.js            ← Homepage /
│   ├── login/
│   │   └── page.js        ← /login page
│   ├── dashboard/
│   │   └── page.js        ← /dashboard page
│   ├── chat/
│   │   └── page.js        ← /chat page (AI Chat UI)
│   └── api/
│       ├── chat/
│       │   └── route.js   ← API /api/chat (Gemini)
│       └── vision/
│           └── route.js   ← API /api/vision (Image AI)
├── lib/
│   ├── supabase.js        ← Supabase Client
│   └── gemini.js          ← Gemini Helper
├── .env.local             ← API Keys (SECRET!)
├── package.json           ← Dependencies
└── next.config.js         ← Next.js Config
💡 Folder ក្នុង app/ = URL path — app/login/page.js = localhost:3000/login
🔐 ផ្នែកទី ៥

Supabase Auth — Login System

Supabase ផ្ដល់ Login System ដែល Ready-Made — អ្នកគ្រាន់ Connect ហើយ Call Function ប៉ុណ្ណោះ

① Connect Supabase

បង្កើត File lib/supabase.js → Paste Code នេះ:

// lib/supabase.js
import { createClient } from '@supabase/supabase-js'

export const supabase = createClient(
  process.env.NEXT_PUBLIC_SUPABASE_URL,
  process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY
)

② Login Page

បង្កើត Folder app/login/ → បង្កើត File page.js → Paste Code:

// app/login/page.js
'use client'
import { useState } from 'react'
import { useRouter } from 'next/navigation'
import { supabase } from '@/lib/supabase'

export default function LoginPage() {
  const router = useRouter()
  const [email, setEmail]       = useState('')
  const [password, setPassword] = useState('')
  const [loading, setLoading]   = useState(false)
  const [error, setError]       = useState('')

  async function handleLogin(e) {
    e.preventDefault()  // ឈប់ Page Reload
    setLoading(true)
    setError('')

    const { error } = await supabase.auth.signInWithPassword({
      email,
      password
    })

    if (error) {
      setError('Email ឬ Password មិនត្រឹមត្រូវ!')
    } else {
      router.push('/dashboard')  // ទៅ Dashboard
    }
    setLoading(false)
  }

  return (
    <div className="min-h-screen flex items-center justify-center bg-gray-900">
      <form onSubmit={handleLogin} className="bg-gray-800 p-8 rounded-2xl w-full max-w-sm">
        <h1 className="text-2xl font-bold text-white mb-6">Login</h1>

        <input
          type="email"
          placeholder="Email"
          value={email}
          onChange={e => setEmail(e.target.value)}
          className="w-full bg-gray-700 text-white px-4 py-3 rounded-xl mb-3 outline-none"
          required
        />

        <input
          type="password"
          placeholder="Password"
          value={password}
          onChange={e => setPassword(e.target.value)}
          className="w-full bg-gray-700 text-white px-4 py-3 rounded-xl mb-4 outline-none"
          required
        />

        {error && <p className="text-red-400 text-sm mb-3">{error}</p>}

        <button
          type="submit"
          disabled={loading}
          className="w-full bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 rounded-xl"
        >
          {loading ? 'កំពុង Login...' : 'Login'}
        </button>
      </form>
    </div>
  )
}

③ ពន្យល់ Code សំខាន់ៗ

'use client'

ប្រាប់ Next.js ថា File នេះ Run ក្នុង Browser (ចាំបាច់សម្រាប់ useState, onClick)

useState('')

Variable ដែល Track ការផ្លាស់ប្ដូរ — ពេល User វាយ Email, email variable Update

supabase.auth.signInWithPassword()

Supabase Function សម្រាប់ Login — Return error ប្រសិនបើ Email/Password ខុស

router.push('/dashboard')

ប្ដូរ URL ទៅ /dashboard — ដូច Click Link ប៉ុន្តែ Code ធ្វើ

💡 AI Studio Prompt: "Generate a Next.js login page with Supabase auth, email/password, with error handling and loading state, Tailwind dark theme"
🤖 ផ្នែកទី ៦

Gemini AI Chat

ភ្ជាប់ Gemini AI ក្នុង App — User Chat → AI ឆ្លើយ — ដូច ChatGPT!

① API Route (Backend)

បង្កើត Folder app/api/chat/ → File route.js:

// app/api/chat/route.js
import { GoogleGenerativeAI } from '@google/generative-ai'

// Initialize Gemini
const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY)

export async function POST(request) {
  try {
    // ទទួល Message ពី Frontend
    const { message, history } = await request.json()

    // Select Model
    const model = genAI.getGenerativeModel({ model: 'gemini-2.0-flash' })

    // Start Chat Session ជាមួយ History
    const chat = model.startChat({
      history: history || []  // Previous messages
    })

    // Send Message → Get Reply
    const result = await chat.sendMessage(message)
    const reply  = result.response.text()

    return Response.json({ reply })

  } catch (error) {
    console.error('Gemini Error:', error)
    return Response.json({ error: 'AI Error!' }, { status: 500 })
  }
}

② Chat UI (Frontend)

បង្កើត app/chat/page.js:

// app/chat/page.js
'use client'
import { useState } from 'react'

export default function ChatPage() {
  const [messages, setMessages] = useState([])
  const [input, setInput]       = useState('')
  const [loading, setLoading]   = useState(false)

  async function sendMessage() {
    if (!input.trim() || loading) return

    const userMsg = input.trim()
    setInput('')  // Clear input

    // Add User Message to UI
    const newMessages = [...messages, { role: 'user', text: userMsg }]
    setMessages(newMessages)
    setLoading(true)

    try {
      // Build History format for Gemini
      const history = messages.map(m => ({
        role:  m.role === 'user' ? 'user' : 'model',
        parts: [{ text: m.text }]
      }))

      // Call API
      const res  = await fetch('/api/chat', {
        method:  'POST',
        headers: { 'Content-Type': 'application/json' },
        body:    JSON.stringify({ message: userMsg, history })
      })
      const data = await res.json()

      // Add AI Reply to UI
      setMessages([...newMessages, { role: 'ai', text: data.reply }])

    } catch (err) {
      setMessages([...newMessages, { role: 'ai', text: 'Error! សូម Try Again' }])
    }
    setLoading(false)
  }

  return (
    <div className="min-h-screen bg-gray-900 flex flex-col">
      <h1 className="text-white text-2xl font-bold p-4">AI Chat</h1>

      {/* Messages */}
      <div className="flex-1 overflow-y-auto p-4 space-y-3">
        {messages.map((msg, i) => (
          <div key={i} className={`flex ${msg.role === 'user' ? 'justify-end' : 'justify-start'}`}>
            <div className={`max-w-xs px-4 py-2 rounded-2xl text-sm ${
              msg.role === 'user'
                ? 'bg-blue-600 text-white'
                : 'bg-gray-700 text-gray-100'
            }`}>
              {msg.text}
            </div>
          </div>
        ))}
        {loading && (
          <div className="flex justify-start">
            <div className="bg-gray-700 text-gray-400 px-4 py-2 rounded-2xl text-sm">
              AI កំពុងគិត...
            </div>
          </div>
        )}
      </div>

      {/* Input */}
      <div className="p-4 flex gap-2">
        <input
          value={input}
          onChange={e => setInput(e.target.value)}
          onKeyDown={e => e.key === 'Enter' && sendMessage()}
          placeholder="សួរ AI..."
          className="flex-1 bg-gray-700 text-white px-4 py-3 rounded-xl outline-none"
        />
        <button
          onClick={sendMessage}
          disabled={loading}
          className="bg-blue-600 text-white px-6 py-3 rounded-xl font-bold"
        >
          ផ្ញើ
        </button>
      </div>
    </div>
  )
}

③ Test Chat

1

Run: npm run dev → ចូល localhost:3000/chat

2

វាយ Message → ចុច "ផ្ញើ" → AI ត្រូវ Reply ក្នុង ២-៣ វិនាទី

3

បើ Error ក្នុង Terminal → Copy Error → Paste ក្នុង AI Studio → "Fix this"

💾 ផ្នែកទី ៧

Save Chat History ទៅ Supabase

Save Conversation ទុក Database ដើម្បី User Reload Page ហើយ History នៅដដែល

① Run SQL ក្នុង Supabase

Supabase Dashboard → SQL Editor → New Query → Paste SQL នេះ → ចុច Run:

-- Table Save Chat History
CREATE TABLE IF NOT EXISTS ai_chats (
  id         UUID    DEFAULT gen_random_uuid() PRIMARY KEY,
  user_id    UUID    REFERENCES auth.users(id) ON DELETE CASCADE,
  role       TEXT    NOT NULL CHECK (role IN ('user','model')),
  message    TEXT    NOT NULL,
  created_at TIMESTAMPTZ DEFAULT NOW()
);

-- Security: User ឃើញតែ Chats ខ្លួនឯង
ALTER TABLE ai_chats ENABLE ROW LEVEL SECURITY;

CREATE POLICY "User owns chats"
  ON ai_chats FOR ALL
  USING     (auth.uid() = user_id)
  WITH CHECK (auth.uid() = user_id);

② Save Message Function

បន្ថែម Save ទៅ Chat Route:

// app/api/chat/route.js — Version ដែល Save History
import { GoogleGenerativeAI } from '@google/generative-ai'
import { createClient } from '@supabase/supabase-js'

const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY)

export async function POST(request) {
  const { message, history, userId } = await request.json()

  const model  = genAI.getGenerativeModel({ model: 'gemini-2.0-flash' })
  const chat   = model.startChat({ history: history || [] })
  const result = await chat.sendMessage(message)
  const reply  = result.response.text()

  // Save to Supabase (ប្រសិនបើ userId មាន)
  if (userId) {
    const supabase = createClient(
      process.env.NEXT_PUBLIC_SUPABASE_URL,
      process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY
    )
    // Save User Message
    await supabase.from('ai_chats').insert({ user_id: userId, role: 'user',  message })
    // Save AI Reply
    await supabase.from('ai_chats').insert({ user_id: userId, role: 'model', message: reply })
  }

  return Response.json({ reply })
}
💡 Load History: ពេល Page Load → Query ai_chats ដែល user_id = current user → Show ក្នុង UI
🚀 ផ្នែកទី ៨

Deploy ដាក់ Online — Vercel

Deploy ៣ ជំហាន: GitHub Push → Vercel Import → Add Env Vars → Done!

① Push Code ទៅ GitHub

1

ចូល github.com → New Repository → ដាក់ឈ្មោះ ai-webapp → Create

2

Run Command ទាំងនេះ ក្នុង Terminal (ក្នុង Folder Project):

git init
git add .
git commit -m "first commit"
git branch -M main
git remote add origin https://github.com/YOUR_USERNAME/ai-webapp.git
git push -u origin main
⚠️ Replace YOUR_USERNAME ជា GitHub Username របស់អ្នក

② Import ក្នុង Vercel

1

ចូល vercel.com → Login → "Add New Project"

2

Import from GitHub → ជ្រើស Repository ai-webapp

3

Environment Variables Section → Add ទាំង ៤ នេះ:

GEMINI_API_KEY = AIzaSy...

NEXT_PUBLIC_GEMINI_API_KEY = AIzaSy...

NEXT_PUBLIC_SUPABASE_URL = https://...supabase.co

NEXT_PUBLIC_SUPABASE_ANON_KEY = eyJhbGci...

4

ចុច "Deploy" → រង់ចាំ ១-២ នាទី → ✅ Website Live!

③ Auto Deploy ពេលក្រោយ

ពេល Push Code ថ្មី → Vercel Auto Deploy ស្វ័យប្រវត្តិ:

git add .
git commit -m "update: add new feature"
git push
💡 ក្រោយ Push → ចូល Vercel Dashboard → Deployments → ឃើញ Deploy ថ្មីកំពុងដំណើរការ
🔧 ផ្នែកទី ៩

Error ទូទៅ & ដំណោះស្រាយ

Error ជាបញ្ហាធម្មតា — ធ្វើ Programmer ល្អ ត្រូវចេះ Debug

❌ Module not found: '@google/generative-ai'

Package មិន Install ទេ

npm install @google/generative-ai

❌ Invalid API Key / 400 Error

API Key ខុស ឬ .env.local មិន Set

✅ ពិនិត្យ .env.local — Key ត្រូវមាន GEMINI_API_KEY=AIzaSy...

❌ "use client" required / Hook Error

File ប្រើ useState/onClick ប៉ុន្តែ គ្មាន 'use client' ខាងលើ

✅ Add 'use client' ជាជួរ ១ នៃ File

⚠️ Supabase Auth Error / 401 Unauthorized

Supabase URL ឬ Anon Key ខុស

✅ Supabase Dashboard → Settings → API → Copy URL + anon public key

💡 Error មិន​ចេះ Fix?

① Copy Error Message ទាំងអស់

② Paste ក្នុង Google AI Studio

③ វាយ: "I'm using Next.js. Fix this error: [paste error]"

④ Apply Fix ដែល AI ផ្ដល់

✅ ផ្នែកទី ១០

Checklist — ពិនិត្យ Progress

🎬 វីដេអូ Course

🎬

Loading videos...