เปรียบเทียบรูปโปสเตอร์เลือกตั้งที่เป็นรูปแถมจากซีดีเธียร์เตอร์ AKB48 52nd Single「Teacher Teacher」และรูปที่ปริ๊นต์จากร้านอัดรูป “Kamera no Kitamura” ที่ญี่ปุ่น

เปรียบเทียบรูปโปสเตอร์เลือกตั้งที่เป็นรูปแถมจากซีดีเธียร์เตอร์ AKB48 52nd Single「Teacher Teacher」และรูปที่ปริ๊นต์จากร้านอัดรูป “Kamera no Kitamura” ที่ญี่ปุ่น ที่ได้รับลิขสิทธิ์เพื่อปริ๊นต์ ภาพอย่างถูกต้องจาก AKS

ความละเอียดของภาพไม่หนีกันเลย โดยดูจากตรงเส้นผมที่จะมาเป็นเส้นที่ชัดมากทั้งสองแบบ

โทนสว่างและมืดของภาพ ภาพจากซีดีจะมืดกว่านิด ๆ ภาพที่ปริ๊นต์เองจะสว่างกว่าเล็กน้อย (ไม่จับผิดนี่มองไม่ออก)

ด้านล่างของรูปจากซีดีจะใส่ที่มาว่ามาจากซีดี AKB48 Teacher Teacher ซึ่งมีขนาดใหญ่กว่าจากการปริ้นต์ที่จะบอกแค่บริษัทที่ถือลิขสิทธิ์ ทำให้พื้นที่ในการวางรูปโปสเตอร์ของรูปแถมจากซีดีเล็กกว่าเล็กน้อย

ด้านหลังรูป ในส่วนรูปแถม จะมีลายน้ำ AKB48 Teacher Teacher ส่วนรูปปริ้นต์จะเป็นกระดาษอัดรูปที่เราคุ้นเคยกัน คือบอกยี่ห้อกระดาษ แต่มีลายน้ำระบุชื่อไฟล์รูป และหมายเลขลำดับรูปที่สั่งปริ้นต์ออกมาแต่ละรูปจะมีลำดับเลขรันไปเรื่อยๆ

โครงการ Music We Choose You เราส่งรหัสโหวตเลือกตั้งด้วยวิธีอัตโนมัติอย่างไร

ก่อนอ่านผมอยากทำความเข้าใจก่อนว่าผมเป็นเพียงหนึ่งในทีมงาน Music We Choose You กว่าหลายสิบชีวิตเท่านั้น มีทีมงานส่วนอื่น ๆ ที่ต้องอ่านบัตรโหวต และกรอกด้วยมือโหวตลงไปบนเว็บเองอีกหลายพันโหวต ที่ไม่ได้เกิดจากกระบวนการนี้ และใน blog นี้ อาจไม่ได้กล่าวถึงชื่อทีมงานหลังบ้านเป็นรายคนได้ เพราะเพิ่งได้เจอหน้ากันก็ตอนวันลุ้นผลคะแนนเสียงเลือกตั้ง และบางคนที่เป็นทีมงานฝั่งญี่ปุ่นก็ยังไม่เจอหน้ากันจนวันนี้ แต่ทุกคนทำงานอย่างหนัก เพื่อให้ได้ซึ่งรหัสโหวตเลือกตั้งมาเข้ากระบวนการ และสุดท้ายคือผู้สนับสนุนเงินที่ร่วมกันโดเนทเข้าโครงการเพื่อให้มีเงินจำนวนมากในการจัดหารซีดี และรหัสโหวตเลือกตั้งมา นั้นหมายความว่า 18,502 คะแนน เกิดจากความร่วมแรงร่วมใจกันของทีมงาน และผู้สนับสนุนทุกคน ผมไม่ขอรับเครเดิตเหล่านี้ไว้เพียงคนเดียว ถ้ามีรายชื่อที่แน่ชัด เดี่ยวจะนำลงมาใส่ให้อีกครั้ง

ในส่วนของกระบวนการนี้ไม่ได้เป็นสิ่งใหม่อะไร แต่เป็นการสังเกต และมีต้นแบบจากคลิปจากแฟนคลับฝั่งญี่ปุ่นที่ได้ลงแนวทางปฏิบัติไว้ เรานำมาปรับปรุงและเปลี่ยนแปลงในหลาย ๆ ส่วนเพื่อให้สอดคล้องกับการทำงานในทีมอีกรอบ (ใน blog นี้บางขั้นตอนเรามี source code เปิดเผยให้ลองนำไปศึกษาต่อด้วย)

ฉะนั้นการเล่าเรื่องของกระบวนการในส่วนนี้จึงเป็นเหมือนบันทึกความทรงจำ เป็นข้อมูลอ้างอิงในอนาคตสำหรับนำไปปรับปรุงกระบวนการ และสำหรับบุคคลที่สนใจ

ตัวอย่างกระบวนการ และสิ่งที่ผมนำเป็นต้นแบบจากฝั่งญี่ปุ่น

การเขียนใน blog นี้จะมี 2 ช่วง คือช่วงก่อนประกาศผลด่วน กับช่วงหลังประกาศผลด่วน ซึ่งผมพยายามแทรกช่วงก่อนประกาศผลด่วนเพื่อให้รู้ว่าก่อนประกาศผลด่วน เราทำอะไร และนำมาปรับปรุงให้ดีขึ้นอย่างไรหลังจากประกาศผลด่วนเพื่อให้ส่งรหัสโหวตให้ได้ทัน เพราะทีมงานก็เสียดายคะแนนอีกหลายร้อยคะแนนที่ส่งขึ้นไปช่วงผลด่วนไม่ทัน เนื่องจากเรายังประสานงานระหว่างทีมกันไม่ดี ตัวชุดโปรแกรมที่ทำงานในช่วงนั้นยังเจอปัญหาติดขัด และรวมไปถึงเว็บรับรหัสโหวต AKB48 ล่มช่วงประมาณตี 2-5 ในช่วงก่อนปิดรับผลด่วน จนทำให้เราโหวตช่วงผลด่วนไปได้ไม่ตามเป้าที่วางไว้

