แอปการค้นหาร้านขายของเล่นที่มีฐานข้อมูลระบบคลาวด์ รันไทม์แบบไม่ใช้เซิร์ฟเวอร์ และการผสานรวมโอเพนซอร์ส

1. ภาพรวม

ลองนึกภาพว่าคุณกำลังเดินเข้าไปในร้านขายของเล่นทางออนไลน์หรือที่หน้าร้าน ซึ่งคุณค้นหาของขวัญที่เหมาะที่สุดได้อย่างง่ายดาย คุณสามารถอธิบายสิ่งที่ต้องการ อัปโหลดรูปภาพของเล่น หรือแม้แต่ออกแบบสิ่งประดิษฐ์ของคุณเอง แล้วร้านค้าจะเข้าใจความต้องการของคุณในทันทีและมอบประสบการณ์การใช้งานที่ปรับให้เหมาะกับคุณ แนวคิดนี้ไม่ใช่ความฝันอันล้ำยุค แต่เป็นความจริงที่ขับเคลื่อนโดย AI, เทคโนโลยีระบบคลาวด์ และวิสัยทัศน์สําหรับอีคอมเมิร์ซที่ปรับเปลี่ยนในแบบของคุณ

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

โซลูชัน: แอปพลิเคชันเดโมนี้ช่วยแก้ปัญหานี้โดยตรง โดยใช้ความสามารถของ AI เพื่อมอบประสบการณ์การใช้งานที่เหมาะกับแต่ละบุคคลและราบรื่นอย่างแท้จริงด้วยการค้นหาตามบริบทและการสร้างผลิตภัณฑ์ที่ตรงกับบริบทการค้นหา

สิ่งที่คุณจะสร้าง

คุณจะทําสิ่งต่อไปนี้ได้

  1. สร้างอินสแตนซ์ AlloyDB และโหลดชุดข้อมูลของ Toys
  2. เปิดใช้ส่วนขยาย pgvector และโมเดล Generative AI ใน AlloyDB
  3. สร้างการฝังจากคำอธิบายผลิตภัณฑ์และทำการค้นหาความคล้ายคลึงแบบโคไซน์แบบเรียลไทม์สำหรับข้อความค้นหาของผู้ใช้
  4. เรียกใช้ Gemini 2.0 Flash เพื่ออธิบายรูปภาพที่ผู้ใช้อัปโหลดสำหรับการค้นหาของเล่นตามบริบท
  5. เรียกใช้ Imagen 3 เพื่อสร้างของเล่นตามความสนใจของผู้ใช้
  6. เรียกใช้เครื่องมือคาดการณ์ราคาที่สร้างโดยใช้ Gen AI Toolbox สําหรับฐานข้อมูลเพื่อดูรายละเอียดราคาของของเล่นที่สร้างขึ้นเอง
  7. ติดตั้งใช้งานโซลูชันใน Cloud Run Functions แบบ Serverless

ข้อกำหนด

  • เบราว์เซอร์ เช่น Chrome หรือ Firefox
  • โปรเจ็กต์ Google Cloud ที่เปิดใช้การเรียกเก็บเงิน

2. สถาปัตยกรรม

ขั้นตอนการส่งข้อมูล: มาดูรายละเอียดของการส่งข้อมูลผ่านระบบกัน

  1. การค้นหาตามบริบทด้วย RAG (Retrieval Augmented Generation) ที่ทำงานด้วยระบบ AI

ลองนึกภาพว่าแทนที่จะมองหาแค่ "รถสีแดง" ระบบจะเข้าใจสิ่งต่อไปนี้

"ยานพาหนะขนาดเล็กเหมาะสำหรับเด็กชายอายุ 3 ปี"

AlloyDB เป็นรากฐาน: เราใช้ AlloyDB ซึ่งเป็นฐานข้อมูลที่เข้ากันได้กับ PostgreSQL ที่มีการจัดการโดยสมบูรณ์ของ Google Cloud เพื่อจัดเก็บข้อมูลของเล่น ซึ่งรวมถึงคำอธิบาย, URL รูปภาพ และแอตทริบิวต์อื่นๆ ที่เกี่ยวข้อง

pgvector สําหรับการค้นหาเชิงความหมาย: pgvector ซึ่งเป็นส่วนขยาย PostgreSQL ช่วยให้เราจัดเก็บการฝังเวกเตอร์ของทั้งคําอธิบายของเล่นและคําค้นหาของผู้ใช้ ซึ่งจะเปิดใช้การค้นหาเชิงความหมาย ซึ่งหมายความว่าระบบจะเข้าใจความหมายที่อยู่เบื้องหลังคํา ไม่ใช่แค่คีย์เวิร์ดแบบตรงทั้งหมด

ความคล้ายคลึงแบบโคไซน์สำหรับความเกี่ยวข้อง: เราใช้ความคล้ายคลึงแบบโคไซน์เพื่อวัดความคล้ายคลึงเชิงความหมายระหว่างเวกเตอร์การค้นหาของผู้ใช้กับเวกเตอร์คำอธิบายของของเล่น เพื่อแสดงผลลัพธ์ที่เกี่ยวข้องมากที่สุด

ดัชนี ScaNN เพื่อความเร็วและความแม่นยำ: เราผสานรวมดัชนี ScaNN (Scalable Nearest Neighbors) เพื่อให้ได้ผลลัพธ์ที่รวดเร็วและแม่นยำ โดยเฉพาะเมื่อสินค้าคงคลังสำหรับของเล่นมีจำนวนเพิ่มขึ้น ซึ่งจะช่วยปรับปรุงประสิทธิภาพและการเรียกคืนของเครื่องมือค้นหาเวกเตอร์ได้อย่างมาก

  1. การค้นหาและการทำความเข้าใจตามรูปภาพด้วย Gemini 2.0 Flash

สมมติว่าผู้ใช้ต้องการอัปโหลดรูปภาพของของเล่นที่คุ้นเคยซึ่งต้องการใช้ค้นหาแทนการพิมพ์บริบทเป็นข้อความ ผู้ใช้สามารถอัปโหลดรูปภาพของของเล่นที่ชอบและดูฟีเจอร์ที่เกี่ยวข้องได้ เราใช้ประโยชน์จากโมเดล Flash ของ Gemini 2.0 ของ Google ซึ่งเรียกใช้โดยใช้ LangChain4j เพื่อวิเคราะห์รูปภาพและดึงบริบทที่เกี่ยวข้อง เช่น สี วัสดุ ประเภท และกลุ่มอายุเป้าหมายของของเล่น

  1. การสร้างของเล่นในฝันที่ปรับแต่งด้วย Generative AI: Imagen 3

