วันนี้ Vultureprime ได้ทำ Project เกี่ยวกับ OpenAI เช่น Chatbot นั้นเอง ในการใช้งาน Chatbot ก็จะมีต้นทุนในส่วนของค่าใช้จ่าย ตัว Model OpenAI ซึ่งถ้าปล่อยให้ใช้ แล้วมีการ request หลายครั้งจำนวนมาก ส่งผลให้ค่าใช้จ่ายสูง ถ้าได้เห็นบิลคงเป็นลมกันแน่นนอน เพื่อป้องกัน พวกเราเลยได้ทำตัวของ Rate Limit เพื่อจำนวนจำนวนการ Request ในเวลาสั้นจำนวนนึง
ถ้านึกภาพให้เห็น ก็เหมือนกับการที่เราช็อปปิ้งด้วย ที่เรากำลังจับจ่ายใช้สอยแต่ถูกควบคุมด้วยวงเงินที่สามารถใช้จ่ายได้นั้นเอง ซึ่งตัว Rate Limit จะช่วยควบคุมจำนวนที่ user จะ request เข้ามาใช้ model นั้นเอง
Implement the Chat interface
ขั้นตอนในการสร้างเราก็ได้เลือก Lib หรือ Framwork มาใช้งานดังต่อไปนี้
1.Next.js:
เริ่มโปรเจกต์ใหม่โดยใช้คำสั่ง create-next-app
npx create-next-app my-project
cd my-project
2.React Hook Form:
yarn add react-hook-form @hookform/resolvers zod
และ เราเลือกใช้ zod ในการจัดการ ทำ validate input form
3.TanStack Query:
ติดตั้ง TanStack Query (React Query) ในโปรเจกต์:
ในการ Implement Chat Interface เราจะทำเป็น 4 section ซึ่งประกอบด้วย
- section hero ใน section hero นี้เราก็จะเกริ่นในเรื่องของ API Rate Limits
- section plan ใน section plan จะมีให้เลือก plan ในแบบต่างๆ ถ้าอยากลองเล่นเยอะๆ 😆 ก็ติดต่อเรามาได้เลยนะคะ
- section demo chatbot ในส่วนของ chatbot ตัว demo ต้องนำ api ที่ขอ จาก plan มาใส่เพื่อทดลองเล่น
- section contact us ในส่วนสุดท้ายใครที่สนใจก็ติดต่อพวกเรามาได้เลย 😎
Connect the frontend with the backend
ซึ่งวันนี้ก็จะขออธิบายในส่วนของการ implement ตัว Chatbot ซึ่งตัว Chatbot นี้เราทำมาในรูปแบบ Stream การสร้างและใช้ Streamed Text จาก API ใน React คือ รับข้อมูลข้อความจาก API แบบเรียลไทม์และนำข้อมูลนั้นมาแสดงผล ซึ่งส่วนมากเราจะนำมาใช้กับสิ่งที่แสดงข้อมูลที่มีการอัปเดตอยู่ตลอดเวลา เช่น ข้อความแชท, ราคาหุ้นและข้อมูลทางการเงินอื่น ๆ หรือข้อมูลอื่น ๆ ที่ต้องการแสดงผลเรียลไทม์ นั้นเอง
ซึ่งในส่วนของการเชื่อมต่อ API เราจะใช้ fetch โดยมี header เป็น text/event-stream โดยเมื่อเราทำการ fetch เราจะได้ ทำการ read โดยใช้ getReader() ซึ่งเป็น stream interface ของ ReadableStream สามารถอ่านเพิ่มเติมได้ที่
ReadableStream: getReader() method - Web APIs | MDN
useEffect(() => {
const message = { query: watch('query') }
const getData = async () => {
try {
// clear input chat
setValue('query', '')
const response = await fetch(
`${API_BOT}/query?uuid=${localStorage?.session}&message=${message.query}`,
{
method: 'GET',
headers: {
Accept: 'text/event-stream',
'x-api-key': localStorage?.apiKey, //api key
},
}
)
const reader = response.body!.getReader()
let result = ''
while (true) {
const { done, value } = await reader?.read()
if (done) {
setStreamText('')
setAnswer((prevState) => [
...prevState,
{
id: (prevState.length + 1).toString(),
role: 'ai',
message: result,
},
])
break
}
result += new TextDecoder().decode(value)
setStreamText(
(prevData) => prevData + new TextDecoder().decode(value)
)
}
} catch (error: any) {
console.error(error)
setError('bot', {
message: error?.response?.data?.message ?? 'Something went wrong',
})
}
}
if (isSubmitSuccessful) {
getData()
}
}, [submitCount, isSubmitSuccessful, setValue, watch, setError])
ซึ่งหลังจากจัดการได้เเล้ว เราก็มาจัดการนำข้อมูลที่เราได้ไปเชื่อมต่อส่วนต่างๆ ได้เลย 💕
เราก็จะมาดูผลลัพธ์ที่เราได้กัน 😎
Implementing API key generation
หลังจากที่เราสร้าง UI interface ขึ้นมาเเล้วเราก็ต้องทำการ connect กับ ฝั่งของ backed ที่เป็นตัว generate API key กัน
ซึ่งตัว API Interface ที่เราได้มาก็มีดังต่อไปนี้
API Plan
[
{
"name": "20RequestPerDay"
},
{
"name": "30RequestPerDay"
},
{
"name": "10RequestPerDay"
}
]
API Create Key
POST {endpoint}/create_key
{
"plan_name": "30RequestPerDay",
"user": "example@email.com"
}
{
"value": "7wuOmY7Osz721X1bQUkAP2aGUF5oOVw28EJx7MVS"
}
หลังจาก เราทำในส่วนของ connect api get key เสร็จเเล้ว ก็จะไปแก้ในส่วนของ Project อื่น โดยการ เพิ่ม header
{
"x-api-key": "7wuOmY7Osz721X1bQUkAP2aGUF5oOVw28EJx7MVS"
}
Implementing rate limit notification
หลังจากที่ทำการ input validation เเล้ว เราก็จะมาจัดการ error ซึ่งก็จะมี error ในส่วนของผู้ใช้ที่ได้ทำการขอ ไปเเล้ว และในส่วนของ User ที่ นำ API Key ไปใช้เเล้ว ใช้จนหมด usage การใช้งานนั้นเอง ซึ่งเราจะได้ Error จากในส่วนของ API
{
"message": "Limit exceeds"
}
ในการดักเราจะดักจาก Stream โดย เมื่อ ใช้เกินจำนวน API จะส่ง status code 429 มา เมื่อเราได้ Error status code 429 เราจะทำ set message Error ให้ Bot เพื่อแสดงผลใน Interface
useEffect(() => {
const message = { query: watch('query') }
const getData = async () => {
try {
setValue('query', '')
const response = await fetch(
`${API_BOT}/query?uuid=${localStorage?.session}&message=${message.query}`,
{
method: 'GET',
headers: {
Accept: 'text/event-stream',
'x-api-key': localStorage?.apiKey,
},
}
)
if (response.status === 200) {
const reader = response.body!.getReader()
let result = ''
while (true) {
const { done, value } = await reader?.read()
if (done) {
setStreamText('')
setAnswer((prevState) => [
...prevState,
{
id: (prevState.length + 1).toString(),
role: 'ai',
message: result,
},
])
break
}
result += new TextDecoder().decode(value)
setStreamText(result)
}
}
if (response.status === 429) {
setError('bot', {
message: 'Limit Exceeded',
})
return
}
} catch (error: any) {
console.error(error)
setError('bot', {
message: error?.response?.data?.message ?? 'Something went wrong',
})
}
}
if (isSubmitSuccessful && localStorage) {
getData()
}
}, [submitCount, isSubmitSuccessful, setValue, watch, setError])
ทิ้งท้ายบทความสำหรับ OpenAI with ratelimit
OpenAI with ratelimit frontend
OpenAI with ratelimit backend
Github Frontend
Github Backend
FAQ Facebook Group