การติดต่อประสานงานระหว่างทีมงานหลัก ๆ คือใช้ LINE และ Discord สำหรับ LINE จะใช้เพื่อสื่อสารแบบเร่งด่วน และสื่อสารกับทีมฝั่งญี่ปุ่น ส่วน Discord จะใช้ประสานงานช่วงส่งรหัสโหวต และพูดคุยแก้ไขรหัสโหวตในช่วงกลางคืนตั้งแต่ประมาณ 3 ทุ่มถึงตี 2 (มีบางวันตี 3) เหตุผลที่เราใช้เพราะการสื่อสารด้วยเสียงมันไม่ต้องพิมพ์ เพราะมือพิมพ์รหัสโหวต หรือแก้ไขข้อมูลกันอยู่ การพิพม์ LINE ทำให้งานส่วนแก้ไขรหัสโหวตหยุดชะงักได้ แล้วคุณภาพเสียงของ Discord ค่อนข้างดีไม่ค่อยเจอดีเลย์อีกด้วย

เริ่มด้วยการแสกนบัตรโหวตด้วย Fujitsu ScanSnap iX500 ซึ่งเป็น Sheet Fed Scanner ยอดนิยมมากสำหรับงานแบบนี้ โดยเราแสกนออกมาเป็น JPEG ไฟล์ โดยเหตุผลที่เราไม่แสกนออกมาเป็น PDF เพราะ ไฟล์รูปภาพบริหารจัดการง่ายกว่า หรือนำไปเปิดไฟล์เพื่ออ่านกับอุปกรณ์หลากหลาย

ScanSnap iX500_006
ScanSnap iX500_006 @ flickr

เมื่อได้ไฟล์รูปภาพ ทีมงานฝั่งญี่ปุ่น-ไทยตกลงกันว่าจะอัพโหลดรูปภาพผ่าน Google Drive จากญี่ปุ่นมาไทยโดยการแชร์ Folder กลางตัวหนึ่ง เพื่อใช้สำหรับการส่งไฟล์รูปภาพบัตรโหวต และเอาไว้ค้นหาสำหรับกรอกทบทวน-แก้ไขรหัสโหวตในกรณีที่นำไฟล์รูปดังกล่าวไป OCR (Optical character recognition – การแปลงไฟล์ภาพเอกสารที่เป็นรูปภาพ ให้เป็นไฟล์ข้อความตัวอักษรโดยอัตโนมัติ) แล้วไม่ได้รหัสโหวตออกมาอย่างถูกต้อง โดยเราจัดแบ่ง Folder ตามรอบที่ส่งมาจากฝั่งญี่ปุ่น โดยคนที่กำหนดชื่อเป็นฝั่งญี่ปุ่น เพราะต้องให้ทางนั้นกำหนดรหัสอ้างอิงที่เข้าใจง่ายสำหรับคนทำงานฝั่งต้นทางที่มีจำนวนแผ่น และต้องดูแลจัดการบัตรโหวตจำนวนมาก เพราะจำนวนคนฝั่งญี่ปุ่นน้อยกว่าฝั่งไทยมาก เราต้องคิดถึงการจัดการหน้างานฝั่งนั้นเป็นหลัก

ในโครงการนี้ในส่วนของการโหวต เรามีทีมงาน 2 ส่วน คือทีมกรอกมือ และกดโหวต แล้วนำรหัสโหวตที่โหวตเสร็จแล้วมาใส่ใน Google Sheets ส่วนอีกทีมคือทีมที่ผมลงมาช่วยเป็นส่วนหนึ่งของทีมงาน ซึ่งทำผ่าน OCR โดยจุดรวมของรหัสโหวตทั้ง 2 ทีมนี้ คือใช้ Google Sheets ตัวหนึ่ง เพื่อใช้สำหรับทำงานร่วมกันเพื่อแชร์ข้อมูลรหัสโหวต และการแก้ไขข้อมูล โดยทั้ง 2 ทีมมีคนกว่า 10 คนช่วยกันดู ช่วยกันแก้ไขรหัสโหวต เราเก็บรหัสโหวตต่างๆ พร้อมกับชื่อไฟล์รูปจากใน Google Drive เพื่อช่วยอ้างอิงย้อนกลับไปยังรูปต้นฉบับที่รหัสโหวตนั้นถูกกรอกมา เพราะหากรหัสโหวตนั้นใช้ไม่ได้ด้วยเหตุผลใด ๆ เราสามารถกลับไปค้นหาได้ง่าย

ในรอบส่งรหัสโหวตก่อนประกาศผลด่วนเมื่อเราได้รับการยืนยันรูปที่จะทำ OCR ได้แล้ว เราเอารูปเหล่านั้นไปเข้า OCR ทันที แล้วพบว่าความเร็วและข้อผิดพลาดมีเยอะพอสมควร ในระดับความผิดพลาด ~35% และความเร็วควรจะเร็วได้มากกว่านี้