ความมหัศจรรย์ที่แท้จริงเกิดขึ้นเมื่อผู้ใช้ตัดสินใจที่จะสร้างของเล่นของตัวเอง เมื่อใช้ Imagen 3 เราอนุญาตให้เด็กๆ อธิบายของเล่นในฝันโดยใช้พรอมต์ข้อความง่ายๆ ลองนึกภาพว่าคุณสามารถพูดว่า "ฉันอยากได้ตุ๊กตามังกรที่มีปีกสีม่วงและใบหน้าน่ารัก" แล้วเห็นมังกรตัวนั้นปรากฏขึ้นบนหน้าจอ จากนั้น Imagen 3 จะสร้างรูปภาพของของเล่นที่ออกแบบเอง ซึ่งช่วยให้ผู้ใช้เห็นภาพผลงานของตนอย่างชัดเจน

  1. การคาดการณ์ราคาที่ทำงานด้วยตัวแทนและกล่องเครื่องมือ Gen AI สําหรับฐานข้อมูล

เราได้ติดตั้งใช้งานฟีเจอร์การคาดการณ์ราคาซึ่งจะประมาณค่าใช้จ่ายในการผลิตของเล่นที่ออกแบบเอง ซึ่งทำงานด้วยตัวแทนที่มีเครื่องมือคำนวณราคาที่ซับซ้อน

Gen AI Toolbox สําหรับฐานข้อมูล: ตัวแทนนี้จะผสานรวมกับฐานข้อมูลได้อย่างราบรื่นโดยใช้เครื่องมือ Gen AI Toolbox สําหรับฐานข้อมูล ซึ่งเป็นเครื่องมือโอเพนซอร์สใหม่ของ Google ซึ่งช่วยให้ตัวแทนเข้าถึงข้อมูลแบบเรียลไทม์เกี่ยวกับต้นทุนวัสดุ กระบวนการผลิต และปัจจัยอื่นๆ ที่เกี่ยวข้องเพื่อให้ราคาโดยประมาณที่ถูกต้อง อ่านข้อมูลเพิ่มเติมได้ที่นี่

  1. Java Spring Boot, Gemini Code Assist และ Cloud Run เพื่อการพัฒนาการและการปรับใช้งานแบบ Serverless ที่มีประสิทธิภาพยิ่งขึ้น

แอปพลิเคชันทั้งหมดสร้างขึ้นโดยใช้ Java Spring Boot ซึ่งเป็นเฟรมเวิร์กที่มีประสิทธิภาพและปรับขนาดได้ เราใช้ประโยชน์จากฟีเจอร์ช่วยเขียนโค้ดของ Gemini ตลอดกระบวนการพัฒนา โดยเฉพาะสำหรับการพัฒนาส่วนหน้า ซึ่งช่วยเร่งวงจรการพัฒนาและปรับปรุงคุณภาพโค้ดได้อย่างมาก เราใช้ Cloud Run เพื่อทำให้ทั้งแอปพลิเคชันใช้งานได้ และ Cloud Run Functions เพื่อทำให้ฐานข้อมูลและฟังก์ชันการทำงานของเอเจนซีใช้งานได้เป็นปลายทางอิสระ

3. ก่อนเริ่มต้น

สร้างโปรเจ็กต์

  1. ในคอนโซล Google Cloud ให้เลือกหรือสร้างโปรเจ็กต์ Google Cloud ในหน้าตัวเลือกโปรเจ็กต์
  2. ตรวจสอบว่าเปิดใช้การเรียกเก็บเงินสำหรับโปรเจ็กต์ Cloud แล้ว ดูวิธีตรวจสอบว่าเปิดใช้การเรียกเก็บเงินในโปรเจ็กต์หรือไม่
  3. คุณจะใช้ Cloud Shell ซึ่งเป็นสภาพแวดล้อมบรรทัดคำสั่งที่ทำงานใน Google Cloud และโหลด bq ไว้ล่วงหน้า คลิก "เปิดใช้งาน Cloud Shell" ที่ด้านบนของคอนโซล Google Cloud

รูปภาพปุ่มเปิดใช้งาน Cloud Shell

  1. เมื่อเชื่อมต่อกับ Cloud Shell แล้ว ให้ตรวจสอบว่าคุณได้รับการตรวจสอบสิทธิ์แล้วและโปรเจ็กต์ได้รับการตั้งค่าเป็นรหัสโปรเจ็กต์ของคุณโดยใช้คําสั่งต่อไปนี้
gcloud auth list
  1. เรียกใช้คำสั่งต่อไปนี้ใน Cloud Shell เพื่อยืนยันว่าคำสั่ง gcloud รู้จักโปรเจ็กต์ของคุณ
gcloud config list project
  1. หากยังไม่ได้ตั้งค่าโปรเจ็กต์ ให้ใช้คําสั่งต่อไปนี้เพื่อตั้งค่า
gcloud config set project <YOUR_PROJECT_ID>
  1. เปิดใช้ API ที่จำเป็นโดยเรียกใช้คำสั่งต่อไปนี้ทีละรายการในเทอร์มินัล Cloud Shell

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

gcloud services enable alloydb.googleapis.com
gcloud services enable compute.googleapis.com 
gcloud services enable cloudresourcemanager.googleapis.com 
gcloud services enable servicenetworking.googleapis.com 
gcloud services enable run.googleapis.com 
gcloud services enable cloudbuild.googleapis.com 
gcloud services enable cloudfunctions.googleapis.com 
gcloud services enable aiplatform.googleapis.com

อีกทางเลือกหนึ่งสำหรับคำสั่ง gcloud คือผ่านคอนโซลโดยค้นหาผลิตภัณฑ์แต่ละรายการหรือใช้ลิงก์นี้

หากมี API ใดขาดหายไป คุณจะเปิดใช้ได้เสมอในระหว่างการติดตั้งใช้งาน

โปรดดูคำสั่งและการใช้งาน gcloud ในเอกสารประกอบ

4. การตั้งค่าฐานข้อมูล

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

มาสร้างคลัสเตอร์ อินสแตนซ์ และตาราง AlloyDB ที่ระบบจะโหลดชุดข้อมูลอีคอมเมิร์ซกัน

สร้างคลัสเตอร์และอินสแตนซ์

  1. ไปยังหน้า AlloyDB ใน Cloud Console วิธีที่ง่ายในการค้นหาหน้าส่วนใหญ่ใน Cloud Console คือค้นหาโดยใช้แถบค้นหาของคอนโซล
  2. เลือกสร้างคลัสเตอร์จากหน้านั้น

f76ff480c8c889aa.png

  1. คุณจะเห็นหน้าจอดังภาพด้านล่าง สร้างคลัสเตอร์และอินสแตนซ์ด้วยค่าต่อไปนี้ (ตรวจสอบว่าค่าตรงกันในกรณีที่คุณทำโคลนโค้ดแอปพลิเคชันจากรีโป)
  • cluster id: "vector-cluster"
  • password: "alloydb"
  • เข้ากันได้กับ PostgreSQL 15
  • ภูมิภาค: "us-central1"
  • เครือข่าย: "default"

538dba58908162fb.png

  1. เมื่อเลือกเครือข่ายเริ่มต้น คุณจะเห็นหน้าจอดังภาพด้านล่าง

