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

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 ส่วนหลัก
และควรมี 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)
}
}
จากนั้นแสดงผลตามสถานะ:
แนวทางนี้ช่วยให้ผู้ใช้ไม่สับสนว่าเกิดอะไรขึ้นกับระบบ และยังทำให้หน้าจอดูเป็น production-ready มากขึ้น
Troubleshooting / Tips
> เป้าหมายของแดชบอร์ดแบบเรียลไทม์ไม่ใช่แค่ดึงข้อมูลได้ แต่ต้องดึงอย่างปลอดภัย เสถียร และไม่สร้างโหลดเกินจำเป็น
toLocaleString() เพื่อให้อ่านค่า token จำนวนมากได้ง่ายdevelopment, staging, productionสรุปแล้ว การทำหน้าจอแสดง Token คงเหลือแบบเรียลไทม์ด้วย Next.js + OpenAI API ควรเริ่มจากการออกแบบข้อมูลที่ต้องใช้ สร้าง API route เพื่อป้องกันการเปิดเผย key จากนั้นจึงทำ UI ที่อ่านง่าย เพิ่ม polling สำหรับอัปเดตข้อมูล และปิดท้ายด้วยการจัดการ state, loading และ error ให้ครบ เมื่อคุณมีโครงนี้แล้ว สามารถต่อยอดไปสู่กราฟรายวัน, การแจ้งเตือนเมื่อใกล้หมด quota หรือแดชบอร์ดแยกตามผู้ใช้และโมเดลได้ทันที