แต่หลังจากรอบผลด่วนเราปรับปรุงกระบวนการเพิ่มด้วยการใช้โปรแกรมที่ชื่อ XnView เข้ามาเพื่อทำ resize/crop แบบ batch (GitHub – Source Code) ในส่วนของรูปก่อนส่งเข้า OCR เพื่อให้ตัว OCR มันอ่านเฉพาะจุดที่จำเป็นต้องอ่าน และได้ผลตอบกลับที่เร็วขึ้น โดยรูปหมื่นกว่ารูปผ่านกระบวนการ batch นี้ เพื่อช่วยเรื่องลดความผิดพลาดจาก OCR ให้ได้มากที่สุด และยังลดจำนวนข้อมูลที่จะต้องส่งขึ้นระบบของ Google Cloud Vision API ได้ด้วย เราเคยจับเวลา รูปบัตรโหวตกว่า 2,000 รูป เราใช้เวลาไม่ถึง 15 นาที โดยนับเวลาตั้งแต่ resize/crop รูปบัตรโหวตจำนวนดังกล่าว มาจนได้ตัวเนื้อ Text กลับออกมาจาก Google Cloud Vision API กว่า 1,800 รายการ ซึ่งเกือบทั้งหมดที่สามารถนำไปส่งรหัสโหวตเข้าระบบได้ทันที ระดับความผิดพลาดลดต่ำลงเหลือ ~20% นั้นทำให้เราได้ประโยชน์จากการใช้ไฟล์รูปภาพแทน PDF เพราะเราสามารถหาชุดโปรแกรมที่สามารถทำการ resize/crop ได้ง่ายกว่า

รูปภาพต้นฉบับ

จะได้รูปภาพที่โดน resize/crop แบบด้านล่าง

 

สำหรับ OCR ที่เราใช้คือ Google Cloud Vision API  ด้วยเหตุผลตั้งต้นดังนี้

  1. การหา OCR Library แบบ Offline ไม่น่าจะคุ้มค่า เพราะคิดบนฐานค่าใช้จ่ายหากซื้อ License หรือหากใช้ Open source ก็ต้องแน่ใจว่าจะใช้งานได้จริง เราลองผิดลองถูกจุดนี้ไม่ได้มากนัก คำตอบของโจทย์จึงตกมาที่ Cloud Service แทน
  2. การเชื่อมต่อกับ Google Sheets API บน Credential ตัวเดียวกันได้ ทำให้การพัฒนาส่วนนี้เร็วขึ้น

แต่สุดท้ายในเหตุผลข้อที่ 2 ไม่ได้ถูกนำไปใช้หลังจากวันประกาศผลด่วน แม้จุดประสงค์คือส่งรหัสโหวตขึ้น Google Sheets ให้ทีมงานคนอื่นเห็นรหัสโหวตชุดนั้นร่วมกันได้ทันที แต่เจอปัญหาใหญ่คือติด rate limit API และทำเรื่องของ request จากทีม support ของ Google แล้วการตอบสนองไม่ทันต่อการใช้งาน (รอตอบกลับ 3 วัน) ผมจึงตัดสินใจย้ายไปใช้ฐานข้อมูลอย่าง MariaDB บน Cloud แทน แล้วเอารหัสโหวตที่ได้จาก OCR ใส่ย้อนหลับไปบน Google Sheets ด้วยมือ (Google Sheets API – Usage Limits = 500 requests per 100 seconds per project, and 100 requests per 100 seconds per user.)

ในขั้นตอน OCR จนได้รหัสโหวตมานี้ ช่วยลดจำนวนงานหลังบ้านที่จะต้องกรอกรหัสโหวตลงใน Google Sheets ได้เยอะมาก โดยเราเหลือกำลังคนไว้แก้รหัสโหวตที่ผิดพลาดประมาณ 15-20% ที่เหลือแทนได้

ในส่วนของ Script ที่เราใช้ส่งรูปขึ้น Google Cloud Vision API นั้น เราใช้ PHP ที่เขียนแบบ CLI เพื่อส่งไฟล์รูปข้างต้นขึ้น Google Cloud Vision API เพื่อให้ได้ Text ออกมา แล้วใช้ Regular expression กรองรหัสโหวตตาม pattern ที่กำหนดออกมา เป็นไฟล์แบบ CSV ไฟล์ (GitHub – Source Code)

เหตุผลที่เราใช้ CSV เพราะมันสามารถ import เข้าฐานข้อมูลผ่าน HeidiSQL เครื่องมือจัดการฐานข้อมูล MariaDB (ใช้งานกับ MySQL หรือ SQL Server ก็ได้) ได้ทันที และยังสามารถเปิดแก้ไขบน Spreadsheet อย่าง Microsoft Excel หรือ Google Sheets ได้ด้วย

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

บางคนอาจจะคิดว่าทำไมไม่ใช้ฐานข้อมูลกลางเชื่อมต่อกันไปเลย ทำไมใช้ CSV โยนให้โปรแกรมส่งรหัสโหวตอัตโนมัติ?
– เหตุผลคือเรื่องกระจายเครื่องไปหลาย ๆ เครื่องเพื่อส่งรหัสโหวต ตัวโปรแกรมดังกล่าวติดตั้งง่ายไม่ซับซ้อนมาก และคัดลอกตัว Project และ CSV ของรหัสโหวต ปรับค่านิดหน่อย ก็เริ่มต้นทำงานได้แล้ว การเชื่อมฐานข้อมูลกลางอาจจะต้องทำ whitelist IP ฯลฯ อีกหลายตัวเพื่อป้องกันโดน hack อีกชั้น ซึ่งยุ่งยากเกินไป

สำหรับตัวโปรแกรมที่ใช้ในการส่งรหัสโหวตแบบอัตโนมัตินั้น ที่ชื่อ Katalon Studio พระเอกของงานนี้ ซึ่งเป็นเครื่องมือ automation testing solution ของนักพัฒนาซอฟต์แวร์ที่ โดยอ่านข้อมูลรหัสโหวตจากไฟล์ CSV ไปส่งลงฟอร์มของเว็บ AKB48