เลือกตั้งค่าการเชื่อมต่อ
7939bbb6802a91bf.png

  1. จากนั้นเลือก "ใช้ช่วง IP ที่มีการจัดสรรโดยอัตโนมัติ" แล้วดำเนินการต่อ หลังจากตรวจสอบข้อมูลแล้ว ให้เลือกสร้างการเชื่อมต่อ 768ff5210e79676f.png
  2. เมื่อตั้งค่าเครือข่ายแล้ว คุณก็สร้างคลัสเตอร์ต่อได้ คลิกสร้างคลัสเตอร์เพื่อตั้งค่าคลัสเตอร์ให้เสร็จสมบูรณ์ตามที่แสดงด้านล่าง

e06623e55195e16e.png

อย่าลืมเปลี่ยนรหัสอินสแตนซ์เป็น "

vector-instance"

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

5. การนำเข้าข้อมูล

ตอนนี้ถึงเวลาเพิ่มตารางที่มีข้อมูลเกี่ยวกับร้านค้า ไปที่ AlloyDB เลือกคลัสเตอร์หลัก แล้วเลือก AlloyDB Studio

847e35f1bf8a8bd8.png

คุณอาจต้องรอให้อินสแตนซ์สร้างเสร็จ เมื่อสร้างแล้ว ให้ลงชื่อเข้าใช้ AlloyDB โดยใช้ข้อมูลเข้าสู่ระบบที่คุณสร้างเมื่อสร้างคลัสเตอร์ ใช้ข้อมูลต่อไปนี้เพื่อตรวจสอบสิทธิ์ใน PostgreSQL

  • ชื่อผู้ใช้ : "postgres"
  • ฐานข้อมูล : "postgres"
  • รหัสผ่าน : "alloydb"

เมื่อตรวจสอบสิทธิ์เข้าสู่ AlloyDB Studio เรียบร้อยแล้ว ให้ป้อนคำสั่ง SQL ในเครื่องมือแก้ไข คุณสามารถเพิ่มหน้าต่างเครื่องมือแก้ไขได้หลายหน้าต่างโดยใช้เครื่องหมายบวกทางด้านขวาของหน้าต่างสุดท้าย

91a86d9469d499c4.png

คุณจะป้อนคำสั่งสำหรับ AlloyDB ในหน้าต่างเครื่องมือแก้ไขโดยใช้ตัวเลือกเรียกใช้ รูปแบบ และล้างตามความจำเป็น

เปิดใช้ส่วนขยาย

เราจะใช้ส่วนขยาย pgvector และ google_ml_integration ในการสร้างแอปนี้ ส่วนขยาย pgvector ช่วยให้คุณจัดเก็บและค้นหาการฝังเวกเตอร์ได้ ส่วนขยาย google_ml_integration มีฟังก์ชันที่คุณใช้เข้าถึงปลายทางการคาดการณ์ Vertex AI เพื่อรับการคาดการณ์ใน SQL เปิดใช้ส่วนขยายเหล่านี้โดยเรียกใช้ DDL ต่อไปนี้

CREATE EXTENSION IF NOT EXISTS google_ml_integration CASCADE;
CREATE EXTENSION IF NOT EXISTS vector;

หากต้องการตรวจสอบส่วนขยายที่เปิดใช้ในฐานข้อมูล ให้เรียกใช้คําสั่ง SQL นี้

select extname, extversion from pg_extension;

สร้างตาราง

สร้างตารางโดยใช้คำสั่ง DDL ด้านล่าง

CREATE TABLE toys ( id VARCHAR(25), name VARCHAR(25), description VARCHAR(20000), quantity INT, price FLOAT, image_url VARCHAR(200), text_embeddings vector(768)) ;

เมื่อเรียกใช้คําสั่งข้างต้นสําเร็จ คุณควรจะดูตารางในฐานข้อมูลได้

นําเข้าข้อมูล

สําหรับห้องทดลองนี้ เรามีข้อมูลทดสอบประมาณ 72 ระเบียนในไฟล์ SQL นี้ โดยไฟล์ดังกล่าวจะมีช่อง id, name, description, quantity, price, image_url คุณจะกรอกข้อมูลในช่องอื่นๆ ในภายหลังในแท็บห้องทดลอง

คัดลอกบรรทัด/คำสั่งแทรกจากตรงนั้น แล้ววางบรรทัดเหล่านั้นในแท็บเครื่องมือแก้ไขว่าง แล้วเลือก "เรียกใช้"

หากต้องการดูเนื้อหาตาราง ให้ขยายส่วน "เครื่องมือสํารวจ" จนกว่าจะเห็นตารางชื่อ "เครื่องแต่งกาย" เลือกเครื่องหมายตรีโคลอน (⋮) เพื่อดูตัวเลือกในการค้นหาตาราง คำสั่ง SELECT จะเปิดในแท็บเครื่องมือแก้ไขใหม่

cfaa52b717f9aaed.png

ให้สิทธิ์

เรียกใช้คำสั่งด้านล่างเพื่อมอบสิทธิ์ดำเนินการในฟังก์ชัน embedding ให้แก่ผู้ใช้ postgres

GRANT EXECUTE ON FUNCTION embedding TO postgres;

มอบบทบาทผู้ใช้ Vertex AI ให้กับบัญชีบริการ AlloyDB

ไปที่เทอร์มินัล Cloud Shell แล้วป้อนคำสั่งต่อไปนี้

PROJECT_ID=$(gcloud config get-value project)

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:service-$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")@gcp-sa-alloydb.iam.gserviceaccount.com" \
--role="roles/aiplatform.user"

6. สร้างการฝังสําหรับบริบท

คอมพิวเตอร์ประมวลผลตัวเลขได้ง่ายกว่าประมวลผลข้อความ ระบบการฝังจะแปลงข้อความให้เป็นชุดตัวเลขทศนิยมที่ควรแสดงข้อความนั้น ไม่ว่าจะใช้คำพูดอย่างไร ใช้ภาษาใด ฯลฯ

ลองอธิบายสถานที่ริมทะเล ที่พักอาจเรียกว่า "ริมน้ำ" "ริมชายหาด" "เดินจากห้องพักไปยังทะเล" "sur la mer" "на берегу океана" เป็นต้น คําเหล่านี้ดูแตกต่างกันทั้งหมด แต่ความหมายเชิงอรรถศาสตร์หรือในคําศัพท์แมชชีนเลิร์นนิง องค์ประกอบของคําเหล่านี้ควรมีความใกล้เคียงกันมาก

เมื่อข้อมูลและบริบทพร้อมแล้ว เราจะเรียกใช้ SQL เพื่อเพิ่มการฝังคำอธิบายผลิตภัณฑ์ลงในตารางในช่อง embedding รูปแบบการฝังมีหลากหลายรูปแบบที่คุณใช้ได้ เราใช้ text-embedding-005 จาก Vertex AI โปรดใช้รูปแบบการฝังเดียวกันตลอดทั้งโปรเจ็กต์

