Aplikasi Penelusuran Toko Mainan dengan Database Cloud, Runtime Tanpa Server, dan Integrasi Open Source

1. Ringkasan

Bayangkan Anda memasuki toko mainan secara virtual atau langsung, tempat menemukan hadiah yang sempurna menjadi mudah. Anda dapat mendeskripsikan apa yang Anda cari, mengupload foto mainan, atau bahkan mendesain kreasi Anda sendiri, dan toko akan langsung memahami kebutuhan Anda serta memberikan pengalaman yang disesuaikan. Ini bukan fantasi futuristik; ini adalah kenyataan yang didukung oleh AI, teknologi cloud, dan visi untuk e-commerce yang dipersonalisasi.

Tantangan: Menemukan produk sempurna yang sesuai dengan imajinasi Anda bisa jadi sulit. Istilah penelusuran, kata kunci, dan penelusuran fuzzy yang generik sering kali tidak memadai, menjelajahi halaman yang tak berujung bisa membosankan, dan perbedaan antara apa yang Anda bayangkan dan apa yang tersedia dapat menyebabkan frustrasi.

Solusi: Aplikasi demo ini mengatasi tantangan ini secara langsung, dengan memanfaatkan kecanggihan AI untuk memberikan pengalaman yang benar-benar personal dan lancar dengan penelusuran kontekstual dan pembuatan kustom produk yang cocok dengan konteks penelusuran.

Yang akan Anda build

Sebagai bagian dari lab ini, Anda akan:

  1. Buat instance AlloyDB dan muat Toys Dataset
  2. Mengaktifkan ekstensi model AI generatif dan pgvector di AlloyDB
  3. Membuat embedding dari deskripsi produk dan melakukan penelusuran kemiripan Kosinus real-time untuk teks penelusuran pengguna
  4. Memanggil Gemini 2.0 Flash untuk mendeskripsikan gambar yang diupload oleh pengguna untuk penelusuran mainan kontekstual
  5. Memanggil Imagen 3 untuk membuat mainan kustom berdasarkan minat pengguna
  6. Memanggil alat prediksi harga yang dibuat menggunakan Gen AI Toolbox for Databases untuk mengetahui detail harga mainan yang dibuat khusus
  7. Men-deploy solusi di Cloud Run Functions serverless

Persyaratan

  • Browser, seperti Chrome atau Firefox
  • Project Google Cloud yang mengaktifkan penagihan.

2. Arsitektur

Alur Data: Mari kita lihat lebih dekat cara data bergerak melalui sistem kami:

  1. Penelusuran Kontekstual dengan RAG (Retrieval Augmented Generation) yang Didukung AI

Anggap saja seperti ini: alih-alih hanya mencari "mobil merah", sistem memahami hal di bawah ini:

"kendaraan kecil yang cocok untuk anak laki-laki berusia 3 tahun".

AlloyDB sebagai fondasi: Kami menggunakan AlloyDB, database yang kompatibel dengan PostgreSQL dan terkelola sepenuhnya dari Google Cloud, untuk menyimpan data mainan kami, termasuk deskripsi, URL gambar, dan atribut relevan lainnya.

pgvector untuk Penelusuran Semantik: pgvector, ekstensi PostgreSQL, memungkinkan kita menyimpan embedding vektor dari deskripsi mainan dan kueri penelusuran pengguna. Hal ini memungkinkan penelusuran semantik, yang berarti sistem memahami makna di balik kata-kata, bukan hanya kata kunci yang tepat.

Kesamaan Kosinus untuk Relevansi: Kami menggunakan kesamaan kosinus untuk mengukur kesamaan semantik antara vektor penelusuran pengguna dan vektor deskripsi mainan, sehingga menampilkan hasil yang paling relevan.

Indeks ScaNN untuk Kecepatan dan Akurasi: Untuk memastikan hasil yang cepat dan akurat, terutama saat inventaris mainan kami bertambah, kami mengintegrasikan indeks ScaNN (Scalable Nearest Neighbors). Hal ini secara signifikan meningkatkan efisiensi dan perolehan penelusuran vektor kami.

  1. Penelusuran & Pemahaman Berbasis Gambar dengan Gemini 2.0 Flash

