เริ่มจากต้นแบบที่ลองได้ในเบราว์เซอร์

ระบบตัวอย่างมีส่วนลงทะเบียนพนักงาน สแกนใบหน้า และตารางบันทึกเวลาเข้าออก ใช้เพื่อทดลองลำดับการทำงานให้เห็นภาพก่อน โดยเริ่มทดสอบด้วยข้อมูลตัวอย่างและภาพที่คุณได้รับอนุญาตให้ใช้

สร้างหน้าเว็บและลงทะเบียนใบหน้า

เปิด Gemini เลือก Canvas แล้ววาง Prompt ท้ายบทความ เมื่อได้หน้าเว็บ ให้ใส่รหัส ชื่อ แผนก ตำแหน่ง และรูปพนักงาน จากนั้นสร้างฐานข้อมูลใบหน้าก่อนเริ่มสแกน หากกล้องถูกบล็อกในหน้า Preview ให้ดาวน์โหลดไฟล์ HTML แล้วเปิดนอกหน้า Preview ตามคำแนะนำในระบบ

ลองเข้าออกและตรวจตาราง

เปิดกล้อง ทดสอบให้ระบบจับคู่กับคนที่ลงทะเบียนไว้ แล้วกดเข้างานหรือออกงาน ตรวจว่าชื่อและเวลาลงตารางถูกต้องก่อนดาวน์โหลด CSV ไปเปิดใน Excel หรือ Google Sheets ต้นแบบนี้ยังต้องประเมินความแม่นยำและการจัดเก็บข้อมูลก่อนใช้เป็นระบบลงเวลาจริง

Prompt พร้อมคัดลอก

คัดลอกคำสั่งด้านล่าง แล้วปรับข้อมูลตัวอย่างให้ตรงกับงานของคุณ

prompt
ทำหน้าที่เป็น Expert Frontend Developer เขียนหน้าเว็บ "ระบบสแกนใบหน้าลงเวลาพนักงาน (Face Recognition Check-in Demo)" แบบไม่ต้องมีฐานข้อมูลหลังบ้าน โดยเขียนทุกอย่าง (HTML, CSS, JS) รวมในไฟล์เดียว ใช้ canvas ประเภท HTML ธรรมดา (ไม่ใช่ React) เพื่อให้เปิดใช้งานได้ทันทีเมื่อดาวน์โหลดออกไปโดยไม่ต้อง build
ข้อกำหนดสำคัญเฉพาะ Gemini Canvas (ต้องทำตามเป๊ะๆ):


Canvas preview ของ Gemini รันอยู่ใน sandboxed iframe ซึ่งบล็อกสิทธิ์กล้อง (navigator.mediaDevices.getUserMedia) โดยดีฟอลต์ — นี่เป็นข้อจำกัดระดับเบราว์เซอร์ที่โค้ดฝั่งหน้าเว็บแก้เองไม่ได้ ดังนั้นกล้องต้องเปิดได้จริง 100% เมื่อไฟล์ถูกเปิดนอก sandbox (ดาวน์โหลดแล้วเปิดตรงๆ ในเบราว์เซอร์ หรือดีพลอยขึ้นเว็บโฮสติ้งเช่น Netlify) — นี่คือเกณฑ์ที่ใช้ตัดสินว่า "กล้องเปิดได้" ไม่ใช่การทดสอบผ่าน Canvas preview
ต้องเขียนโค้ดขอสิทธิ์กล้องให้แข็งแรง (robust): มีปุ่ม "ลองใหม่" หลัง error, ข้อความ error ที่บอกสาเหตุจริงจาก error.name (เช่น NotAllowedError = ผู้ใช้ปฏิเสธสิทธิ์หรือถูกบล็อกจาก policy, NotFoundError = ไม่มีกล้อง, NotReadableError = กล้องถูกแอปอื่นใช้งานอยู่)
ถ้าตรวจพบว่ากำลังรันอยู่ใน iframe (window.self !== window.top) และขอสิทธิ์กล้องไม่สำเร็จ ให้แสดงข้อความแนะนำเพิ่มเติมชัดเจนว่า "กล้องอาจถูกบล็อกเพราะกำลังดูผ่านหน้า Preview ของ Canvas กรุณากดดาวน์โหลดไฟล์แล้วเปิดไฟล์ .html นั้นตรงๆ ในเบราว์เซอร์ (หรือนำไปอัปโหลดขึ้นเว็บโฮสติ้ง เช่น Netlify) เพื่อใช้งานกล้องได้เต็มรูปแบบ"
โหลด Tailwind CDN, face-api.js CDN, Font Awesome CDN ผ่าน <script>/<link> แท็กปกติเท่านั้น ห้ามใช้ ES module import
ข้อกำหนดเครื่องมือ (Tech Stack):


Tailwind CSS ผ่าน CDN
face-api.js (vladmandic fork) ผ่าน CDN — pin เวอร์ชันให้ตรงกันทั้ง script และ URL โมเดล (เช่น @vladmandic/face-api@1.7.12) ห้ามใช้ @latest
Font Awesome ผ่าน CDN
ข้อกำหนดเรื่องโมเดล AI (ห้ามใช้ SsdMobilenetv1 — เคยทำให้เบราว์เซอร์ค้าง):