หมายเหตุ: หากคุณใช้โปรเจ็กต์ Google Cloud ที่มีอยู่ซึ่งสร้างขึ้นเมื่อสักพักที่ผ่านมา คุณอาจต้องใช้รูปแบบการฝังข้อความเวอร์ชันเก่า เช่น textembedding-gecko ต่อไป

กลับไปที่แท็บ AlloyDB Studio แล้วพิมพ์ DML ต่อไปนี้

UPDATE toys set text_embeddings = embedding( 'text-embedding-005', description);

ดูตาราง toys อีกครั้งเพื่อดูการฝังบางส่วน อย่าลืมเรียกใช้คำสั่ง SELECT อีกครั้งเพื่อดูการเปลี่ยนแปลง

SELECT id, name, description, price, quantity, image_url, text_embeddings FROM toys;

ซึ่งจะแสดงผลเวกเตอร์การฝังที่ดูเหมือนอาร์เรย์ของตัวเลขทศนิยมสำหรับคำอธิบายของของเล่นดังที่แสดงด้านล่าง

7d32f7cd7204e1f3.png

หมายเหตุ: โปรเจ็กต์ Google Cloud ที่สร้างขึ้นใหม่ในรุ่นไม่มีค่าใช้จ่ายอาจพบปัญหาเกี่ยวกับโควต้าในเรื่องจำนวนคำขอฝังที่อนุญาตต่อวินาทีสำหรับรูปแบบการฝัง เราขอแนะนำให้คุณใช้การค้นหาตัวกรองสำหรับรหัส แล้วเลือกระเบียน 1-5 รายการและอื่นๆ ขณะสร้างการฝัง

7. ทำการค้นหาเวกเตอร์

เมื่อตาราง ข้อมูล และการฝังพร้อมแล้ว ให้ทำการค้นหาเวกเตอร์แบบเรียลไทม์สำหรับข้อความค้นหาของผู้ใช้

สมมติว่าผู้ใช้ถามคำถามต่อไปนี้

"I want a white plush teddy bear toy with a floral pattern"

คุณค้นหารายการที่ตรงกันได้โดยเรียกใช้ข้อความค้นหาด้านล่าง

select * from toys
ORDER BY text_embeddings <=> CAST(embedding('text-embedding-005', 'I want a white plush teddy bear toy with a floral pattern') as vector(768))
LIMIT 5;

มาดูรายละเอียดของข้อความค้นหานี้กัน

ในข้อความค้นหานี้

  1. ข้อความค้นหาของผู้ใช้คือ "I want a white plush teddy bear toy with a floral pattern."
  2. เรากําลังแปลงเป็นข้อมูลเชิงลึกในเมธอด embedding() โดยใช้โมเดล text-embedding-005 ขั้นตอนนี้น่าจะดูคุ้นเคยหลังจากขั้นตอนสุดท้ายที่เราใช้ฟังก์ชันการฝังกับรายการทั้งหมดในตาราง
  3. "<=>" แสดงถึงการใช้วิธีการวัดระยะทางความคล้ายคลึงกันของ COSINES คุณดูการวัดความคล้ายคลึงทั้งหมดที่มีได้ในเอกสารประกอบของ pgvector
  4. เรากําลังแปลงผลลัพธ์ของวิธีการฝังเป็นประเภทเวกเตอร์เพื่อให้เข้ากันได้กับเวกเตอร์ที่จัดเก็บไว้ในฐานข้อมูล
  5. LIMIT 5 แสดงว่าเราต้องการนำข้อความที่ใกล้เคียงที่สุด 5 รายการสำหรับข้อความค้นหา

ผลลัพธ์จะมีลักษณะดังนี้

fa7f0fc3a4c68804.png

ดังที่คุณเห็นในผลการค้นหา รายการที่ตรงกันนั้นใกล้เคียงกับข้อความค้นหามาก ลองเปลี่ยนข้อความเพื่อดูว่าผลลัพธ์จะเปลี่ยนแปลงอย่างไร

หมายเหตุสำคัญ:

สมมติว่าเราต้องการเพิ่มประสิทธิภาพ (เวลาในการค้นหา) ประสิทธิภาพ และความสามารถในการแสดงผลของผลการค้นหาด้วยเวกเตอร์นี้โดยใช้ดัชนี ScaNN โปรดอ่านขั้นตอนในบล็อกนี้เพื่อเปรียบเทียบความแตกต่างของผลลัพธ์ที่มีและไม่มีดัชนี

ขั้นตอนที่ไม่บังคับ: ปรับปรุงประสิทธิภาพและการเรียกคืนด้วยดัชนี ScaNN

ขั้นตอนการสร้างดัชนีมีดังนี้

  1. เนื่องจากเรามีคลัสเตอร์ อินสแตนซ์ บริบท และการฝังที่สร้างไว้แล้ว เราจึงต้องติดตั้งส่วนขยาย ScaNN โดยใช้คำสั่งต่อไปนี้
CREATE EXTENSION IF NOT EXISTS alloydb_scann;
  1. ต่อไปเราจะสร้างดัชนี (ScaNN)
CREATE INDEX toysearch_index ON toys
USING scann (text_embeddings cosine)
WITH (num_leaves=9);

ใน DDL ด้านบน apparel_index คือชื่อของดัชนี

"toys" คือตารางของฉัน

"scann" คือวิธีการจัดทำดัชนี

"embedding" คือคอลัมน์ในตารางที่ฉันต้องการจัดทำดัชนี

"cosine" คือวิธีการวัดระยะทางที่ฉันต้องการใช้กับดัชนี

"8" คือจํานวนพาร์ติชันที่จะใช้กับดัชนีนี้ ตั้งค่าเป็นค่าใดก็ได้ระหว่าง 1 ถึง 1048576 ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีกำหนดค่านี้ได้ที่ปรับแต่งดัชนี ScaNN

เราใช้รากคําคูณของจํานวนจุดข้อมูลตามที่แนะนําใน ScaNN repo (เมื่อแบ่งพาร์ติชัน num_leaves ควรเป็นรากคําคูณของจํานวนจุดข้อมูลโดยประมาณ)

  1. ตรวจสอบว่าระบบสร้างดัชนีโดยใช้คําค้นหาหรือไม่
SELECT * FROM pg_stat_ann_indexes;
  1. ทำการค้นหาเวกเตอร์โดยใช้ข้อความค้นหาเดียวกับที่เราใช้โดยไม่มีดัชนี
select * from toys
ORDER BY text_embeddings <=> CAST(embedding('text-embedding-005', 'I want a white plush teddy bear toy with a floral pattern') as vector(768))
LIMIT 5;

คําค้นหาข้างต้นคือคําค้นหาเดียวกับที่เราใช้ในขั้นตอนที่ 8 ของห้องทดลอง แต่ตอนนี้เราจัดทําดัชนีช่องแล้ว

  1. ทดสอบด้วยข้อความค้นหาง่ายๆ ที่มีและไม่มีดัชนี (โดยการยกเลิกดัชนี)