Daripada mengetik konteks sebagai teks, misalnya pengguna ingin mengupload gambar mainan yang sudah dikenal yang ingin mereka gunakan untuk menelusuri. Pengguna dapat mengupload gambar mainan yang mereka sukai dan mendapatkan fitur yang relevan dengan mainan tersebut. Kami memanfaatkan model Gemini 2.0 Flash Google, yang dipanggil menggunakan LangChain4j, untuk menganalisis gambar dan mengekstrak konteks yang relevan, seperti warna, bahan, jenis, dan kelompok usia yang dituju mainan.

  1. Membangun Mainan Impian Anda yang Disesuaikan dengan AI Generatif: Imagen 3

Keajaiban sesungguhnya terjadi saat pengguna memutuskan untuk membuat mainan mereka sendiri. Dengan Imagen 3, kami memungkinkan mereka mendeskripsikan mainan impian mereka menggunakan perintah teks sederhana. Bayangkan Anda dapat mengatakan: "Saya ingin naga boneka dengan sayap ungu dan wajah yang ramah" dan melihat naga tersebut muncul di layar Anda. Kemudian, Imagen 3 membuat gambar mainan yang didesain khusus, sehingga pengguna dapat melihat visualisasi yang jelas dari kreasi mereka.

  1. Prediksi Harga yang Didukung oleh Agen & Gen AI Toolbox for Databases

Kami telah menerapkan fitur prediksi harga yang memperkirakan biaya produksi mainan yang didesain khusus. Fitur ini didukung oleh agen yang mencakup alat penghitungan harga canggih.

Gen AI Toolbox for Databases: Agen ini terintegrasi dengan lancar dengan database kami menggunakan alat open source baru Google, Gen AI Toolbox for Databases. Dengan demikian, agen dapat mengakses data real-time tentang biaya bahan, proses manufaktur, dan faktor relevan lainnya untuk memberikan estimasi harga yang akurat. Baca selengkapnya di sini.

  1. Java Spring Boot, Gemini Code Assist, dan Cloud Run untuk Pengembangan yang Lebih Efisien dan Deployment Serverless

Seluruh aplikasi dibangun menggunakan Java Spring Boot, framework yang andal dan skalabel. Kami memanfaatkan Gemini Code Assist selama proses pengembangan, terutama untuk pengembangan front-end, sehingga mempercepat siklus pengembangan secara signifikan dan meningkatkan kualitas kode. Kami menggunakan Cloud Run untuk men-deploy seluruh aplikasi dan Cloud Run Functions untuk men-deploy database dan fungsi agentik sebagai endpoint independen.

3. Sebelum memulai

Membuat project

  1. Di Konsol Google Cloud, di halaman pemilih project, pilih atau buat project Google Cloud.
  2. Pastikan penagihan diaktifkan untuk project Cloud Anda. Pelajari cara memeriksa apakah penagihan telah diaktifkan pada suatu project .
  3. Anda akan menggunakan Cloud Shell, lingkungan command line yang berjalan di Google Cloud yang telah dilengkapi dengan bq. Klik Activate Cloud Shell di bagian atas konsol Google Cloud.

Gambar tombol Activate Cloud Shell

  1. Setelah terhubung ke Cloud Shell, Anda dapat memeriksa bahwa Anda sudah diautentikasi dan project sudah ditetapkan ke project ID Anda menggunakan perintah berikut:
gcloud auth list
  1. Jalankan perintah berikut di Cloud Shell untuk mengonfirmasi bahwa perintah gcloud mengetahui project Anda.
gcloud config list project
  1. Jika project Anda belum ditetapkan, gunakan perintah berikut untuk menetapkannya:
gcloud config set project <YOUR_PROJECT_ID>
  1. Aktifkan API yang diperlukan dengan menjalankan perintah berikut satu per satu di Terminal Cloud Shell Anda:

Ada juga satu perintah untuk menjalankan perintah di bawah, tetapi jika Anda adalah pengguna akun uji coba, Anda mungkin mengalami masalah kuota saat mencoba mengaktifkan perintah ini secara massal. Itulah sebabnya perintah-perintah tersebut dipisahkan satu per baris.

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

Alternatif untuk perintah gcloud adalah melalui konsol dengan menelusuri setiap produk atau menggunakan link ini.

Jika ada API yang terlewat, Anda dapat mengaktifkannya selama proses penerapan.

Baca dokumentasi untuk mempelajari perintah gcloud dan penggunaannya.

4. Penyiapan database

Di lab ini, kita akan menggunakan AlloyDB sebagai database untuk menyimpan data toko mainan. Cloud SQL menggunakan cluster untuk menyimpan semua resource, seperti database dan log. Setiap cluster memiliki instance utama yang menyediakan titik akses ke data. Tabel akan menyimpan data sebenarnya.