ตัว script ภายในเขียนด้วย groovy (GitHub – Source Code) ดักจับผลการส่งรหัสโหวตมี 4 สถานะดังนี้

  1. OK – รูปซ้ายบน
    เราดัก Keyword “投票完了” ที่หมายถึง Vote completed
    สถานะลงคะแนนโหวตสำเร็จ เก็บรวบรวมไปทำข้อที่ 2 อีกทีตอนที่ไม่มีรหัสโหวตส่งเข้าระบบเพื่อบันทึกวัน-เวลา และยืนยันผลอีกรอบ
  2. Already – รูปขวาบน
    เราดัก Keyword “入力したシリアルナンバーは既に投票済みです。” ที่หมาย The serial number you have entered has already been voted.
    เป็นสถานะที่บอกว่ารหัสโหวตนี้ถูกใช้งานกับผู้ลงเลือกตั้งคนนี้ โดยมีเวลากำกับ
    โดยเราจะต้องนำผลของหน้านี้ใช้ Regular expression เอาชุดข้อมูลวันและเวลาที่โหวตออกมาใส่ลงฐานข้อมูลด้วยเพื่อยืนยันวัน-เวลา
  3. Error – รูปขวาล่าง
    เราดัก Keyword “エラーが発生しました。” ซึ่งหมายถึง An error occurred.
    เกิดจากเว็บ AKB48 เกิดข้อผิดพลาด โดยถ้าเราได้ข้อความตัวนี้ คือโหวตไม่เข้า และเท่าที่เจอ คือรหัสโหวตใช้งานได้ เราต้องเอาไปเข้ากระบวนการสำหรับส่งรหัสโหวตเข้าเว็บอีกรอบ
  4. Failed – รูปซ้ายล่าง
    เราดัก Keyword “入力されたシリアルナンバーは無効であるか既に投票済みです。” ที่หมายถึง The serial number entered is invalid or already voted.
    ตรงนี้จะมี 2 ส่วน คือรหัสโหวตผิดจริง ๆ หรือรหัสโหวตถูกนำไปใช้กับผู้สมัครคนอื่นแล้ว หากรหัสโหวตถูกต้องโดยเทียบกับบัตรโหวต แสดงว่ารหัสโหวตใบนั้นถูกนำไปโหวตกับผู้สมัครคนใดคนหนึ่งที่ไม่ใช่คนที่เรากำลังโหวตอยู่ วิธีต่อไปคือเอารหัสดังกล่าวไปกรอกให้กับผู้สมัครคนอื่น ๆ ถ้าคนไหนขึ้นสถานะแบบข้อที่ 2. ก็คือรหัสโหวตนั้นถูกใช้โหวตผู้สมัครคนนั้นไปก่อนหน้านี้

รูปแบบหน้าทั้ง 4 หน้าที่จะเจอเมื่อเราส่งผลโหวต


จากการใช้ Katalon Studio เราจะเก็บผลการทำงานทั้ง HTML ไฟล์ และ Screenshot ของหน้าผลการโหวตเป็น JPEG ด้วย เพื่อใช้ในการตรวจสอบต่อไปหลังจบรอบโหวต

ในช่วงก่อนประกาศผลด่วนเราไม่ได้ตรวจสอบเคสในข้อที่ 3. และ 4. แยกออกจากกัน ทำให้เราพลาดคะแนนบางส่วนไปเพราะเว็บรับรหัสโหวต AKB48 ไม่ได้เสถียรตลอดเวลา จะมีการส่ง “An error occurred.” ออกมาอยู่เรื่อยๆ แม้แต่ช่วงวันท้าย ๆ ก็ยังไม่ได้แก้ไขให้ดีขึ้น มีอยู่หลายช่วงที่เราส่งรหัสโหวตไปกว่า 1,000 รายการ แล้วโดนตีตกด้วย An error occurred. อยู่เกือบ 600 รายการ และสุดท้ายทั้งหมดที่โดนตีตกเป็นรหัสโหวตที่ใช้งานได้ทุกตัว ทำให้เราต้องคัดแยกเพื่อให้ทีมหลังบ้านที่อ่านรหัสโหวตผิดพลาดไม่ต้องไปอ่านข้อมูลที่เกิดจากตัวเว็บ AKB48 แจ้งความผิดพลาดทั้ง ๆ ที่รหัสโหวตไม่ผิดอีก เพื่อลดงานฝั่งคนแก้ไขรหัสโหวตลง

เมื่อรหัสโหวตทุกส่วนส่งครบหมดจะเหลือเฉพาะรหัสโหวตที่โหวตได้ และรหัสโหวตที่โหวตไม่ได้ เราจะเอา log ของการส่งรหัสโหวตครั้งนั้นมาอ่านด้วย PHP ที่เป็น script ตัวอ่าน log แล้วเข้าไป flag สถานะในฐานข้อมูลตามแต่ละรหัสโหวตที่มี เพื่อบอกว่าโหวตสำเร็จหรือไม่ แล้วทำการสรุปรหัสโหวตที่โหวตได้ และรหัสโหวตที่โหวตไม่ได้ แยก Worksheet บน Google Sheets ออกจากกัน โดยในส่วนของ Worksheet ที่ใส่รหัสโหวตที่ส่งแล้วผิดพลาด จะมีทีมงานอีกส่วนเข้ามาช่วยกันอ่านไฟล์รูปบัตรโหวตและกรอกรหัสโหวตที่ถูกต้องลงไปแทน แล้วเมื่อจบการแก้ไขในแต่ละ Worksheet จะรวบรวมแล้วใช้โปรแกรมอัตโนมัติส่งเข้าเว็บโหวตอีกรอบ และในส่วนรหัสโหวตที่โหวตเรียบร้อย จะมีรอบสำหรับทบทวนวัน-เวลาที่โหวตเพื่อยืนยันรหัสโหวตว่าเมื่อโหวตเข้าไปแล้ว