Use Case นี้มีระเบียนเพียง 72 รายการ ดัชนีจึงไม่มีผลจริง ผลการทดสอบที่ดำเนินการในกรณีการใช้งานอื่นมีดังนี้

การค้นหาด้วยเวกเตอร์แบบเดียวกันในข้อมูลการฝังที่จัดทำดัชนีจะให้ผลลัพธ์การค้นหาที่มีคุณภาพและมีประสิทธิภาพ ประสิทธิภาพจะดีขึ้นอย่างมาก (ในแง่ของเวลาในการดำเนินการ: 10.37 มิลลิวินาทีไม่มี ScaNN และ 0.87 มิลลิวินาทีมี ScaNN) เมื่อใช้ดัชนี ดูข้อมูลเพิ่มเติมเกี่ยวกับหัวข้อนี้ได้ในบล็อกนี้

8. การตรวจสอบการจับคู่กับ LLM

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

ตรวจสอบว่าได้ตั้งค่าอินสแตนซ์สำหรับ Gemini แล้ว

ก่อนอื่น ให้ตรวจสอบว่าได้เปิดใช้การผสานรวม Google ML สําหรับคลัสเตอร์และอินสแตนซ์แล้วหรือยัง ใน AlloyDB Studio ให้ป้อนคำสั่งต่อไปนี้

show google_ml_integration.enable_model_support;

หากค่าแสดงเป็น "on" คุณสามารถข้าม 2 ขั้นตอนถัดไปและไปที่การตั้งค่าการผสานรวม AlloyDB กับโมเดล Vertex AI ได้โดยตรง

  1. ไปที่อินสแตนซ์หลักของคลัสเตอร์ AlloyDB แล้วคลิก "แก้ไขอินสแตนซ์หลัก"

cb76b934ba3735bd.png

  1. ไปที่ส่วน Flag ในตัวเลือกการกําหนดค่าขั้นสูง และตรวจสอบว่าได้ตั้งค่า google_ml_integration.enable_model_support flag เป็น "on" ดังที่แสดงด้านล่าง

6a59351fcd2a9d35.png

หากไม่ได้ตั้งค่าเป็น "เปิด" ให้ตั้งค่าเป็น "เปิด" แล้วคลิกปุ่มอัปเดตอินสแตนซ์ ขั้นตอนนี้จะใช้เวลาสักครู่

การผสานรวม AlloyDB กับโมเดล Vertex AI

ตอนนี้คุณสามารถเชื่อมต่อกับ AlloyDB Studio และเรียกใช้คำสั่ง DML ต่อไปนี้เพื่อตั้งค่าการเข้าถึงโมเดล Gemini จาก AlloyDB โดยใช้รหัสโปรเจ็กต์ที่ระบุ คุณอาจได้รับคำเตือนเกี่ยวกับข้อผิดพลาดทางไวยากรณ์ก่อนเรียกใช้คําสั่ง แต่คําสั่งควรทํางานได้

ก่อนอื่น เราจะสร้างการเชื่อมต่อของรุ่น Gemini 1.5 ดังที่แสดงด้านล่าง อย่าลืมแทนที่ $PROJECT_ID ในคําสั่งด้านล่างด้วยรหัสโปรเจ็กต์ Google Cloud

CALL
 google_ml.create_model( model_id => 'gemini-1.5',
   model_request_url => 'https://us-central1-aiplatform.googleapis.com/v1/projects/$PROJECT_ID/locations/us-central1/publishers/google/models/gemini-1.5-pro:streamGenerateContent',
   model_provider => 'google',
   model_auth_type => 'alloydb_service_agent_iam');

คุณสามารถตรวจสอบโมเดลที่กำหนดค่าไว้สำหรับการเข้าถึงผ่านคำสั่งต่อไปนี้ใน AlloyDB Studio

select model_id,model_type from google_ml.model_info_view;        

สุดท้าย เราต้องให้สิทธิ์ผู้ใช้ฐานข้อมูลเพื่อเรียกใช้ฟังก์ชัน ml_predict_row เพื่อเรียกใช้การคาดการณ์ผ่านโมเดล Google Vertex AI เรียกใช้คำสั่งต่อไปนี้

GRANT EXECUTE ON FUNCTION ml_predict_row to postgres;

หมายเหตุ: หากคุณใช้โปรเจ็กต์ Google Cloud ที่มีอยู่และคluster/อินสแตนซ์ AlloyDB ที่มีอยู่ซึ่งสร้างขึ้นเมื่อสักครู่ คุณอาจต้องยกเลิกการอ้างอิงเก่าไปยังโมเดล gemini-1.5 และสร้างอีกครั้งด้วยคำสั่ง CALL ด้านบน แล้วเรียกใช้ grant execute ในฟังก์ชัน ml_predict_row อีกครั้งในกรณีที่พบปัญหาในการเรียกใช้ gemini-1.5 ในอนาคต

การประเมินคำตอบ

แม้ว่าเราจะใช้คําค้นหาขนาดใหญ่รายการเดียวในส่วนถัดไปเพื่อให้คําตอบจากคําค้นหาสมเหตุสมผล แต่คําค้นหานั้นอาจทําความเข้าใจได้ยาก เราจะดูชิ้นส่วนต่างๆ และดูว่าชิ้นส่วนเหล่านั้นจะประกอบเข้าด้วยกันได้อย่างไรในอีก 2-3 นาที

  1. ก่อนอื่น เราจะส่งคําขอไปยังฐานข้อมูลเพื่อรับรายการที่ตรงกับคําค้นหาของผู้ใช้มากที่สุด 10 รายการ
  2. เราจะใช้การค้นหาภายนอกเพื่ออธิบายวิธีประเมินคำตอบเพื่อพิจารณาความถูกต้องของคำตอบ โดยใช้ฟิลด์ recommended_text ซึ่งเป็นข้อความค้นหาและ content (ซึ่งเป็นฟิลด์คำอธิบายของของเล่น) ของตารางด้านในเป็นส่วนหนึ่งของการค้นหา
  3. จากนั้นเราจะตรวจสอบ "คุณภาพ" ของคำตอบที่แสดง
  4. predict_row จะแสดงผลลัพธ์ในรูปแบบ JSON โค้ด "-> 'candidates' -> 0 -> 'content' -> 'parts' -> 0 -> 'text'" ใช้เพื่อดึงข้อความจริงจาก JSON นั้น หากต้องการดู JSON จริงที่แสดงผล ให้นำโค้ดนี้ออก
  5. สุดท้าย เราจะดึงข้อมูลคำตอบ LLM โดยใช้ REGEXP_REPLACE(gemini_validation, '[^a-zA-Z,: ]', '', 'g')