Mari kita buat cluster, instance, dan tabel AlloyDB tempat set data e-commerce akan dimuat.

Membuat cluster dan instance

  1. Buka halaman AlloyDB di Konsol Cloud. Cara mudah untuk menemukan sebagian besar halaman di Konsol Cloud adalah dengan menelusurinya menggunakan kotak penelusuran konsol.
  2. Pilih CREATE CLUSTER dari halaman tersebut:

f76ff480c8c889aa.png

  1. Anda akan melihat layar seperti di bawah. Buat cluster dan instance dengan nilai berikut (Pastikan nilai cocok jika Anda meng-clone kode aplikasi dari repo):
  • cluster id: "vector-cluster"
  • password: "alloydb"
  • Kompatibel dengan PostgreSQL 15
  • Wilayah: "us-central1"
  • Jaringan: "default"

538dba58908162fb.png

  1. Saat Anda memilih jaringan default, Anda akan melihat layar seperti di bawah.

Pilih SIAPKAN KONEKSI.
7939bbb6802a91bf.png

  1. Dari sana, pilih "Gunakan rentang IP yang dialokasikan secara otomatis" dan Lanjutkan. Setelah meninjau informasi, pilih BUAT KONEKSI. 768ff5210e79676f.png
  2. Setelah jaringan disiapkan, Anda dapat melanjutkan pembuatan cluster. Klik CREATE CLUSTER untuk menyelesaikan penyiapan cluster seperti yang ditunjukkan di bawah:

e06623e55195e16e.png

Pastikan untuk mengubah ID instance menjadi

vector-instance

Jika Anda tidak dapat mengubahnya, ingatlah untuk mengubah ID instance di semua referensi mendatang.

Perhatikan bahwa pembuatan Cluster akan memerlukan waktu sekitar 10 menit. Setelah berhasil, Anda akan melihat layar yang menampilkan ringkasan cluster yang baru saja Anda buat.

5. Penyerapan data

Sekarang saatnya menambahkan tabel dengan data tentang toko. Buka AlloyDB, pilih cluster utama, lalu AlloyDB Studio:

847e35f1bf8a8bd8.png

Anda mungkin perlu menunggu hingga instance selesai dibuat. Setelah selesai, login ke AlloyDB menggunakan kredensial yang Anda buat saat membuat cluster. Gunakan data berikut untuk melakukan autentikasi ke PostgreSQL:

  • Nama pengguna : "postgres"
  • Database : "postgres"
  • Sandi : "alloydb"

Setelah Anda berhasil diautentikasi ke AlloyDB Studio, perintah SQL dimasukkan di Editor. Anda dapat menambahkan beberapa jendela Editor menggunakan tanda plus di sebelah kanan jendela terakhir.

91a86d9469d499c4.png

Anda akan memasukkan perintah untuk AlloyDB di jendela editor, menggunakan opsi Jalankan, Format, dan Hapus sesuai kebutuhan.

Mengaktifkan Ekstensi

Untuk membangun aplikasi ini, kita akan menggunakan ekstensi pgvector dan google_ml_integration. Ekstensi pgvector memungkinkan Anda menyimpan dan menelusuri embedding vektor. Ekstensi google_ml_integration menyediakan fungsi yang Anda gunakan untuk mengakses endpoint prediksi Vertex AI guna mendapatkan prediksi di SQL. Aktifkan ekstensi ini dengan menjalankan DDL berikut:

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

Jika Anda ingin memeriksa ekstensi yang telah diaktifkan di database Anda, jalankan perintah SQL ini:

select extname, extversion from pg_extension;

Membuat tabel

Buat tabel menggunakan pernyataan DDL di bawah:

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

Setelah berhasil menjalankan perintah di atas, Anda akan dapat melihat tabel di database.

Menyerap data

Untuk lab ini, kita memiliki data pengujian sekitar 72 rekaman dalam file SQL ini. Berisi kolom id, name, description, quantity, price, image_url. Kolom lainnya akan diisi nanti di lab.

Salin hanya 5 baris/pernyataan penyisipan pertama dari sana, lalu tempel baris tersebut di tab editor kosong dan pilih RUN. Jika Anda TIDAK menggunakan akun penagihan uji coba, Anda mungkin dapat menyalin semua pernyataan penyisipan dan menjalankannya.

Untuk melihat isi tabel, luaskan bagian Explorer hingga Anda dapat melihat tabel bernama apparels. Pilih tiga titik (⋮) untuk melihat opsi Kueri tabel. Pernyataan SELECT akan terbuka di tab Editor baru.