โดยในขั้นตอนทบทวนวัน-เวลา เราจะใช้ script ส่งรหัสโหวตชุดเดิมส่งรหัสโหวตที่ต้องการวัน-เวลาส่งเข้าไปที่เว็บ AKB48 จนได้สถานะตามข้อที่ 2 แล้วใช้ script อีกชุดเข้าไปอ่านวัน-เวลาในไฟล์ HTML ที่บันทึกไว้ เพื่อนำไปอัพเดทลงฐานข้อมูลเมื่ออัพเดทเสร็จครบทั้งสถานะและวัน-เวลาโหวต เราจะเอาผลทั้งหมดกลับขึ้นไปที่ Google Sheets เพื่อสรุปผลการโหวตในแต่ละรอบเพื่อปิดงานรอบนั้น (ในขั้นตอนทบทวนวัน-เวลานี้เราเอารหัสโหวตที่กรอกด้วยมือไปก่อนหน้านี้ของอีกทีมหนึ่ง มาเข้ากระบวนการนี้ด้วยเช่นกัน)

นั้นหมายความว่า ทุก ๆ รหัสโหวตเราส่งเข้าเว็บ AKB48 เราจำเป็นต้องส่งรหัสโหวตเข้าเว็บโหวตอย่างน้อย 2 ครั้ง แต่ผลดีคือ มันช่วยทำให้เราสรุปยอดในแต่ละวันว่าเราส่งรหัสโหวตเข้าไปได้เท่าไหร่ และช่วยให้เราเก็บคะแนนที่ตกหล่นกลับมาโหวตได้อีกพอสมควร

ตัวอย่างการทำงานในการส่งรหัสโหวตด้วย Katalon Studio

สำหรับหน้ารายงานรหัสโหวต และจำนวนโหวตที่ Actual Vote ช่วงแรกเราใช้ Firebase Realtime Database ซึ่งทำการ Sync ข้อมูลกับ Google Sheetes อีกที ช่วงแรกข้อมูล Realtime มาก กดอัพเดทจำนวนคะแนนฝั่งหน้าเว็บรายงานขึ้นคะแนนใหม่ทันที แต่ด้วยความที่เราไม่ได้ optimize อะไรเลย (คือไม่มีเวลาทำ) สุดท้ายมันก็ไม่ได้ Realtime ตลอด เจออาการ Push ไม่ทำงาน เพราะเราไม่ได้ Index ข้อมูล มันเลยหยุด Push เพราะด้วยจำนวนของ node (รหัสโหวต) เริ่มเยอะขึ้น แถมเราเจอ charge ค่า B/W ของ Firebase เยอะตามไปด้วย เลยเปลี่ยนแผนใหม่เป็นการใช้ไฟล์ JSON data แบบอัพมือแทน โดยก็แค่ Sync จาก Google Sheets ไป export เป็นไฟล์ JSON data เดี่ยว ๆ แล้วฝั่งทีมเว็บส่วนรายงานผลแค่เอาไฟล์ไปวางที่เดิมก็จบงาน ลดค่าใช้จ่ายไปได้เยอะมาก แต่ก็มาหนักฝั่ง client ซึ่งก็เป็นเรื่องที่ช่วยไม่ได้ เพราะเอาเร็วเข้าว่า แล้วช่วง 2-3 วันสุดท้ายเราไม่ได้รายงานคะแนนสุดท้าย เพราะคิดว่ารอสรุปยอดทีเดียวหลังปิดโหวตดีกว่า เพื่อให้ทีมงานทุกส่วนได้โฟกัสกับการหาบัตรโหวต และส่งรหัสโหวตเข้าระบบ AKB48 ให้ได้จนหมดโดยไม่ตกหล่น และยืนยันผลให้พร้อมทุกอย่าง เพราะเราพลาดแบบรอบผลด่วนอีกไม่ได้แล้ว

ในส่วนของเครื่องคอมฯ ที่ส่งรหัสโหวตนั้น เราใช้ทั้งหมด 3 ตัวทำงานสลับกัน มี 1 ตัวทำงานตลอด 24 ชั่วโมง 5 วันติดต่อกันเพื่อโหวตเข้าระบบ และทบทวนผลการโหวตออกมาเป็นวัน-เวลาที่โหวตเพื่อให้แน่ใจว่าคะแนนทุกคะแนนที่ถืออยู่จะเข้าระบบจริง ๆ ซึ่งหากจำนวนคะแนนในมือเยอะกว่านี้ อาจส่งไม่ทัน เพราะจากที่ลองทดสอบค่าเฉลี่ยนในการส่งโหวต สามารถทำความเร็วได้ที่ 600-800 รหัสโหวตต่อชั่วโมง (อย่าลืมว่าเราต้องเก็บตกจากเหตุการณ์เจอหน้าเว็บ Error และทวนวัน-เวลาโหวตอีก) แต่เราก็ได้เตรียมแผนรองรับไว้แล้ว ด้วยการเตรียมเช่า Cloud VPS ที่อยู่ญี่ปุ่นเพิ่มเติมสำหรับส่งรหัสโหวตเพิ่มเติมได้ทันที (คิดว่าภายใน 4-6 ชั่วโมงน่าจะสร้างเครื่อง และพร้อมส่งรหัสโหวตได้อย่างน้อย 4 ตัว หรือเพิ่มความเร็วเป็น 2,000-3,000 โหวตต่อชั่วโมง)