SELECT id,
       name,
       content,
       quantity,
       price,
       image_url,
       recommended_text,
       REGEXP_REPLACE(gemini_validation, '[^a-zA-Z,: ]', '', 'g') AS gemini_validation
  FROM (SELECT id,
               name,
               content,
               quantity,
               price,
               image_url,
               recommended_text,
               CAST(ARRAY_AGG(LLM_RESPONSE) AS TEXT) AS gemini_validation
          FROM (SELECT id,
                       name,
                       content,
                       quantity,
                       price,
                       image_url,
                       recommended_text,
                       json_array_elements(google_ml.predict_row(model_id => 'gemini-1.5',
                                                                   request_body => CONCAT('{ "contents": [ { "role": "user", "parts": [ { "text": "User wants to buy a toy and this is the description of the toy they wish to buy: ',                                                                                              recommended_text,                                                                                              '. Check if the following product items from the inventory are close enough to really, contextually match the user description. Here are the items: ',                                                                                         content,                                                                                         '. Return a ONE-LINE response with 3 values: 1) MATCH: if the 2 contexts are reasonably matching in terms of any of the color or color family specified in the list, approximate style match with any of the styles mentioned in the user search text: This should be a simple YES or NO. Choose NO only if it is completely irrelevant to users search criteria. 2) PERCENTAGE: percentage of match, make sure that this percentage is accurate 3) DIFFERENCE: A clear one-line easy description of the difference between the 2 products. Remember if the user search text says that some attribute should not be there, and the record has it, it should be a NO match. " } ] } ] }')::JSON)) -> 'candidates' -> 0 -> 'content' -> 'parts' -> 0 -> 'text' :: TEXT AS LLM_RESPONSE
                  FROM (SELECT id,
                               name,
                               description AS content,
                               quantity,
                               price,
                               image_url,
                               'Pink panther standing' AS recommended_text
                          FROM toys
                         ORDER BY text_embeddings <=> embedding('text-embedding-005',
                                                                'Pink panther standing')::VECTOR
                         LIMIT 10) AS xyz) AS X
         GROUP BY id,
                  name,
                  content,
                  quantity,
                  price,
                  image_url,
                  recommended_text) AS final_matches
 WHERE REGEXP_REPLACE(gemini_validation, '[^a-zA-Z,: ]', '', 'g') LIKE '%MATCH%:%YES%';

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

โปรดทราบว่าโมเดล Gemini เปิดการสตรีมไว้โดยค่าเริ่มต้น คำตอบจริงจึงกระจายอยู่หลายบรรทัด

c2b006aeb3f3a2fc.png

9. ย้าย Toy Search ไปยังระบบคลาวด์แบบเซิร์ฟเวอร์เสมือน

พร้อมที่จะย้ายแอปนี้ไปยังเว็บหรือยัง ทําตามขั้นตอนด้านล่างเพื่อสร้าง Knowledge Engine แบบ Serverless ด้วย Cloud Run Functions

  1. ไปที่ฟังก์ชัน Cloud Run ในคอนโซล Google Cloud เพื่อสร้างฟังก์ชัน Cloud Run ใหม่ หรือใช้ลิงก์ https://console.cloud.google.com/functions/add
  2. เลือกสภาพแวดล้อมเป็น "ฟังก์ชัน Cloud Run" ระบุชื่อฟังก์ชัน "get-toys-alloydb" และเลือกภูมิภาคเป็น "us-central1" ตั้งค่าการตรวจสอบสิทธิ์เป็น "อนุญาตการเรียกใช้ที่ไม่ผ่านการตรวจสอบสิทธิ์" แล้วคลิกถัดไป เลือก Java 17 เป็นรันไทม์และเครื่องมือแก้ไขในบรรทัดสำหรับซอร์สโค้ด
  3. โดยค่าเริ่มต้น ระบบจะตั้งค่าจุดแรกเข้าไปยังโค้ดเป็น "gcfv2.HelloHttpFunction" ให้แทนที่โค้ดตัวยึดตําแหน่งใน HelloHttpFunction.java และ pom.xml ของฟังก์ชัน Cloud Run ด้วยโค้ดจาก HelloHttpFunction.java และ pom.xml ตามลําดับ
  4. อย่าลืมเปลี่ยนตัวยึดตําแหน่ง <<YOUR_PROJECT>> และข้อมูลเข้าสู่ระบบการเชื่อมต่อ AlloyDB ด้วยค่าของคุณในไฟล์ Java ข้อมูลเข้าสู่ระบบ AlloyDB คือข้อมูลที่เราใช้ตอนเริ่มต้นโค้ดแล็บนี้ หากคุณใช้ค่าอื่น โปรดแก้ไขค่าดังกล่าวในไฟล์ Java
  5. คลิกทำให้ใช้งานได้

เมื่อทำให้ใช้งานได้แล้ว เราจะสร้างเครื่องมือเชื่อมต่อ VPC เพื่อให้ Cloud Function เข้าถึงอินสแตนซ์ฐานข้อมูล AlloyDB ได้

ขั้นตอนสำคัญ:

เมื่อพร้อมทำให้ใช้งานได้แล้ว คุณควรจะเห็นฟังก์ชันในคอนโซล Cloud Run Functions ของ Google ค้นหาฟังก์ชันที่สร้างขึ้นใหม่ (get-toys-alloydb) คลิกฟังก์ชันนั้น แล้วคลิกแก้ไข แล้วทำการเปลี่ยนแปลงต่อไปนี้

  1. ไปที่การตั้งค่ารันไทม์ บิลด์ การเชื่อมต่อ และความปลอดภัย
  2. เพิ่มการหมดเวลาเป็น 180 วินาที
  3. ไปที่แท็บการเชื่อมต่อ

4e83ec8a339cda08.png

  1. ในส่วนการตั้งค่า Ingress ให้ตรวจสอบว่าได้เลือก "Allow all traffic" แล้ว
  2. ในส่วนการตั้งค่าขาออก ให้คลิกเมนูแบบเลื่อนลงของเครือข่าย แล้วเลือกตัวเลือก "เพิ่มตัวเชื่อมต่อ VPC ใหม่" แล้วทําตามวิธีการที่คุณเห็นในกล่องโต้ตอบที่ปรากฏขึ้น

8126ec78c343f199.png

  1. ตั้งชื่อเครื่องมือเชื่อมต่อ VPC และตรวจสอบว่าภูมิภาคตรงกับอินสแตนซ์ของคุณ ปล่อยค่าเครือข่ายเป็นค่าเริ่มต้นและตั้งค่าซับเน็ตเป็นช่วง IP ที่กําหนดเองซึ่งมีช่วง IP ของ 10.8.0.0 หรือค่าที่คล้ายกันซึ่งพร้อมใช้งาน
  2. ขยาย "แสดงการตั้งค่าการปรับขนาด" และตรวจสอบว่าคุณได้ตั้งค่าการกําหนดค่าเป็นค่าต่อไปนี้อย่างตรงทั้งหมด

7baf980463a86a5c.png

  1. คลิก "สร้าง" แล้วเครื่องมือเชื่อมต่อนี้จะแสดงอยู่ในการตั้งค่าการส่งออก
  2. เลือกเครื่องมือเชื่อมต่อที่สร้างขึ้นใหม่
  3. เลือกให้กำหนดเส้นทางการรับส่งข้อมูลทั้งหมดผ่านเครื่องมือเชื่อมต่อ VPC นี้
  4. คลิกถัดไป แล้วคลิกทำให้ใช้งานได้