cfaa52b717f9aaed.png

Berikan Izin

Jalankan pernyataan di bawah untuk memberikan hak eksekusi pada fungsi embedding kepada pengguna postgres:

GRANT EXECUTE ON FUNCTION embedding TO postgres;

Memberikan PERAN Vertex AI User ke akun layanan AlloyDB

Buka terminal Cloud Shell dan berikan perintah berikut:

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. Membuat embedding untuk konteks

Komputer jauh lebih mudah memproses angka daripada memproses teks. Sistem penyematan mengonversi teks menjadi serangkaian angka floating point yang harus merepresentasikan teks, terlepas dari bagaimana teks tersebut disusun, bahasa yang digunakan, dll.

Pertimbangkan untuk mendeskripsikan lokasi di tepi laut. Mungkin disebut "di atas air", "di tepi pantai", "berjalan dari kamar Anda ke laut", "sur la mer", "на берегу океана", dll. Semua istilah ini terlihat berbeda, tetapi makna semantiknya atau dalam terminologi machine learning, embeddingnya harus sangat dekat satu sama lain.

Setelah data dan konteks siap, kita akan menjalankan SQL untuk menambahkan embedding deskripsi produk ke tabel di kolom embedding. Ada berbagai model penyematan yang dapat Anda gunakan. Kita menggunakan text-embedding-005 dari Vertex AI. Pastikan untuk menggunakan model sematan yang sama di seluruh project.

Catatan: Jika Anda menggunakan Project Google Cloud yang sudah ada dan dibuat beberapa waktu lalu, Anda mungkin perlu terus menggunakan model penyematan teks versi lama seperti textembedding-gecko.

Kembali ke tab AlloyDB Studio dan ketik DML berikut:

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

Lihat tabel toys lagi untuk melihat beberapa penyematan. Pastikan untuk menjalankan ulang pernyataan SELECT untuk melihat perubahan.

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

Tindakan ini akan menampilkan vektor embedding, yang terlihat seperti array float, untuk deskripsi mainan seperti yang ditunjukkan di bawah ini:

7d32f7cd7204e1f3.png

Catatan: Project Google Cloud yang baru dibuat dalam paket gratis mungkin mengalami masalah kuota terkait jumlah permintaan penyematan yang diizinkan per detik ke model Penyematan. Sebaiknya gunakan kueri filter untuk ID, lalu pilih 1-5 rekaman secara selektif dan seterusnya, saat membuat penyematan.

7. Melakukan penelusuran Vektor

Setelah tabel, data, dan embedding siap, mari lakukan penelusuran vektor real time untuk teks penelusuran pengguna.

Misalkan pengguna bertanya:

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

Anda dapat menemukan kecocokan untuk hal ini dengan menjalankan kueri di bawah:

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 2;

Mari kita lihat kueri ini secara mendetail:

Dalam kueri ini,

  1. Teks penelusuran pengguna adalah: "I want a white plush teddy bear toy with a floral pattern."
  2. Kita akan mengonversinya menjadi embedding dalam metode embedding() menggunakan model: text-embedding-005. Langkah ini akan terlihat familiar setelah langkah terakhir, saat kita menerapkan fungsi penyematan ke semua item dalam tabel.
  3. "<=>" menunjukkan penggunaan metode jarak COSINE SIMILARITY. Anda dapat menemukan semua ukuran kemiripan yang tersedia di dokumentasi pgvector.
  4. Kita mengonversi hasil metode embedding ke jenis vektor agar kompatibel dengan vektor yang disimpan dalam database.
  5. LIMIT 5 menunjukkan bahwa kita ingin mengekstrak 5 tetangga terdekat untuk teks penelusuran.

Hasilnya akan terlihat seperti ini:

fa7f0fc3a4c68804.png

Seperti yang dapat Anda amati di hasil Anda, kecocokannya cukup dekat dengan teks penelusuran. Coba ubah teks untuk melihat perubahan hasilnya.

Catatan Penting:

Sekarang, misalkan kita ingin meningkatkan performa (waktu kueri), efisiensi, dan perolehan hasil Penelusuran Vektor ini menggunakan indeks ScaNN. Baca langkah-langkah dalam blog ini untuk membandingkan perbedaan hasil dengan dan tanpa indeks.

Langkah Opsional: Meningkatkan Efisiensi dan Ingatan dengan Indeks ScaNN

Abaikan langkah ini jika jumlah data Anda kurang dari 100.