สรุปว่าโครงการนี้เน้นถึกเยอะมาก script อะไรต่าง ๆ บางส่วนก็เผา และ workaround กันแบบสุด ๆ เนื่องจากรีบ และไม่มีเวลามาคิดเรื่อง seamless มากนักในบางขั้นตอน (เพราะงานประจำก็ต้องทำ คะแนนที่ต้องส่งก็เยอะขึ้นกว่าที่คาดหวังไว้ด้วย ต้องเผื่อเวลาตกหล่นไว้อย่างน้อย 1-2 วัน) ตามตารางกราฟด้านล่าง

ช่วงวันประกาศผลเลือกตั้ง ค่อนข้างลุ้นมาก เพราะตอนที่ประกาศแล้วผ่านคะแนนของโครงการไปแล้ว แล้วน้องยังไม่ได้ประกาศชื่อ โดนแซวว่า “พี่ฟอร์ดทำโปรแกรมโหวตผิดคนป่าวพี่” ทีมงานก็ใจคอไม่ดี ผมก็ใจคอไม่ดี เพราะลุ้นมาก แล้วเราทบทวนรหัสโหวตและคะแนนกันเยอะมาก

แล้วสุดท้ายก็เป็นแบบวิดีโอข้างล่างเนี่ยแหละครับ

หากมีอะไรอัพเดทหรือตกหล่น เดี่ยวค่อย ๆ อัพเดทใน blog ตอนนี้เพิ่มเติมอีกที เพราะตอนนี้นึกออกมาได้ประมาณนี้

ทิ้งท้าย ด้านล่างคือสรุป Workflow การทำงานในช่วง 7 วันสุดท้ายของการโหวต

 

 

 

ว่าด้วยการจัดเวลาไลฟ์ของเมมเบอร์ BNK48 ใน VOOV

ถ้าได้ตาม 48G ฝั่งญี่ปุ่นไลฟ์ใน Showroom มาก่อน จะหงุดหงิดกับการจัดเวลาไลฟ์ของน้อง ๆ BNK48 ใน VOOV อยู่พอสมควร เพราะฝั่งญี่ปุ่น การไลฟ์ใน 1 วันของเมมเบอร์บางคนก็มากัน 1-2 รอบก็มี บางคนเดือนนึงจะมาสักครั้ง หรืออาทิตย์นึงเจอกันครั้งนึงก็มี หรือว่าง่าย ๆ จัดสรรเวลากันแบบมาเรื่อยๆ มากันตลอด ไม่ใช่หายไปทั้งวง ผมตามอยู่เกือบ 10 คน วันนึงต้องได้ดู Showroom สักคน แล้วเวลาที่เมมเบอร์ฝั่งญี่ปุ่นไลฟ์เหมือนจะไม่ได้กำหนดระยะเวลาตายตัวว่า 1 ชั่วโมง บางคนยาว 2-3 ชั่วโมงก็มี บางคนมา 10-15 นาทีก็มี แล้วก็มักเจอไลฟ์พร้อม ๆ กันหลายคน ยิ่งช่วงหัวค่ำของที่โน้นนะ เปิด Showroom เข้าไป เจอ 5-10 คนนี่เรื่องปรกติมาก (อันนี้เกิดจากประสบการณ์ที่ได้ติดตาม แน่นอนว่าดีลธุรกิจจริงๆ เป็นอย่างไรก็อีกเรื่อง)

อย่างวันก่อนเปิดตัวโปสเตอร์เลือกตั้ง ระหว่างั้น ก็มีเมมเบอร์ญี่ปุ่น เค้าก็ไลฟ์ซ้อนกับรายการนั้นไม่ได้หยุดไลฟ์แต่อย่างใด แล้วช่วงที่มีไลฟ์เลือกตั้ง มักมีเมมเบอร์เปิดไลฟ์ใน Showroom ไปพร้อม ๆ กับแฟนคลับ พูดคุยกับแฟนคลับไป ดูไลฟ์เลือกตั้งไปด้วยก็มี

จากสิ่งที่พบเจอมา แล้วเอามาเทียบกับฝั่ง BNK48 ก็จะเห็นว่า หากสามารปรับเปลี่ยนให้ไลฟ์แบบรับผิดชอบตัวเอง จัดเวลาเอง มีกลยุทธในการไลฟ์เพื่อดึงฐานแฟนคลับ ดูว่าเวลาไหนเหมาะสมของแต่ละคน มีการนัดแฟนคลับว่าวันนี้วันนั้น ผมว่าการไลฟ์จะดูน่าติดตามกว่านี้ ยิ่งตอนนี้มีรุ่น 1 และ 2 คิดว่าจำนวนเมมเบอร์ก็น่าจะเยอะพอที่จะปรับเปลี่ยนรูปแบบการจัดเวลาในการไลฟ์ได้บ้าง อีกทั้งผลดีก็ตกอยู่กับน้องๆ เอง โดยเฉพาะรุ่น 2 ที่ยังไม่มีฐานแฟนคลับมากนัก เพราะน้องๆ ได้สร้างฐานแฟนคลับได้ง่ายมากขึ้น แล้วไม่จำเป็นต้องวันละ 1 ชั่วโมงพอดี แต่อาจจะนิดๆ หน่อยๆ แต่เก็บให้ครบเดือนละ 1-2 ชั่วโมง ก็น่าจะเป็นทางออก (ถ้าไลฟ์ชนกันก็ไม่น่าจะมีผลอะไรเพราะ VOOV ดูย้อนหลังได้อยู่ดี)

แล้วยิ่งช่วงนี้มีเลือกตั้งเมมเบอร์ฝั่งญี่ปุ่นเค้าไลฟ์กันเยอะมาก มากันทุกวันเลยก็มีบางคน ก็ออกจะเสียดายโอกาศหลายๆ อย่างเหมือนกันนะ