10. ทดสอบฟังก์ชัน Cloud Run

เมื่อมีการทําให้ Cloud Function ที่อัปเดตแล้วใช้งานได้ คุณควรเห็นปลายทางในรูปแบบต่อไปนี้

https://us-central1-YOUR_PROJECT_ID.cloudfunctions.net/get-toys-alloydb

หรือจะทดสอบฟังก์ชัน Cloud Run ก็ได้ ดังนี้

PROJECT_ID=$(gcloud config get-value project)

curl -X POST https://us-central1-$PROJECT_ID.cloudfunctions.net/get-toys-alloydb \
  -H 'Content-Type: application/json' \
  -d '{"search":"I want a standing pink panther toy"}' \
  | jq .

และผลลัพธ์ที่ได้คือ

23861e9091565a64.png

เท่านี้ก็เรียบร้อย เพียงเท่านี้คุณก็ทําการค้นหาเวกเตอร์ความคล้ายคลึงโดยใช้รูปแบบการฝังในข้อมูล AlloyDB ได้แล้ว

11. การสร้างไคลเอ็นต์เว็บแอปพลิเคชัน

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

  1. เนื่องจากเราใช้ Gemini 2.0 Flash เพื่ออธิบายรูปภาพที่ผู้ใช้อาจอัปโหลดเพื่อค้นหาของเล่นที่ตรงกัน เราจึงจำเป็นต้องขอคีย์ API สำหรับแอปพลิเคชันนี้ โดยไปที่ https://aistudio.google.com/apikey และรับคีย์ API สำหรับโปรเจ็กต์ Google Cloud ที่ใช้งานอยู่ซึ่งคุณใช้ติดตั้งใช้งานแอปพลิเคชันนี้ และบันทึกคีย์ไว้ที่ใดก็ได้

ae2db169e6a94e4a.png

  1. ไปที่เทอร์มินัล Cloud Shell
  2. โคลนที่เก็บด้วยคำสั่งต่อไปนี้
git clone https://github.com/AbiramiSukumaran/toysearch

cd toysearch
  1. เมื่อโคลนที่เก็บแล้ว คุณควรเข้าถึงโปรเจ็กต์ได้จาก Cloud Shell Editor
  2. คุณต้องลบโฟลเดอร์ "get-toys-alloydb" และ "toolbox-toys" ออกจากโปรเจ็กต์ที่โคลน เนื่องจากโฟลเดอร์ 2 นี้เป็นโค้ดฟังก์ชัน Cloud Run ซึ่งอ้างอิงได้จากที่เก็บเมื่อต้องการ
  3. ตรวจสอบว่าได้ตั้งค่าตัวแปรสภาพแวดล้อมที่จําเป็นทั้งหมดแล้วก่อนสร้างและติดตั้งใช้งานแอป ไปที่ Cloud Shell Terminal แล้วทําดังนี้
PROJECT_ID=$(gcloud config get-value project)

export PROJECT_ID $PROJECT_ID

export GOOGLE_API_KEY <YOUR API KEY that you saved>
  1. สร้างและเรียกใช้แอปในเครื่อง

ตรวจสอบว่าคุณอยู่ในไดเรกทอรีโปรเจ็กต์ แล้วเรียกใช้คำสั่งต่อไปนี้

mvn package

mvn spring-boot:run 
  1. ติดตั้งใช้งานใน Cloud Run
gcloud run deploy --source .

12. ทำความเข้าใจรายละเอียดของ Generative AI

คุณไม่ต้องดำเนินการใดๆ โปรดทราบว่า

เมื่อคุณมีแอปพลิเคชันที่จะติดตั้งใช้งานแล้ว โปรดสละเวลาสักครู่เพื่อทำความเข้าใจวิธีที่เราทำการค้นหา (ข้อความและรูปภาพ) และการสร้าง

  1. การค้นหาเวกเตอร์ตามข้อความของผู้ใช้

ปัญหานี้ได้รับการแก้ไขแล้วในฟังก์ชัน Cloud Run ที่เราติดตั้งใช้งานในส่วน "ใช้เว็บแอปพลิเคชัน Vector Search"

  1. การค้นหาเวกเตอร์ที่อิงตามการอัปโหลดรูปภาพ

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

เราใช้ประโยชน์จากโมเดล Flash ของ Gemini 2.0 ของ Google ซึ่งเรียกใช้โดยใช้ LangChain4j เพื่อวิเคราะห์รูปภาพและดึงบริบทที่เกี่ยวข้อง เช่น สี วัสดุ ประเภท และกลุ่มอายุเป้าหมายของของเล่น

เพียง 5 ขั้นตอน เรานำข้อมูลมัลติโมดัลของผู้ใช้มาจับคู่กับผลการเรียกใช้โมเดลภาษาขนาดใหญ่โดยใช้เฟรมเวิร์กแบบโอเพนซอร์ส เรียนรู้วิธีการดังนี้

package cloudcode.helloworld.web;

import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.googleai.GoogleAiGeminiChatModel;
import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.data.message.AiMessage;
import dev.langchain4j.model.output.Response;
import dev.langchain4j.data.message.ImageContent;
import dev.langchain4j.data.message.TextContent;
import java.util.Base64;
import java.util.Optional;

public class GeminiCall {
  public String imageToBase64String(byte[] imageBytes) {
    String base64Img = Base64.getEncoder().encodeToString(imageBytes);
    return base64Img;
  }

  public String callGemini(String base64ImgWithPrefix) throws Exception {
    String searchText = "";

    // 1. Remove the prefix
    String base64Img = base64ImgWithPrefix.replace("data:image/jpeg;base64,", "");

    // 2. Decode base64 to bytes
    byte[] imageBytes = Base64.getDecoder().decode(base64Img);
    String image = imageToBase64String(imageBytes);

    // 3. Get API key from environment variable
        String apiKey = Optional.ofNullable(System.getenv("GOOGLE_API_KEY"))
                .orElseThrow(() -> new IllegalArgumentException("GOOGLE_API_KEY environment variable not set"));

    // 4. Invoke Gemini 2.0
    ChatLanguageModel gemini = GoogleAiGeminiChatModel.builder()
        .apiKey(apiKey)
        .modelName("gemini-2.0-flash-001")
        .build();

    Response<AiMessage> response = gemini.generate(
        UserMessage.from(
            ImageContent.from(image, "image/jpeg"),
            TextContent.from(
                "The picture has a toy in it. Describe the toy in the image in one line. Do not add any prefix or title to your description. Just describe that toy that you see in the image in one line, do not describe the surroundings and other objects around the toy in the image. If you do not see any toy in the image, send  response stating that no toy is found in the input image.")));
   
    // 5. Get the text from the response and send it back to the controller
    searchText = response.content().text().trim();
    System.out.println("searchText inside Geminicall: " + searchText);
    return searchText;
  }
}
  1. ทําความเข้าใจว่าเราใช้ Imagen 3 เพื่อสร้างของเล่นที่กําหนดเองตามคําขอของผู้ใช้ด้วย Generative AI อย่างไร

