ทำแดชบอร์ด Token คงเหลือแบบเรียลไทม์ด้วย Next.js และ OpenAI API

บทความนี้จะพาคุณสร้างหน้าแดชบอร์ดสำหรับดูการใช้ token และโควตาแบบเรียลไทม์ด้วย Next.js ตั้งแต่การออกแบบ API route, ดึงข้อมูล usage, จัดการ state และตั้งค่า polling ให้เหมาะกับการใช้งานจริง

ทำแดชบอร์ด Token คงเหลือแบบเรียลไทม์ด้วย Next.js และ OpenAI API

Next.js, OpenAI API, Dashboard, React, Token Usage

ถ้าคุณกำลังทำแอป AI ที่มีต้นทุนผูกกับการใช้ token การมีหน้าจอที่บอกว่าใช้ไปเท่าไร เหลืออีกเท่าไร และแนวโน้มการใช้งานเป็นอย่างไร จะช่วยทั้งทีมพัฒนาและผู้ดูแลระบบตัดสินใจได้เร็วขึ้น บทความนี้จะสอนสร้างแดชบอร์ดแบบ step-by-step ด้วย Next.js + OpenAI API โดยหลังอ่านจบคุณจะได้หน้า UI ที่ดึงข้อมูล usage ผ่าน backend อย่างปลอดภัย แสดงผลแบบเรียลไทม์ด้วย polling และจัดการ state ได้พร้อมใช้งานจริง โดยควรมีพื้นฐาน Next.js, React hooks, API route และการตั้งค่า environment variables มาก่อนเล็กน้อย

Step 1: วางโครงข้อมูลและ API route สำหรับ usage

ก่อนทำ UI เราควรกำหนดก่อนว่าหน้าจอต้องใช้อะไรบ้าง เช่น quota ทั้งหมด, token ที่ใช้แล้ว, token คงเหลือ, และ เวลาอัปเดตล่าสุด เหตุผลที่เริ่มจากจุดนี้คือจะช่วยให้เราออกแบบทั้ง frontend และ backend ไปในทิศทางเดียวกัน

ในงานจริงไม่ควรเรียก OpenAI API จาก browser โดยตรง เพราะจะเสี่ยงต่อการเปิดเผย API key ดังนั้นให้สร้าง API route ใน Next.js เพื่อเป็นตัวกลาง

ตัวอย่างโครงสร้าง response ที่ frontend ใช้งานง่าย:

{
  quota: 1000000,
  used: 245000,
  remaining: 755000,
  updatedAt: "2026-05-27T10:30:00.000Z"
}

ตัวอย่างไฟล์ app/api/usage/route.ts:

import { NextResponse } from 'next/server'

export async function GET() {
  const quota = 1000000
  const used = 245000
  const remaining = quota - used

  return NextResponse.json({
    quota,
    used,
    remaining,
    updatedAt: new Date().toISOString(),
  })
}

ในตัวอย่างนี้เราใช้ mock data ก่อน เพื่อให้พัฒนา UI ได้เร็ว เมื่อหน้าจอเสร็จแล้วค่อยเปลี่ยนไปดึงข้อมูลจริงจากระบบ usage ของคุณเอง วิธีนี้ช่วยลดความซับซ้อนและแยกปัญหาได้ชัดเจน

Step 2: สร้างหน้าแดชบอร์ดและออกแบบ UI ให้อ่านง่าย