ตัวอย่างกลยุทธในการไลฟ์เพื่อดึงฐานแฟนคลับ ที่น่าสนใจของฝั่งญี่ปุ่น “1 Year Miracle โอนิชิ โมโมกะ เด็กสาวตี5ครึ่ง ปาฏิหาริย์ที่เกิดจากความพยายามในอีกรูปแบบหนึ่ง

ทยอยเปลี่ยนจากใช้ HDD External 3.5″ มาใช้ HDD External 2.5″

ช่วงต้นปี HDD External 2TB 2.5″ ราคาลงมาเหลือประมาณ 2,2xx – 2,3xx บาท (ล่าสุดเหลือ 1,990 บาท) ก็เลยทยอยๆ ซื้อเก็บมาเรื่อยๆ ตอนนี้ได้มา 3 ลูกแล้ว (ได้พื้นที่มา 6TB)

แต่การซื้อ HDD ดังกล่าวไม่ใช่เอามาเก็บข้อมูลเท่านั้น แต่เอามาทดแทน HDD External 3.5″ ตัวเก่าๆ ที่ใช้มานาน (3 ปีบ้าง 5 ปีบ้าง) แม้ทั้งหมดยังคงทำงานได้ดี แต่ก็ด้วยอายุที่มาก ความเสี่ยงก็มากตาม

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

ซึ่งลูกเก่าที่กำลังจะเป็นตัวสำรองข้อมูล กำลังคิดว่าจะซื้อกล่อง super lock เพิ่มเติมเพื่อมาใส่ HDD กลุ่มนี้ เพื่อเก็บรักษาสภาพให้เหมาะสม

ปล1. เหตุผลที่ไม่ซื้อ 3.5″ มาแทนตามเดิม แต่ใช้ 2.5″ แทน เพราะเรื่องความคล่องตัวในการใช้งานเป็นหลัก เพราะจากที่ใช้ 3.5″ มา 7 ตัวค่อนข้างเปลืองพื้นที่มาก ยังไม่รวมต้องหาชุดปลั๊กไฟเพิ่มเติมอีก
ปล2. เหตุผลที่ไม่ซื้อ 4TB หรือมากกว่า เพราะเน้นการกระจายความเสี่ยงเรื่องการเสียของ H/W ด้วย (ราคา 4TB ถูกกว่า 2TB x2 อยู่นิดหน่อย)

ไปงาน BNK48 Campus Card Handshake

ว่าจะเขียนลง blog แต่คิดว่าเขียนลง facebook แล้วเสียดายของ เลยเอามาลงเก็บไว้ดีกว่า

ตัวงาน BNK48 Campus Card Handshake จัดที่ MCC Hall ชั้น 4 เดอะมอลล์บางกะปิ ซึ่งงานนี้ไปจับมือน้องๆ BNK48 จำนวน 3 คน

(2 คนเป็นคนที่เราติดตาม ส่วนอีก 1 เป็นคนที่คุณแฟนติดตาม แต่มาจับมือไม่ได้เพราะติดงานเลยมาเป็นตัวแทนคุณแฟน)

ตัวงานถ่ายรูปมาไม่ได้ (ถ่ายป้ายโปรเจคมิวสิคมารูปนึง กลัวเค้าด่าเหมือนัน 555555)

รีพอตว่าพูดอะไรบ้างกับน้องๆ  3 คน

  1. มิวสิค (รอประมาณ 40 นาที)
    สิค: (เห็นหน้าเรา) ไม่จับมืออ่ะ งอน (ทำหน้างอนใส่ เสียไป 2 วินาที)
    ผม: อ้าว พี่ไม่ได้คน tag รูปหน้ามีมใน IG น๊า (ที่รู้เพราะมีคนโดนมาก่อนหน้านี้หลายคน)
    สิค: อ้าวเหรอ โอ๋ๆๆ (น้องก็จับมือเหมือนเดิม)
    ผม: พี่มาบอกว่า พี่ลงบัตรโหวตเลือกตั้ง AKB48 ไปให้แล้วนะ เราก็สู้ๆ นะ พยายามให้เต็มที่
    สิค: ขอบคุณมากๆ เลยค๊าาา สู้ๆ ไปด้วยกันเนอะ
    (หมดเวลา) (แล้วก็โบกมือบ๊าบาย)
  2. เมษา (รอประมาณ 5 นาที)
    ต๋า: สวัสดีค๊าาา (จ้องตา)
    ผม: (ลืม นึกอะไรไม่ออก เวลาหายไป 2 วินาที) ช่วงนี้เรียนหนัก แล้วยังต้องซ้อมหนักอีก ยังไงก็สู้ๆ น๊า เป็นกำลังใจให้
    ต๋า: จ้าา ต๋าก็สู้อยู่เหมือนกัน
    (หมดเวลา) (แล้วก็โบกมือบ๊าบาย)
  3. อิซึตะ รินะ (รอประมาณ 5 นาที)
    รินะ: สวัสดีค๊า
    ผม: สวัสดีครับ ช่วงนี้เรียนภาษาไทย สู้ๆ นะ (พยายามค่อยๆ พูด กลัวฟังไม่ทัน)
    รินะ: ค๊า ช่วงนี้เรียนภาษาเยอะมากเลย
    ผม: จะมาบอกว่า ภาษาไทยเราดีขึ้นเยอะเลยนะ
    รินะ: จริงป่ะ ดีใจๆๆๆ (รีเอคน้องมาเต็มมาก) ขอบคุณนะค๊า
    (หมดเวลา) (แล้วก็โบกมือบ๊าบาย)