จากนั้น Imagen 3 จะสร้างรูปภาพของของเล่นที่ออกแบบเอง ซึ่งช่วยให้ผู้ใช้เห็นภาพผลงานของตนอย่างชัดเจน วิธีการของเรามีเพียง 5 ขั้นตอนดังนี้

// Generate an image using a text prompt using an Imagen model
    public String generateImage(String projectId, String location, String prompt)
        throws ApiException, IOException {
      final String endpoint = String.format("%s-aiplatform.googleapis.com:443", location);
      PredictionServiceSettings predictionServiceSettings =
      PredictionServiceSettings.newBuilder().setEndpoint(endpoint).build();
     
      // 1. Set up the context and prompt
      String context = "Generate a photo-realistic image of a toy described in the following input text from the user. Make sure you adhere to all the little details and requirements mentioned in the prompt. Ensure that the user is only describing a toy. If it is anything unrelated to a toy, politely decline the request stating that the request is inappropriate for the current context. ";
      prompt = context + prompt;

      // 2. Initialize a client that will be used to send requests. This client only needs to be created
      // once, and can be reused for multiple requests.
      try (PredictionServiceClient predictionServiceClient =
          PredictionServiceClient.create(predictionServiceSettings)) {
 
      // 3. Invoke Imagen 3
        final EndpointName endpointName =
            EndpointName.ofProjectLocationPublisherModelName(
                projectId, location, "google", "imagen-3.0-generate-001"); //"imagegeneration@006"; imagen-3.0-generate-001
        Map<String, Object> instancesMap = new HashMap<>();
        instancesMap.put("prompt", prompt);
        Value instances = mapToValue(instancesMap);
        Map<String, Object> paramsMap = new HashMap<>();
        paramsMap.put("sampleCount", 1);
        paramsMap.put("aspectRatio", "1:1");
        paramsMap.put("safetyFilterLevel", "block_few");
        paramsMap.put("personGeneration", "allow_adult");
        paramsMap.put("guidanceScale", 21);
        paramsMap.put("imagenControlScale", 0.95); //Setting imagenControlScale
        Value parameters = mapToValue(paramsMap);
       
      // 4. Get prediction response image
        PredictResponse predictResponse =
            predictionServiceClient.predict(
                endpointName, Collections.singletonList(instances), parameters);

      // 5. Return the Base64 Encoded String to the controller
        for (Value prediction : predictResponse.getPredictionsList()) {
          Map<String, Value> fieldsMap = prediction.getStructValue().getFieldsMap();
          if (fieldsMap.containsKey("bytesBase64Encoded")) {
            bytesBase64EncodedOuput = fieldsMap.get("bytesBase64Encoded").getStringValue();
        }
      }
      return bytesBase64EncodedOuput.toString();
    }
  }

การคาดการณ์ราคา

ในส่วนก่อนหน้า เราได้พูดถึงวิธีที่ Imagen สร้างรูปภาพของของเล่นที่ผู้ใช้ต้องการออกแบบด้วยตนเอง แอปพลิเคชันต้องกำหนดราคาของสินค้าเพื่อให้ผู้ใช้ซื้อได้ และเราได้ใช้ตรรกะที่ใช้งานง่ายเพื่อกำหนดราคาของของเล่นสั่งทำ ตรรกะคือการใช้ราคาเฉลี่ยของของเล่นที่ตรงกันที่สุด 5 อันดับแรก (ในแง่ของคำอธิบาย) ของของเล่นที่ผู้ใช้ออกแบบ

การคาดการณ์ราคาของของเล่นที่สร้างขึ้นเป็นส่วนสําคัญของแอปพลิเคชันนี้ และเราได้ใช้แนวทางแบบตัวแทนในการสร้างการคาดการณ์นี้ ขอแนะนํากล่องเครื่องมือ Gen AI สําหรับฐานข้อมูล

13. กล่องเครื่องมือ Gen AI สําหรับฐานข้อมูล

กล่องเครื่องมือ Gen AI สําหรับฐานข้อมูลคือเซิร์ฟเวอร์แบบโอเพนซอร์สจาก Google ที่ช่วยให้คุณสร้างเครื่องมือ Gen AI สําหรับการโต้ตอบกับฐานข้อมูลได้ง่ายขึ้น ซึ่งจะช่วยให้คุณพัฒนาเครื่องมือได้ง่ายขึ้น รวดเร็วขึ้น และปลอดภัยยิ่งขึ้นด้วยการจัดการกับความซับซ้อนต่างๆ เช่น การรวมการเชื่อมต่อ การตรวจสอบสิทธิ์ และอื่นๆ ซึ่งจะช่วยสร้างเครื่องมือ Gen AI ที่ช่วยให้ตัวแทนเข้าถึงข้อมูลในฐานข้อมูลได้

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

ตอนนี้แอปพลิเคชันของคุณสามารถใช้ปลายทางฟังก์ชัน Cloud Run ที่ติดตั้งใช้งานนี้เพื่อป้อนข้อมูลราคาพร้อมกับผลลัพธ์ Imagen ที่สร้างขึ้นสำหรับรูปภาพของของเล่นสั่งทำ

14. ทดสอบเว็บแอปพลิเคชัน

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

https://www.youtube.com/shorts/ZMqUAWsghYQ

หน้า Landing Page จะมีลักษณะดังนี้

241db19e7176e93e.png

15. ล้างข้อมูล

โปรดทำตามขั้นตอนต่อไปนี้เพื่อเลี่ยงไม่ให้เกิดการเรียกเก็บเงินกับบัญชี Google Cloud สำหรับทรัพยากรที่ใช้ในโพสต์นี้

  1. ในคอนโซล Google Cloud ให้ไปที่หน้าจัดการทรัพยากร
  2. ในรายการโปรเจ็กต์ ให้เลือกโปรเจ็กต์ที่ต้องการลบ แล้วคลิกลบ
  3. ในกล่องโต้ตอบ ให้พิมพ์รหัสโปรเจ็กต์ แล้วคลิกปิดเพื่อลบโปรเจ็กต์

16. ขอแสดงความยินดี

ยินดีด้วย คุณได้ดำเนินการค้นหาและสร้างข้อความตามบริบทของ Toystore โดยใช้ AlloyDB, pgvector, Imagen และ Gemini 2.0 เรียบร้อยแล้ว พร้อมทั้งใช้ประโยชน์จากไลบรารีโอเพนซอร์สเพื่อสร้างการผสานรวมที่มีประสิทธิภาพ การรวมความสามารถของ AlloyDB, Vertex AI และ การค้นหาแบบเวกเตอร์ช่วยให้เราก้าวไปอีกขั้นในการทำให้การค้นหาตามบริบทและการค้นหาแบบเวกเตอร์เข้าถึงได้ มีประสิทธิภาพ และมุ่งเน้นความหมายอย่างแท้จริง