เมื่อมี API แล้ว ขั้นต่อไปคือทำหน้าจอที่มองแล้วเข้าใจทันที โดยแนะนำให้แยกเป็น 3 ส่วนหลัก

  • Quota ทั้งหมด
  • ใช้ไปแล้ว
  • คงเหลือ
  • และควรมี progress bar เพื่อให้เห็นสัดส่วนการใช้งานอย่างรวดเร็ว เหตุผลคือข้อมูลเชิงตัวเลขอย่างเดียวอาจอ่านยากเมื่อปริมาณ token สูงมาก

    ตัวอย่างหน้า app/dashboard/page.tsx:

    'use client'
    
    import { useEffect, useState } from 'react'
    
    type UsageData = {
      quota: number
      used: number
      remaining: number
      updatedAt: string
    }
    
    export default function DashboardPage() {
      const [data, setData] = useState<UsageData | null>(null)
    
      useEffect(() => {
        fetch('/api/usage')
          .then((res) => res.json())
          .then(setData)
      }, [])
    
      if (!data) return <div>Loading...</div>
    
      const percent = (data.used / data.quota) * 100
    
      return (
        <main>
          <h1>Token Dashboard</h1>
          <p>อัปเดตล่าสุด: {new Date(data.updatedAt).toLocaleString()}</p>
    
          <div>
            <div>Quota: {data.quota.toLocaleString()}</div>
            <div>Used: {data.used.toLocaleString()}</div>
            <div>Remaining: {data.remaining.toLocaleString()}</div>
          </div>
    
          <div style={{ width: '100%', background: '#eee', height: 12 }}>
            <div style={{ width: `${percent}%`, background: '#111', height: 12 }} />
          </div>
        </main>
      )
    }

    จุดสำคัญคือทำให้ผู้ใช้ตอบคำถามได้ทันทีว่า ตอนนี้ใช้ไปเท่าไร และ ใกล้ชน quota หรือยัง ถ้าจะใช้จริงใน production อาจเพิ่มสีเตือนเมื่อเกิน 80% เพื่อให้ทีมเห็นความเสี่ยงเร็วขึ้น

    Step 3: เพิ่ม polling เพื่ออัปเดตแบบเรียลไทม์

    ถ้าดึงข้อมูลแค่ครั้งเดียว หน้าแดชบอร์ดจะไม่สะท้อนการใช้งานล่าสุด ดังนั้นเราควรเพิ่ม polling เช่นทุก 10 หรือ 30 วินาที ตามความถี่ที่เหมาะกับระบบจริง

    เหตุผลที่ใช้ polling เพราะตั้งค่าง่าย ดูแลง่าย และเพียงพอสำหรับแดชบอร์ดส่วนใหญ่ โดยยังไม่ต้องซับซ้อนถึงระดับ WebSocket

    ปรับโค้ดในหน้า dashboard ดังนี้:

    useEffect(() => {
      let mounted = true
    
      const fetchUsage = async () => {
        const res = await fetch('/api/usage')
        const json = await res.json()
        if (mounted) setData(json)
      }
    
      fetchUsage()
      const interval = setInterval(fetchUsage, 10000)
    
      return () => {
        mounted = false
        clearInterval(interval)
      }
    }, [])

    สิ่งที่ควรระวังคือ polling ที่ถี่เกินไปอาจเพิ่มโหลดให้ทั้ง frontend และ backend โดยไม่จำเป็น สำหรับแดชบอร์ดผู้ดูแลระบบทั่วไป ช่วง 10-30 วินาที มักเหมาะสม แต่ถ้าเป็นระบบที่ต้องจับ usage แบบใกล้เคียงวินาทีจริง ค่อยพิจารณาแนวทางอื่นเพิ่มเติม

    Step 4: จัดการ loading, error และ state ให้พร้อมใช้งานจริง

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

    ตัวอย่างการจัดการ state เพิ่มเติม:

    const [data, setData] = useState<UsageData | null>(null)
    const [loading, setLoading] = useState(true)
    const [error, setError] = useState('')
    
    const fetchUsage = async () => {
      try {
        setError('')
        const res = await fetch('/api/usage')
        if (!res.ok) throw new Error('Failed to fetch usage')
        const json = await res.json()
        setData(json)
      } catch (err) {
        setError('ไม่สามารถโหลดข้อมูล usage ได้')
      } finally {
        setLoading(false)
      }
    }

    จากนั้นแสดงผลตามสถานะ:

  • ถ้า loading ให้แสดงข้อความหรือ skeleton
  • ถ้า error ให้แสดงข้อความที่อ่านง่ายและมีปุ่มลองใหม่
  • ถ้ามี data ให้แสดง dashboard ตามปกติ
  • แนวทางนี้ช่วยให้ผู้ใช้ไม่สับสนว่าเกิดอะไรขึ้นกับระบบ และยังทำให้หน้าจอดูเป็น production-ready มากขึ้น

    Troubleshooting / Tips

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

  • อย่าเก็บ API key ฝั่ง client ให้เรียกผ่าน API route หรือ backend เท่านั้น
  • เริ่มจาก mock data ก่อน เพื่อพัฒนา UI และ flow ได้เร็ว แล้วค่อยต่อข้อมูลจริง
  • ตั้ง polling ให้เหมาะกับงาน ถ้าถี่เกินไปจะเปลืองทรัพยากรโดยไม่จำเป็น
  • แสดงเวลา updatedAt เสมอ เพื่อให้ผู้ใช้รู้ว่าข้อมูลล่าสุดเมื่อไร
  • เพิ่ม formatting ตัวเลข เช่น toLocaleString() เพื่อให้อ่านค่า token จำนวนมากได้ง่าย
  • ถ้าต้องรองรับหลายโมเดลหรือหลายโปรเจกต์ อาจขยาย response ให้มีข้อมูลแยกตาม service หรือ environment เช่น development, staging, production
  • สรุปแล้ว การทำหน้าจอแสดง Token คงเหลือแบบเรียลไทม์ด้วย Next.js + OpenAI API ควรเริ่มจากการออกแบบข้อมูลที่ต้องใช้ สร้าง API route เพื่อป้องกันการเปิดเผย key จากนั้นจึงทำ UI ที่อ่านง่าย เพิ่ม polling สำหรับอัปเดตข้อมูล และปิดท้ายด้วยการจัดการ state, loading และ error ให้ครบ เมื่อคุณมีโครงนี้แล้ว สามารถต่อยอดไปสู่กราฟรายวัน, การแจ้งเตือนเมื่อใกล้หมด quota หรือแดชบอร์ดแยกตามผู้ใช้และโมเดลได้ทันที

    กลับไปยังบล็อก OVERFLOW