[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"academy-blogs-th-1-1-all-golang-the-series-ep150-workshop-ai-chatbot-gin-framework-all--*":3,"academy-blog-translations-uz642au85qm6tzz":88},{"data":4,"page":74,"perPage":74,"totalItems":74,"totalPages":74},[5],{"alt":6,"collectionId":7,"collectionName":8,"content":9,"cover_image":10,"cover_image_path":11,"created":12,"created_by":13,"expand":14,"id":82,"keywords":83,"locale":54,"published_at":84,"scheduled_at":70,"school_blog":78,"short_description":85,"status":76,"title":86,"updated":87,"updated_by":13,"slug":79,"views":81},"สถาปัตยกรรมการต่อท่อระบบสตรีมมิ่ง AI Chatbot ด้วย Gin Framework และ OpenAI API","sclblg987654321","school_blog_translations","\u003Cp>เดินทางมาถึง EP.150 กันแล้วครับ Gophers ทุกคน! ยินดีด้วยที่คุณได้สะสมจิ๊กซอว์ชิ้นสำคัญมาครบหมดแล้ว ตั้งแต่การจัดการ Environment ด้วย Docker, การทำ Streaming ด้วย Channels, ไปจนถึงการควบคุมงบประมาณด้วย Token Management\u003C\u002Fp>\u003Cp>ในตอนนี้ ได้เวลาที่เราจะนำความรู้ทั้งหมดมารวมร่างปล่อยของจริงใน Workshop แรกของซีซันนี้ เราจะสร้าง Simple AI Chatbot Server ที่รองรับการสตรีมข้อมูลข้อความแบบ Real-time โดยใช้ Gin Framework ร่วมกับ OpenAI SDK กันครับ!\u003C\u002Fp>\u003Ch2>โครงสร้างโปรเจกต์ (Project Structure)\u003C\u002Fh2>\u003Cp>เพื่อให้โค้ดของเราสะอาดและดูแลรักษาง่าย เราจะจัดโครงสร้างตามมาตรฐาน Go แบบเรียบง่ายดังนี้:\u003C\u002Fp>\u003Cp>Plaintext\u003C\u002Fp>\u003Cpre>\u003Ccode>ai-chatbot-server\u002F\r\n├── main.go\r\n├── handlers\u002F\r\n│   └── chat.go\r\n├── go.mod\r\n└── go.sum\r\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>เริ่มสร้างโปรเจกต์และติดตั้ง Dependencies ที่จำเป็นผ่าน Terminal:\u003C\u002Fp>\u003Cp>Bash\u003C\u002Fp>\u003Cpre>\u003Ccode>go mod init ai-chatbot-server\r\ngo get github.com\u002Fgin-gonic\u002Fgin\r\ngo get github.com\u002Fsashabaranov\u002Fgo-openai\r\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch2>เขียนส่วนขับเคลื่อนหลัก:\u003Cstrong> \u003Ccode>main.go\u003C\u002Fcode>\u003C\u002Fstrong>\u003C\u002Fh2>\u003Cp>ในไฟล์นี้เราจะทำหน้าที่ดึง API Key จากระบบ, เริ่มต้นทำงาน OpenAI Client และตั้งค่า Route ของ Gin Framework เพื่อเตรียมเปิดท่อสตรีมข้อมูล\u003C\u002Fp>\u003Cp>Go\u003C\u002Fp>\u003Cpre>\u003Ccode>package main\r\n\r\nimport (\r\n\t\"log\"\r\n\t\"os\"\r\n\r\n\t\"ai-chatbot-server\u002Fhandlers\"\r\n\t\"github.com\u002Fgin-gonic\u002Fgin\"\r\n\t\"github.com\u002Fsashabaranov\u002Fgo-openai\"\r\n)\r\n\r\nfunc main() {\r\n\t\u002F\u002F 1. ดึง API Key จาก Environment เพื่อความปลอดภัย\r\n\tapiKey := os.Getenv(\"OPENAI_API_KEY\")\r\n\tif apiKey == \"\" {\r\n\t\tlog.Fatal(\"ERROR: OPENAI_API_KEY env variable is required\")\r\n\t}\r\n\r\n\t\u002F\u002F 2. สร้าง OpenAI Client\r\n\taiClient := openai.NewClient(apiKey)\r\n\r\n\t\u002F\u002F 3. Setup Gin Engine\r\n\tr := gin.Default()\r\n\r\n\t\u002F\u002F ทำการฉีด Dependency (Inject Client) เข้าไปใน Handler ผ่าน Closure\r\n\tr.POST(\"\u002Fapi\u002Fchat\u002Fstream\", handlers.HandleChatStream(aiClient))\r\n\r\n\tlog.Println(\"🚀 AI Chatbot Server starting on :8080...\")\r\n\tr.Run(\":8080\")\r\n}\r\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch2>สร้างขบวนการส่งข้อมูล:\u003Cstrong> \u003Ccode>handlers\u002Fchat.go\u003C\u002Fcode>\u003C\u002Fstrong>\u003C\u002Fh2>\u003Cp>เราจะใช้เทคนิค \u003Cstrong>Server-Sent Events (SSE)\u003C\u002Fstrong> ร่วมกับฟีเจอร์ Streaming ของ OpenAI เพื่อดันข้อความออกไปหา Client ทันทีที่ AI คิดเสร็จทีละคำ ซึ่ง Gin มีฟังก์ชัน \u003Ca rel=\"noopener noreferrer\" href=\"http:\u002F\u002Fc.Stream\">\u003Ccode>c.Stream\u003C\u002Fcode>\u003C\u002Fa>\u003Ccode>()\u003C\u002Fcode> มาช่วยซัพพอร์ตจุดนี้ให้เขียนง่ายขึ้นมากครับ\u003C\u002Fp>\u003Cp>Go\u003C\u002Fp>\u003Cpre>\u003Ccode>package handlers\r\n\r\nimport (\r\n\t\"context\"\r\n\t\"errors\"\r\n\t\"io\"\r\n\t\"net\u002Fhttp\"\r\n\r\n\t\"github.com\u002Fgin-gonic\u002Fgin\"\r\n\t\"github.com\u002Fsashabaranov\u002Fgo-openai\"\r\n)\r\n\r\n\u002F\u002F โครงสร้างสำหรับรับข้อมูล Request จาก Client\r\ntype ChatRequest struct {\r\n\tMessage string `json:\"message\" binding:\"required\"`\r\n}\r\n\r\nfunc HandleChatStream(client *openai.Client) gin.HandlerFunc {\r\n\treturn func(c *gin.Context) {\r\n\t\tvar req ChatRequest\r\n\t\tif err := c.ShouldBindJSON(&amp;req); err != nil {\r\n\t\t\tc.JSON(http.StatusBadRequest, gin.H{\"error\": \"Invalid request body\"})\r\n\t\t\treturn\r\n\t\t}\r\n\r\n\t\tctx := c.Request.Context()\r\n\r\n\t\t\u002F\u002F 1. สร้างคำร้องขอไปยัง OpenAI แบบเปิดโหมด Stream\r\n\t\tstreamReq := openai.ChatCompletionRequest {\r\n\t\t\tModel:  openai.GPT4o, \u002F\u002F ตรวจสอบให้มั่นใจว่าใช้ go-openai เวอร์ชันล่าสุด หรือเปลี่ยนเป็น \"gpt-4o\" แบบสตริงตรงๆ ได้\r\n\t\t\tStream: true,\r\n\t\t\tMessages: []openai.ChatCompletionMessage{\r\n\t\t\t\t{\r\n\t\t\t\t\tRole:    openai.ChatMessageRoleUser,\r\n\t\t\t\t\tContent: req.Message,\r\n\t\t\t\t},\r\n\t\t\t},\r\n\t\t}\r\n\r\n\t\tstream, err := client.CreateChatCompletionStream(ctx, streamReq)\r\n\t\tif err != nil {\r\n\t\t\tc.JSON(http.StatusInternalServerError, gin.H{\"error\": err.Error()})\r\n\t\t\treturn\r\n\t\t}\r\n\t\tdefer stream.Close()\r\n\r\n\t\t\u002F\u002F สำคัญสำหรับ Production: ตั้งค่า Headers สำหรับ Server-Sent Events (SSE)\r\n\t\t\u002F\u002F เพื่อป้องกันไม่ให้ Reverse Proxy (เช่น Nginx, Cloudflare) ทำการกักข้อมูล (Buffer)\r\n\t\tc.Header(\"Content-Type\", \"text\u002Fevent-stream\")\r\n\t\tc.Header(\"Cache-Control\", \"no-cache\")\r\n\t\tc.Header(\"Connection\", \"keep-alive\")\r\n\t\tc.Header(\"Transfer-Encoding\", \"chunked\")\r\n\r\n\t\t\u002F\u002F 2. ใช้ c.Stream ของ Gin ในการยิงข้อมูลออกแบบ Real-time ต่อเนื่อง\r\n\t\tc.Stream(func(w io.Writer) bool {\r\n\t\t\tselect {\r\n\t\t\tcase &lt;-ctx.Done():\r\n\t\t\t\t\u002F\u002F ปลอดภัยสูงสุด: หาก Client ตัดการเชื่อมต่อ (ปิดหน้าจอ\u002Fกดยกเลิก) ลูปจะหยุดทำงานทันที\r\n\t\t\t\treturn false\r\n\r\n\t\t\tdefault:\r\n\t\t\t\tresponse, err := stream.Recv()\r\n\t\t\t\tif errors.Is(err, io.EOF) {\r\n\t\t\t\t\t\u002F\u002F เมื่อส่งข้อมูลหมดแล้ว ส่งสัญญาณบอก Client ว่าสิ้นสุดการทำงาน\r\n\t\t\t\t\tc.SSEvent(\"message\", \"[DONE]\")\r\n\t\t\t\t\treturn false\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif err != nil {\r\n\t\t\t\t\t\u002F\u002F หากเกิด Error ระหว่างสตรีม ยิง Event แจ้งฝั่ง Client แล้วตัดการทำงาน\r\n\t\t\t\t\tc.SSEvent(\"error\", err.Error())\r\n\t\t\t\t\treturn false\r\n\t\t\t\t}\r\n\r\n\t\t\t\t\u002F\u002F ดึงข้อความ chunk เล็กๆ ที่ AI ส่งมาในรอบนั้นๆ\r\n\t\t\t\tif len(response.Choices) &gt; 0 {\r\n\t\t\t\t\tcontent := response.Choices[0].Delta.Content\r\n\t\t\t\t\tif content != \"\" {\r\n\t\t\t\t\t\t\u002F\u002F ส่งข้อมูลกลับไปยัง Client แบบ Real-time ทันที ผ่าน SSE format\r\n\t\t\t\t\t\tc.SSEvent(\"message\", content)\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn true \u002F\u002F คืนค่า true เพื่อวนลูปดึงข้อมูลใน Chunk ถัดไป\r\n\t\t\t}\r\n\t\t})\r\n\t}\r\n}\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch2>🎯 ท้าให้ลอง (Daily Mission)\u003C\u002Fh2>\u003Cp>เมื่อรันเซิร์ฟเวอร์เสร็จแล้ว (อย่าลืมตั้งค่า \u003Ccode>export OPENAI_API_KEY=\"your-key\"\u003C\u002Fcode>) ให้ลองใช้คำสั่ง \u003Ccode>curl\u003C\u002Fcode> ผ่าน Terminal เพื่อทดสอบประสิทธิภาพการสตรีมข้อความของ API ของคุณ:\u003C\u002Fp>\u003Cp>Bash\u003C\u002Fp>\u003Cpre>\u003Ccode># แฟล็ก -N คือสิ่งสำคัญเพื่อปิดการทำ Buffering ของ curl ทำให้เห็นตัวอักษรไหลทันที\r\ncurl -N -X POST http:\u002F\u002Flocalhost:8080\u002Fapi\u002Fchat\u002Fstream \\\r\n     -H \"Content-Type: application\u002Fjson\" \\\r\n     -d '{\"message\": \"ขอ 3 เหตุผลที่ควรเขียน Go ยุค AI-First แบบกระชับ\"}'\r\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Cul>\u003Cli>\u003Cp>\u003Cstrong>การบ้านเพิ่มความโปร:\u003C\u002Fstrong> ตอนนี้บอทของเรายังเป็นแบบ \"ถามคำตอบคำ\" (Stateless) ลองนำความรู้เรื่อง Go Slices มาประยุกต์ทำระบบ Memory จำประวัติการคุย (Chat History) ก่อนส่งไปหา OpenAI เพื่อให้แอปพลิเคชันของเราคุยตอบโต้ต่อเนื่องได้สนุกขึ้นดูครับ!\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Ch2>FAQ (คำถามที่พบบ่อยประจำตอน)\u003C\u002Fh2>\u003Ch3>Q: ทำไมต้องใส่ Header\u003Cstrong> \u003Ccode>Cache-Control: no-cache\u003C\u002Fcode> \u003C\u002Fstrong>และ\u003Cstrong> \u003Ccode>Transfer-Encoding: chunked\u003C\u002Fcode> \u003C\u002Fstrong>ก่อนรัน \u003Ca rel=\"noopener noreferrer\" href=\"http:\u002F\u002Fc.Stream\">\u003Cstrong>\u003Ccode>c.Stream\u003C\u002Fcode>\u003C\u002Fstrong>\u003C\u002Fa>\u003Cstrong>\u003Ccode>()\u003C\u002Fcode>\u003C\u002Fstrong>?\u003C\u002Fh3>\u003Cp>\u003Cstrong>A:\u003C\u002Fstrong> หากแอปพลิเคชัน Go รันอยู่เบื้องหลัง Reverse Proxy เช่น Nginx, Apache หรือบริการ Cloudflare ตัว Proxy เหล่านี้มักจะพยายาม \"กัก\" ข้อมูล (Buffer) ไว้ให้ครบก้อนก่อนส่งให้ผู้ใช้เพื่อประหยัดสตรีมเน็ต การใส่ Header เหล่านี้เป็นการสั่ง Proxy ว่า \u003Cem>\"ห้ามกักข้อมูล ให้ปล่อยไหลผ่านทันทีทีละชิ้น\"\u003C\u002Fem> ส่งผลให้ข้อความบนหน้าจอลื่นไหลไม่กระตุกครับ\u003C\u002Fp>\u003Ch3>Q: ฟังก์ชัน\u003Cstrong> \u003C\u002Fstrong>\u003Ca rel=\"noopener noreferrer\" href=\"http:\u002F\u002Fc.Stream\">\u003Cstrong>\u003Ccode>c.Stream\u003C\u002Fcode>\u003C\u002Fstrong>\u003C\u002Fa>\u003Cstrong>\u003Ccode>()\u003C\u002Fcode> \u003C\u002Fstrong>ของ Gin ทำงานอย่างไรเบื้องหลัง และมันปลอดภัยกับ Memory ไหม?\u003C\u002Fh3>\u003Cp>\u003Cstrong>A:\u003C\u002Fstrong> เบื้องหลังของ \u003Ca rel=\"noopener noreferrer\" href=\"http:\u002F\u002Fc.Stream\">\u003Ccode>c.Stream\u003C\u002Fcode>\u003C\u002Fa>\u003Ccode>()\u003C\u002Fcode> คือการทำลูปเรียก Anonymous function ที่เราส่งเข้าไปเรื่อยๆ ตราบใดที่ฟังก์ชันนั้นยังคืนค่าเป็น \u003Ccode>true\u003C\u002Fcode> และ HTTP Connection ยังไม่ถูกตัด ข้อดีคือมันใช้หน่วยความจำต่ำมาก (Low Memory Footprint) เพราะข้อมูลแต่ละ Chunk ถูกแปลงเป็นไบต์แล้วพ่นลงเน็ตเวิร์กทันที ไม่ได้ถูกเก็บสะสมไว้ในแรมของ Server ครับ\u003C\u002Fp>\u003Ch3>Q: ถ้า Client ปิดหน้าจอไปดื้อๆ ในขณะที่\u003Cstrong> \u003C\u002Fstrong>\u003Ca rel=\"noopener noreferrer\" href=\"http:\u002F\u002Fc.Stream\">\u003Cstrong>\u003Ccode>c.Stream\u003C\u002Fcode>\u003C\u002Fstrong>\u003C\u002Fa>\u003Cstrong>\u003Ccode>()\u003C\u002Fcode> \u003C\u002Fstrong>กำลังทำงานอยู่ จะเกิดอะไรขึ้น?\u003C\u002Fh3>\u003Cp>\u003Cstrong>A:\u003C\u002Fstrong> ตัวแปร \u003Ccode>ctx\u003C\u002Fcode> ที่เราดึงมาจาก \u003Ccode>c.Request.Context()\u003C\u002Fcode> จะได้รับสัญญาณ Cancellation ทันที และเมื่อโค้ดวนลูปไปเจอ \u003Ccode>stream.Recv()\u003C\u002Fcode> ในรอบถัดไป มันจะเกิด Error จาก Context ส่งผลให้ฟังก์ชันคืนค่า \u003Ccode>false\u003C\u002Fcode> และจบการรัน Goroutine ลงอย่างปลอดภัย (Graceful Termination) ไม่เกิดปัญหา Goroutine ค้างในระบบแน่นอนครับ\u003C\u002Fp>\u003Cdiv data-type=\"horizontalRule\">\u003Chr>\u003C\u002Fdiv>\u003Ch2>บทสรุป\u003C\u002Fh2>\u003Cp>การนำ Gin Framework มารวมร่างกับ Go Channels และระบบ Stream ของ OpenAI ช่วยให้เราสร้าง API สตรีมมิ่งที่เบา หนาแน่น และเสถียรมากในฝั่ง Backend โดยไม่ต้องใช้ทรัพยากรเครื่องมหาศาล นี่คือเสน่ห์ที่แท้จริงของการทำสถาปัตยกรรมด้วยภาษา Go ครับ\u003C\u002Fp>\u003Cp>\u003Cstrong>ในตอนต่อไป (EP.151):\u003C\u002Fstrong> แม้ว่า AI ของเราจะฉลาดและตอบไวแค่ไหน แต่มันก็ไม่รู้ข้อมูลภายในองค์กร ข้อมูลส่วนตัว หรืออัปเดตใหม่ๆ ของเราอยู่ดี... ตอนหน้าเราจะก้าวเข้าสู่เฟสถัดไปที่ล้ำขึ้นไปอีกกับเรื่อง \u003Cstrong>\"What is RAG?: ทำไม AI ต้องมีฐานข้อมูลส่วนตัว\"\u003C\u002Fstrong> เตรียมตัวเปิดโลก Retrieval-Augmented Generation กันได้เลยครับ!\u003C\u002Fp>\u003Cp>\u003Cstrong>ฝากกดติดตามพวกเราได้ที่ Superdev Academy\u003C\u002Fstrong> ในทุกช่องทางนะครับ!\u003C\u002Fp>\u003Cul>\u003Cli>\u003Cp>\u003Cstrong>🔵 Facebook: \u003C\u002Fstrong>\u003Ca target=\"_blank\" rel=\"noopener\" class=\"ng-star-inserted\" href=\"https:\u002F\u002Fwww.facebook.com\u002Fsuperdev.academy.th\">\u003Cstrong>Superdev Academy Thailand\u003C\u002Fstrong>\u003C\u002Fa>\u003Cstrong> \u003C\u002Fstrong>(อัปเดตข่าวสารและบทความใหม่)\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cstrong>🎬 YouTube: \u003C\u002Fstrong>\u003Ca target=\"_blank\" rel=\"noopener\" class=\"ng-star-inserted\" href=\"https:\u002F\u002Fwww.youtube.com\u002F@SuperdevAcademy\">\u003Cstrong>Superdev Academy Channel\u003C\u002Fstrong>\u003C\u002Fa>\u003Cstrong> \u003C\u002Fstrong>(ติวเข้มแบบวิดีโอ)\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cstrong>📸 Instagram: \u003C\u002Fstrong>\u003Ca target=\"_blank\" rel=\"noopener\" class=\"ng-star-inserted\" href=\"https:\u002F\u002Fwww.instagram.com\u002Fsuperdevacademy\u002F\">\u003Cstrong>@superdevacademy\u003C\u002Fstrong>\u003C\u002Fa>\u003Cstrong> \u003C\u002Fstrong>(เกร็ดความรู้สั้นๆ และเบื้องหลังการทำงาน)\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cstrong>🎬 TikTok: \u003C\u002Fstrong>\u003Ca target=\"_blank\" rel=\"noopener\" class=\"ng-star-inserted\" href=\"https:\u002F\u002Fwww.tiktok.com\u002F@superdevacademy?lang=th-TH\">\u003Cstrong>@superdevacademy\u003C\u002Fstrong>\u003C\u002Fa>\u003Cstrong> \u003C\u002Fstrong>(Tips &amp; Tricks ฉบับย่อยง่าย)\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Cstrong>🌐 Website: \u003C\u002Fstrong>\u003Ca target=\"_blank\" rel=\"noopener noreferrer\" href=\"http:\u002F\u002Fsuperdevacademy.com\">\u003Cstrong>superdevacademy.com\u003C\u002Fstrong>\u003C\u002Fa>\u003Cstrong> \u003C\u002Fstrong>(คลังบทความและคอร์สเรียนฉบับเต็ม)\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003C\u002Fp>","191qogwlo8bh_5xvzamg2m5.png","https:\u002F\u002Ftwsme-r2.tumwebsme.com\u002Fsclblg987654321\u002Fixnjos9m1nv5g0s\u002F191qogwlo8bh_5xvzamg2m5.png","2026-06-09 03:32:24.212Z","76qprkevbgfdps8",{"keywords":15,"locale":48,"school_blog":58},[16,22,26,30,34,38,43],{"collectionId":17,"collectionName":18,"created":19,"created_by":13,"id":20,"name":21,"updated":19,"updated_by":13},"sclkey987654321","school_keywords","2026-06-09 02:45:44.652Z","h420uh9497imwwg","Gin Framework",{"collectionId":17,"collectionName":18,"created":23,"created_by":13,"id":24,"name":25,"updated":23,"updated_by":13},"2026-06-09 02:45:54.612Z","mwdzo7snibz38p4","Go Web Server",{"collectionId":17,"collectionName":18,"created":27,"created_by":13,"id":28,"name":29,"updated":27,"updated_by":13},"2026-06-09 02:46:00.725Z","rgplhhj7796zaqg","AI Chatbot Backend",{"collectionId":17,"collectionName":18,"created":31,"created_by":13,"id":32,"name":33,"updated":31,"updated_by":13},"2026-06-09 02:46:06.302Z","728qxum2gfiormu","Real-time Streaming",{"collectionId":17,"collectionName":18,"created":35,"created_by":13,"id":36,"name":37,"updated":35,"updated_by":13},"2026-06-09 02:46:11.702Z","y9xcv17enwjxdcw","Server-Sent Events",{"collectionId":17,"collectionName":18,"created":39,"created_by":13,"id":40,"name":41,"updated":42,"updated_by":13},"2026-03-04 08:20:11.547Z","ey3puyme01a9bsw","Go","2026-06-07 06:45:07.798Z",{"collectionId":17,"collectionName":18,"created":44,"created_by":13,"id":45,"name":46,"updated":47,"updated_by":13},"2026-03-04 08:20:14.253Z","ah6lvy4x8qe08l5","Golang","2026-06-07 06:45:08.193Z",{"code":49,"collectionId":50,"collectionName":51,"created":52,"flag":53,"id":54,"is_default":55,"label":56,"updated":57},"th","pbc_1989393366","locales","2026-01-22 10:59:55.832Z","twemoji:flag-thailand","s8wri3bt4vgg2ji",true,"Thai","2026-04-10 15:42:46.614Z",{"category":59,"collectionId":60,"collectionName":61,"created":62,"expand":63,"id":78,"slug":79,"updated":80,"views":81},"wqxt7ag2gn7xcmk","pbc_2105096300","school_blogs","2026-06-09 03:32:23.973Z",{"category":64},{"blogIds":65,"collectionId":66,"collectionName":67,"created":68,"created_by":13,"id":59,"image":69,"image_alt":70,"image_path":71,"label":72,"name":73,"priority":74,"publish_at":75,"scheduled_at":70,"status":76,"updated":77,"updated_by":13},[],"sclcatblg987654321","school_category_blogs","2026-03-04 08:33:53.210Z","59ty92ns80w_15oc1implw.png","","https:\u002F\u002Ftwsme-r2.tumwebsme.com\u002Fsclcatblg987654321\u002Fwqxt7ag2gn7xcmk\u002F59ty92ns80w_15oc1implw.png",{"en":73,"th":73},"Golang The Series",1,"2026-03-16 04:39:38.440Z","published","2026-06-07 06:45:03.856Z","uz642au85qm6tzz","golang-the-series-ep150-workshop-ai-chatbot-gin-framework","2026-06-09 08:17:17.349Z",123,"ixnjos9m1nv5g0s",[20,24,28,32,36,40,45],"2026-06-09 04:21:19.536Z","ถึงเวลาปล่อยของจริง! เวิร์กชอปสร้างระบบ AI Chatbot Server รองรับการสตรีมข้อความ Real-time (SSE) ด้วย Gin Framework และ Go Concurrency ตั้งค่าโค้ดระดับ Production พร้อมลุยใช้งานจริง","Golang The Series EP.150: Workshop 1: สร้าง Simple AI Chatbot Server ด้วย Gin Framework","2026-06-09 04:21:19.537Z",{"th":79,"en":79}]