จบรีพอต 3 คนในงานครั้งนี้

แล้วด้วยความเป็นคามิโอชิมิวสิค ก็เลยดูกิจกรรมโปรโมทเลือกตั้งของน้อง ร่วมส่งน้องไป AKB48 53rd Single World Senbatsu General Election ซึ่งต้องชมว่าทีมงานทำมาได้ดีมาก มีป้ายหาเสียง มีใบปลิว มีกลุ่มก้อนที่นำเสนอข้อมูลต่างๆ ของเว็บ http://www.music48project.com ภายในงาน ซึ่งเป็นการใช้โอกาสนี้ในการโปรโมทได้ดี ก็เอาใจช่วยทีมงานโปรเจคนี้ด้วย
(ผมก็อยู่ในกลุ่มที่เค้าปรึกษาโปรเจคนี้ ตั้งแต่สมัยจอ LED แล้วแต่ไม่ได้อยู่ในทีมลงมือทำ เป็นพวกออกความคิดเห็น กับลงเงินช่วยเป็นหลัก)

สำหรับบรรยากาศงาน คือไปถึงประมาณ 13:05 น. เลยไม่ค่อยรู้ว่าช่วงเช้าวุ่นวายแค่ไหน แต่จากที่เจอในช่วงเวลานั้นคือ

– สถานที่จัดงานคับแคบกว่ารอบ BNK48 2nd Single Koisuru Fortune Cookie handshake event ที่จัดไปวันที่ 13-14 มกราคม พ.ศ. 2561 ที่ผ่านมา
– เข้าใจว่าการรองรับสถานที่จะคาดเดาจากจำนวนบัตรจับมือเป็นหลัก นั้นทำให้ผู้จัดงานคาดว่าจะมีคนเข้ามาในงานน้อยกว่ารอบก่อน แต่ในความเป็นจริงแล้วไม่ใช่ เพราะรอบก่อนนั้น จำนวนบัตรมากกว่า แต่จำนวนบัตรจับมือต่อหนึ่งคนเยอะกว่า ทำให้จำนวนคนในงานน้อยกว่ารอบนี้ ที่จำนวนบัตรจับมือต่อหนึ่งคนน้อยและกระจายไปในจำนวนคนที่มากกว่า ทำให้กลายเป็นว่างานแออัดมากกว่าเดิมมาก
– จุดตรวจสัมภาระรอบนี้เหมือนเตรียมสเกลได้ พอรู้ว่าคนเริ่มเยอะ ก็เปิดเลนตรวจของเพิ่ม คือตอนแรกมี 4 แถว แถวยาวทะลุจาก MCC ไปถึงหน้าเธียร์เตอร์อีกฝั่งเลย แต่ก็ต่อแถวเป็นระเบียบดี ติดแค่หาหางแถวยากหน่อย เจ้าหน้าที่ไม่พอช่วงนั้น
– จุดเทรดสินค้าระหว่างแฟนคลับจัดห่างจากจุดตรวจสัมภาระไม่มากนัก ทำให้เกิดคอขวดก่อนเข้าสู่จุดจับมือพอสมคว
– จุดขายสินค้าอยู่ภายในงานที่ต้องมีบัตรจับมือก่อนถึงจะเข้าไปซื้อสินค้าได้ ถือแม้จะคัดกรองคนได้ แต่ก็ทำให้ภายในโซนจับมือแออัดมากขึ้น
– เลนจับมือเหมือนจะรู้แล้วว่าใครจะมีคนมาจับมือเยอะน้อย เลยมีความกว้างของเลนจับมือไม่เท่ากัน
– เลนคนที่ได้รับความนิยมสูงๆ มีจำนวนขดของแถวประมาณ 5-7 ขดโดยประมาณ ระยะเวลารอก็ 30-60 นาที ต่อรอบ ก็ทำใจรอได้เลยสำหรับคนที่จะจับมือคนความนิยมสูง
– คนเยอะจนจนเครื่องปรับอากาศทำงานไม่ทัน บางจุดร้อนจนเหงื่อออก แม้ว่านั่งหรือยืนเฉยๆ
– The Mall รอบนี้เหมือนรู้ว่าคนมาเยอะ มีจุดขายของเฉพาะมาขายน้ำ รับสมัครบัตร M Card เพิ่มยอดขายหน้างาน มีบูทสินค้าหลาย บูทมาเปิด ก็ดูเป็นการเปิดโอกาสของงานระดับนี้ไปในตัว แต่รอบต่อไปจัด BITEC แหละ น่าจะสบายขึ้น แล้วจะกลับมาจัด เครือ The Mall อีกไหม อันนี้ก็คงดูที่กระแสคนในอนาคต

ปิดท้าย ได้ของติดไม้ติดมือกลับมานิดหน่อย
– ใบปลิวหาเสียและนามบัตรโปรโมท Music, We Choose You! เป็นโปรเจคเลือกตั้ง ที่ขนมาเต็มที่ ยืนแจกหาเสียงให้น้อยตลอดทั้งงาน
– ของแจกหน้าเลนจับมือ ที่โหดคือของรินะจัง มีพี่ผู้หญิงท่านหนึ่งเอาบัตร Starbucks Gift Card มาแจกตรงเลนรินะหลังจากจับมือเสร็จด้วย โหดมาก โคตรทุ่มทุน น่าจะใบละ 100 บาทมั้ง
– แคนแคนนี่ก็โอชิผม ไปตามเก็บกลับมาบ้านนิดหน่อย แฮะๆๆๆ
– ได้รูป ฟตซ เมษา หนึ่งในโอชิเรา ติดไม้ติดมือกลับมานิดหน่อย เดินๆ หาในราคาที่พอรับได้ เลยจัดมาก่อน