ใช้ TinyFaceDetector เท่านั้น ทั้งตอน Build Database และตอนสแกนกล้อง
โหลดเฉพาะ tinyFaceDetector, faceLandmark68Net, faceRecognitionNet
loadFromUri() ทุกครั้งต้อง wrap ด้วย timeout 30 วินาที (Promise.race) พร้อม error message ชัดเจน
ย่อขนาดรูปที่อัปโหลดอัตโนมัติให้ด้านยาวสุดไม่เกิน 640px ก่อนเข้า AI เสมอ
ระหว่างวนลูปหลายคนใน Build Database ต้อง yield ให้ browser และอัปเดตสถานะความคืบหน้า
ส่วนประกอบของหน้าเว็บ:
ส่วน Header & การตั้งค่า:


ชื่อระบบ + คำอธิบายสั้นๆ
ช่อง "Google Apps Script URL" (เป็นฟีเจอร์เสริม/optional เท่านั้น) + ปุ่ม "บันทึก URL" เซฟลง LocalStorage อัตโนมัติ
ส่วนที่ 1: การลงทะเบียน (Register Employees):


เริ่มต้นแสดงฟอร์ม 5 คน แต่ละฟอร์มมี: Employee ID, ชื่อ-นามสกุล, แผนก, ตำแหน่ง, ช่องอัปโหลดรูป
อัปโหลดรูปแล้วย่อขนาดก่อนเสมอ แล้วแสดง Preview แบบ In-memory
ปุ่ม "+ เพิ่มฟอร์มพนักงาน" เพิ่มได้ไม่จำกัด
ปุ่ม "Build Face Database" ต้องไม่บังคับให้กรอกครบทุกฟอร์ม — ตรวจสอบเฉพาะฟอร์มที่มีการอัปโหลดรูปเท่านั้น ฟอร์มที่เว้นว่างไว้ให้ข้ามไปเงียบๆ ไม่ต้อง validate ว่าต้องครบ 5 คน แค่มีคนเดียวที่มีรูปก็ต้องสร้างฐานข้อมูลและใช้งานต่อได้ทันที ถ้าไม่มีใครอัปโหลดรูปเลยสักคนถึงค่อย Alert แจ้งเตือน
โหลดโมเดล → สกัด Face Descriptor ทีละคนพร้อม yield → Alert ถ้าหาใบหน้าไม่เจอในรูปคนไหน → สร้าง FaceMatcher แล้วปลดล็อกปุ่ม Start Camera
ส่วนที่ 2: สแกนใบหน้า (Scan & Check-in):


เลย์เอาต์ 2 ฝั่ง (ซ้าย: กล้อง, ขวา: ข้อมูลคนที่สแกนเจอ)
ปุ่ม Start/Stop Camera พร้อม error handling ตามข้อกำหนด Canvas ด้านบน, วาดกรอบใบหน้า Real-time บน canvas overlay ด้วย TinyFaceDetector
เทียบกับ FaceMatcher → ตรงให้แสดงชื่อ + ปลดล็อก Check In/Out, ไม่ตรงให้วาดกรอบแดง/เหลือง + "Unknown"
ส่วนที่ 3: การบันทึกข้อมูล และ Logs:


Local Logs คือแหล่งข้อมูลหลักที่ต้องเชื่อถือได้เสมอ
กด Check In/Out → บันทึกลง Local Table + localStorage ก่อนเป็นอันดับแรกเสมอ แสดงข้อความสำเร็จทันที → ถ้ามี Apps Script URL ส่งแบบ background (no-cors, text/plain;charset=utf-8, timeout 8 วินาที) ไม่บล็อก UI
Payload: { timestamp, type, empId, name, dept, position }
เก็บ log ลง localStorage ถาวร โหลดขึ้นแสดงใหม่ทุกครั้งที่เปิดหน้าเว็บ, แทรกแถวใหม่ไว้บนสุดเสมอ
ปุ่ม "ดาวน์โหลด Excel/CSV" (ใส่ BOM, หน่วง revokeObjectURL อย่างน้อย 1 วินาที)
ปุ่ม "ล้างข้อมูล" พร้อม confirm() ยืนยัน
หมายเหตุ Google Apps Script: บัญชี Gmail ส่วนตัวส่วนใหญ่ไม่มีตัวเลือก "Anyone" (ไม่ login) ให้เลือกตอน deploy ให้ถือเป็น best-effort เสริมเท่านั้น Local CSV Export คือทางหลักที่ใช้งานได้เสมอ
ข้อควรระวังสำหรับ AI:


ห้ามใช้ alert()/confirm() พร่ำเพรื่อ ใช้เฉพาะ Error ร้ายแรงหรือยืนยันการลบข้อมูล
เขียนโค้ดให้สมบูรณ์ ห้ามเว้นว่างด้วย // ...
จัดการ Error Handling ทุกจุดที่เรียก async/fetch/AI model/กล้อง

อยากเห็นวิธีทำทีละขั้น?

ถ้าอ่านแล้วยังไม่เข้าใจ ดูวิธีทำในคลิป YouTube Shorts นี้ แล้วลองทำตามไปพร้อมกันได้เลย