Langkah-langkah pembuatan indeks dicantumkan di sini untuk memudahkan:

  1. Karena kita sudah membuat cluster, instance, konteks, dan embedding, kita hanya perlu menginstal ekstensi ScaNN menggunakan pernyataan berikut:
CREATE EXTENSION IF NOT EXISTS alloydb_scann;
  1. Selanjutnya, kita akan membuat indeks (ScaNN):
CREATE INDEX toysearch_index ON toys
USING scann (text_embeddings cosine)
WITH (num_leaves=9);

Dalam DDL di atas, apparel_index adalah nama indeks

"toys" adalah tabel saya

"scann" adalah metode indeks

"embedding" adalah kolom dalam tabel yang ingin saya indeks

"cosine" adalah metode jarak yang ingin saya gunakan dengan indeks

"8" adalah jumlah partisi yang akan diterapkan ke indeks ini. Tetapkan ke nilai apa pun antara 1 hingga 1048576. Untuk mengetahui informasi selengkapnya tentang cara menentukan nilai ini, lihat Menyesuaikan indeks ScaNN.

Saya menggunakan AKAR KUADRAT dari jumlah titik data seperti yang direkomendasikan di repo ScaNN (Saat membuat partisi, num_leaves harus kira-kira akar kuadrat dari jumlah titik data.).

  1. Periksa apakah indeks dibuat menggunakan kueri:
SELECT * FROM pg_stat_ann_indexes;
  1. Lakukan Vector Search menggunakan kueri yang sama dengan yang kita gunakan tanpa indeks:
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;

Kueri di atas sama dengan kueri yang kita gunakan di lab pada langkah 8. Namun, sekarang kita telah mengindeks kolom tersebut.

  1. Uji dengan kueri penelusuran sederhana dengan dan tanpa indeks (dengan menghapus indeks):

Kasus penggunaan ini hanya memiliki 72 data, sehingga indeks tidak benar-benar berlaku. Untuk pengujian yang dilakukan dalam kasus penggunaan lain, hasilnya adalah sebagai berikut:

Kueri Vector Search yang sama pada data embedding yang DIINDEX menghasilkan hasil penelusuran yang berkualitas dan efisien. Efisiensi sangat meningkat (dalam hal waktu eksekusi: 10,37 md tanpa ScaNN dan 0,87 md dengan ScaNN) dengan indeks. Untuk mengetahui informasi selengkapnya tentang topik ini, lihat blog ini.

8. Validasi Kecocokan dengan LLM

Sebelum melanjutkan dan membuat layanan untuk menampilkan kecocokan terbaik ke aplikasi, mari kita gunakan model AI generatif untuk memvalidasi apakah potensi respons ini benar-benar relevan dan aman untuk dibagikan kepada pengguna.

Memastikan instance disiapkan untuk Gemini

Pertama, periksa apakah Integrasi ML Google sudah diaktifkan untuk Cluster dan Instance Anda. Di AlloyDB Studio, berikan perintah berikut:

show google_ml_integration.enable_model_support;

Jika nilai ditampilkan sebagai "aktif", Anda dapat melewati 2 langkah berikutnya dan langsung melanjutkan ke penyiapan integrasi Model AlloyDB dan Vertex AI.

  1. Buka instance utama cluster AlloyDB Anda, lalu klik EDIT PRIMARY INSTANCE

cb76b934ba3735bd.png

  1. Buka bagian Flags di Advanced Configuration Options. dan pastikan google_ml_integration.enable_model_support flag disetel ke "on" seperti yang ditunjukkan di bawah:

6a59351fcd2a9d35.png

Jika tidak disetel ke "on", setel ke "on", lalu klik tombol UPDATE INSTANCE. Langkah ini akan memakan waktu beberapa menit.

Integrasi Model AlloyDB dan Vertex AI

Sekarang Anda dapat terhubung ke AlloyDB Studio dan menjalankan pernyataan DML berikut untuk menyiapkan akses model Gemini dari AlloyDB, menggunakan project ID Anda di tempat yang ditunjukkan. Anda mungkin diperingatkan tentang error sintaksis sebelum menjalankan perintah, tetapi perintah tersebut akan berjalan dengan baik.

Pertama, kita membuat koneksi model Gemini 1.5 seperti yang ditunjukkan di bawah. Jangan lupa untuk mengganti $PROJECT_ID dalam perintah di bawah dengan ID Project Google Cloud Anda.

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');

Anda dapat memeriksa model yang dikonfigurasi untuk akses melalui perintah berikut di AlloyDB Studio:

select model_id,model_type from google_ml.model_info_view;        

Terakhir, kita perlu memberikan izin kepada pengguna database untuk menjalankan fungsi ml_predict_row guna menjalankan prediksi melalui model Google Vertex AI. Jalankan perintah berikut:

GRANT EXECUTE ON FUNCTION ml_predict_row to postgres;

Catatan: Jika Anda menggunakan Project Google Cloud yang sudah ada dan cluster/instance AlloyDB yang sudah ada yang dibuat beberapa waktu lalu, Anda mungkin perlu menghapus referensi lama ke model gemini-1.5 dan membuatnya lagi dengan pernyataan CALL di atas serta menjalankan kembali grant execute pada fungsi ml_predict_row jika Anda mengalami masalah dalam pemanggilan gemini-1.5 mendatang.

Mengevaluasi respons

Meskipun kita akan menggunakan satu kueri besar di bagian berikutnya untuk memastikan respons dari kueri tersebut wajar, kueri tersebut mungkin sulit dipahami. Kita akan melihat komponen-komponennya sekarang dan melihat cara kerjanya dalam beberapa menit.

  1. Pertama, kita akan mengirim permintaan ke database untuk mendapatkan 10 kecocokan terdekat dengan kueri pengguna.
  2. Untuk menentukan seberapa valid respons, kita akan menggunakan kueri luar yang menjelaskan cara mengevaluasi respons. Kueri ini menggunakan kolom recommended_text yang merupakan teks penelusuran dan content (yang merupakan kolom deskripsi mainan) dari tabel dalam sebagai bagian dari kueri.
  3. Dengan begitu, kita akan meninjau "kualitas" respons yang ditampilkan.
  4. predict_row menampilkan hasilnya dalam format JSON. Kode "-> 'candidates' -> 0 -> 'content' -> 'parts' -> 0 -> 'text'" digunakan untuk mengekstrak teks sebenarnya dari JSON tersebut. Untuk melihat JSON sebenarnya yang ditampilkan, Anda dapat menghapus kode ini.
  5. Terakhir, untuk mendapatkan respons LLM, kita mengekstraknya menggunakan 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 1) 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%';

Meskipun masih tampak sulit, semoga Anda bisa lebih memahaminya. Hasilnya menunjukkan apakah ada kecocokan atau tidak, berapa persentase kecocokan, dan beberapa penjelasan tentang rating.

Perhatikan bahwa model Gemini mengaktifkan streaming secara default, sehingga respons sebenarnya tersebar di beberapa baris:

c2b006aeb3f3a2fc.png

9. Membawa Penelusuran Mainan ke Cloud Tanpa Server

Siap membawa aplikasi ini ke web? Ikuti langkah-langkah di bawah untuk membuat Knowledge Engine Serverless dengan Cloud Run Functions:

  1. Buka Cloud Run Functions di Konsol Google Cloud untuk MEMBUAT Cloud Run Function baru atau gunakan link: https://console.cloud.google.com/functions/add.
  2. Pilih Lingkungan sebagai "Cloud Run function". Berikan Nama Fungsi "get-toys-alloydb" dan pilih Region sebagai "us-central1". Tetapkan Autentikasi ke "Izinkan pemanggilan yang tidak diautentikasi", lalu klik BERIKUTNYA. Pilih Java 17 sebagai runtime dan Inline Editor untuk kode sumber.
  3. Secara default, Entry Point akan ditetapkan ke "gcfv2.HelloHttpFunction". Ganti kode placeholder di HelloHttpFunction.java dan pom.xml Cloud Run Function Anda dengan kode dari HelloHttpFunction.java dan pom.xml.
  4. Jangan lupa untuk mengubah placeholder <<YOUR_PROJECT>> dan kredensial koneksi AlloyDB dengan nilai Anda di file Java. Kredensial AlloyDB adalah kredensial yang kita gunakan di awal codelab ini. Jika Anda telah menggunakan nilai yang berbeda, ubah nilai yang sama dalam file Java.
  5. Klik Deploy.

Setelah di-deploy, untuk mengizinkan Cloud Function mengakses instance database AlloyDB, kita akan membuat konektor VPC.

LANGKAH PENTING:

Setelah siap untuk deployment, Anda akan dapat melihat fungsi di konsol Cloud Run Functions Google. Cari fungsi yang baru dibuat (get-toys-alloydb), klik fungsi tersebut, lalu klik EDIT dan ubah hal berikut:

  1. Buka Setelan runtime, build, koneksi, dan keamanan
  2. Tingkatkan waktu tunggu menjadi 180 detik
  3. Buka tab KONEKSI:

4e83ec8a339cda08.png

  1. Di bagian setelan Ingress, pastikan "Izinkan semua traffic" dipilih.
  2. Di bagian setelan Egress, Klik dropdown Network, pilih opsi "Add New VPC Connector", lalu ikuti petunjuk yang Anda lihat di kotak dialog yang muncul:

8126ec78c343f199.png

  1. Berikan nama untuk VPC Connector dan pastikan regionnya sama dengan instance Anda. Biarkan nilai Jaringan sebagai default dan tetapkan Subnet sebagai Rentang IP Kustom dengan rentang IP 10.8.0.0 atau yang serupa yang tersedia.
  2. Perluas SHOW SCALING SETTINGS dan pastikan Anda telah menyetel konfigurasi persis seperti berikut:

7baf980463a86a5c.png

  1. Klik CREATE dan konektor ini akan tercantum di setelan egress sekarang.
  2. Pilih konektor yang baru dibuat
  3. Pilih agar semua traffic dirutekan melalui konektor VPC ini.
  4. Klik NEXT, lalu DEPLOY.

10. Menguji Cloud Run Function

Setelah Cloud Function yang diupdate di-deploy, Anda akan melihat endpoint yang dibuat. Salin dan ganti di perintah berikut:

Atau, Anda dapat menguji Cloud Run Function sebagai berikut:

PROJECT_ID=$(gcloud config get-value project)

curl -X POST <<YOUR_ENDPOINT>> \
  -H 'Content-Type: application/json' \
  -d '{"search":"I want a standing pink panther toy"}' \
  | jq .

Dan hasilnya:

23861e9091565a64.png

Selesai! Semudah itu melakukan Penelusuran Vektor Kemiripan menggunakan model Embedding pada data AlloyDB.

11. Membangun Klien Aplikasi Web

Di bagian ini, kita akan membuat aplikasi web agar pengguna dapat berinteraksi dan menemukan mainan yang cocok berdasarkan teks, gambar, dan bahkan membuat mainan baru berdasarkan kebutuhan mereka. Karena aplikasi sudah dibuat, Anda dapat mengikuti langkah-langkah di bawah untuk menyalinnya ke IDE dan menjalankan aplikasi.

  1. Karena kita menggunakan Gemini 2.0 Flash untuk mendeskripsikan gambar yang mungkin diupload pengguna untuk menemukan mainan yang cocok, kita perlu mendapatkan KUNCI API untuk aplikasi ini. Untuk melakukannya, buka https://aistudio.google.com/apikey dan dapatkan Kunci API untuk Project Google Cloud aktif tempat Anda menerapkan aplikasi ini, lalu simpan kunci tersebut di suatu tempat:

ae2db169e6a94e4a.png

  1. Buka Terminal Cloud Shell
  2. Clone repo dengan perintah berikut:
git clone https://github.com/AbiramiSukumaran/toysearch

cd toysearch
  1. Setelah repo di-clone, Anda dapat mengakses project dari Cloud Shell Editor.
  2. Anda perlu menghapus folder "get-toys-alloydb" dan "toolbox-toys" dari project yang di-clone karena kedua folder ini adalah kode Cloud Run Functions yang dapat dirujuk dari repo saat Anda membutuhkannya.
  3. Buka GenerateToy.java di folder web, lalu temukan baris berikut dan hapus karena mengizinkan konten dewasa mungkin memerlukan izin khusus yang mungkin tidak tersedia untuk beberapa akun penagihan uji coba:

paramsMap.put("personGeneration", "allow_adult");

  1. Pastikan semua variabel lingkungan yang diperlukan telah ditetapkan sebelum Anda membangun dan men-deploy aplikasi. Buka Terminal Cloud Shell dan jalankan perintah berikut:
PROJECT_ID=$(gcloud config get-value project)

export PROJECT_ID=$PROJECT_ID

export GOOGLE_API_KEY=<YOUR API KEY that you saved>
  1. Bangun dan jalankan aplikasi secara lokal:

Pastikan Anda berada di direktori project, lalu jalankan perintah berikut:

mvn package

mvn spring-boot:run 
  1. Men-deploy di Cloud Run
gcloud run deploy --source .

12. Memahami detail AI Generatif

Tidak perlu tindakan apa pun. Sekadar untuk pemahaman Anda:

Setelah aplikasi siap di-deploy, luangkan waktu untuk memahami cara kami melakukan penelusuran (teks dan gambar) dan pembuatan.

  1. Penelusuran Vektor berbasis teks pengguna:

Hal ini sudah ditangani di Cloud Run Functions yang kita deploy di bagian "Gunakan web aplikasi Penelusuran Vektor".

  1. Penelusuran Vektor berbasis upload gambar:

Daripada mengetik konteks sebagai teks, misalnya pengguna ingin mengupload gambar mainan yang sudah dikenal yang ingin mereka gunakan untuk menelusuri. Pengguna dapat mengupload gambar mainan yang mereka sukai dan mendapatkan fitur yang relevan dengan mainan tersebut.

Kami memanfaatkan model Gemini 2.0 Flash Google, yang dipanggil menggunakan LangChain4j, untuk menganalisis gambar dan mengekstrak konteks yang relevan, seperti warna, bahan, jenis, dan kelompok usia yang dituju mainan.

Hanya dalam 5 langkah, kami mengambil input data multimodal pengguna untuk mencocokkan hasil dengan pemanggilan model bahasa besar menggunakan framework open source. Pelajari caranya:

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. Pahami cara kami menggunakan Imagen 3 untuk membuat mainan yang disesuaikan berdasarkan permintaan pengguna dengan AI Generatif.

Kemudian, Imagen 3 membuat gambar mainan yang didesain khusus, sehingga pengguna dapat melihat visualisasi yang jelas dari kreasi mereka. Berikut cara kami melakukannya hanya dalam 5 langkah:

// 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();
    }
  }

Prediksi Harga

Di bagian sebelumnya di atas, kita membahas cara Imagen membuat gambar mainan yang ingin didesain sendiri oleh pengguna. Agar mereka dapat membelinya, aplikasi perlu menetapkan harga untuknya dan kami telah menerapkan logika intuitif untuk menentukan harga mainan buatan khusus yang dibuat sesuai pesanan. Logikanya adalah menggunakan harga rata-rata dari 5 mainan yang paling cocok (dalam hal deskripsi) dengan mainan yang didesain pengguna.

Prediksi harga untuk mainan yang dibuat adalah bagian penting dari aplikasi ini dan kami telah menggunakan pendekatan berbasis agen untuk membuatnya. Memperkenalkan Gen AI Toolbox for Databases.

13. Gen AI Toolbox for Databases

Gen AI Toolbox for Databases adalah server open source dari Google yang mempermudah pembuatan alat AI generatif untuk berinteraksi dengan database. Hal ini memungkinkan Anda mengembangkan alat dengan lebih mudah, cepat, dan aman dengan menangani kompleksitas seperti penggabungan koneksi, autentikasi, dan lainnya. Alat ini membantu Anda membangun alat AI Generatif yang memungkinkan agen Anda mengakses data di database Anda.

Berikut langkah-langkah yang perlu Anda ikuti untuk menyiapkan Alat agar siap digunakan dan membuat aplikasi kami menjadi agentik: Link ke Codelab Toolbox

Aplikasi Anda kini dapat menggunakan endpoint Cloud Run Function yang di-deploy ini untuk mengisi harga bersama dengan hasil Imagen yang dihasilkan untuk gambar mainan buatan khusus sesuai pesanan.

14. Menguji Aplikasi Web Anda

Setelah semua komponen aplikasi Anda dibuat dan di-deploy, aplikasi siap ditayangkan di cloud. Uji aplikasi Anda untuk semua skenario. Berikut link video tentang apa yang mungkin terjadi:

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

Tampilan halaman landing adalah sebagai berikut:

241db19e7176e93e.png

15. Pembersihan

Agar tidak menimbulkan biaya pada akun Google Cloud Anda untuk resource yang digunakan dalam posting ini, ikuti langkah-langkah berikut:

  1. Di konsol Google Cloud, buka halaman Manage resources.
  2. Dalam daftar project, pilih project yang ingin Anda hapus, lalu klik Delete.
  3. Pada dialog, ketik project ID, lalu klik Shut down untuk menghapus project.

16. Selamat

Selamat! Anda telah berhasil melakukan Penelusuran dan Pembuatan Kontekstual Toko Mainan menggunakan AlloyDB, pgvector, Imagen, dan Gemini 2.0 sekaligus memanfaatkan library open source untuk membangun integrasi yang andal. Dengan menggabungkan kemampuan AlloyDB, Vertex AI, dan Vector Search, kami telah membuat lompatan besar dalam menjadikan penelusuran kontekstual dan vektor dapat diakses, efisien, dan benar-benar berbasis makna.