วิธีทำให้แอปแชทที่ทำงานด้วยระบบ Gemini ใช้งานได้บน Cloud Run

1. บทนำ

ภาพรวม

ใน Codelab นี้ คุณจะได้ดูวิธีสร้างแชทบ็อตพื้นฐานที่เขียนด้วย Node โดยใช้ Vertex AI Gemini API และไลบรารีของไคลเอ็นต์ Vertex AI แอปนี้ใช้ที่เก็บเซสชันด่วนที่ได้รับการสนับสนุนโดย Google Cloud Firestore

สิ่งที่คุณจะได้เรียนรู้

  • วิธีใช้ htmx, tailwindcss และ express.js เพื่อสร้างบริการ Cloud Run
  • วิธีใช้ไลบรารีของไคลเอ็นต์ Vertex AI เพื่อตรวจสอบสิทธิ์กับ Google API
  • วิธีสร้างแชทบ็อตเพื่อโต้ตอบกับโมเดล Gemini
  • วิธีทำให้บริการ Cloud Run ใช้งานได้โดยไม่ต้องใช้ Dockerfile
  • วิธีใช้ที่เก็บเซสชันด่วนที่ขับเคลื่อนโดย Google Cloud Firestore

2. การตั้งค่าและข้อกำหนด

ข้อกำหนดเบื้องต้น

เปิดใช้งาน Cloud Shell

  1. จาก Cloud Console ให้คลิกเปิดใช้งาน Cloud Shell d1264ca30785e435.png

cb81e7c8e34bc8d.png

หากคุณเริ่มใช้ Cloud Shell เป็นครั้งแรก คุณจะเห็นหน้าจอระดับกลางที่อธิบายว่า Cloud Shell คืออะไร หากเห็นหน้าจอระดับกลาง ให้คลิกต่อไป

d95252b003979716.png

การจัดสรรและเชื่อมต่อกับ Cloud Shell จะใช้เวลาไม่นาน

7833d5e1c5d18f54.png

เครื่องเสมือนนี้โหลดเครื่องมือพัฒนาซอฟต์แวร์ทั้งหมดที่จำเป็นไว้แล้ว โดยมีไดเรกทอรีหลักแบบถาวรขนาด 5 GB และทำงานใน Google Cloud ซึ่งช่วยเพิ่มประสิทธิภาพเครือข่ายและการตรวจสอบสิทธิ์ได้อย่างมาก คุณสามารถทำงานส่วนใหญ่หรือทั้งหมดใน Codelab นี้ได้ด้วยเบราว์เซอร์

เมื่อเชื่อมต่อกับ Cloud Shell แล้ว คุณควรเห็นว่าคุณได้รับการตรวจสอบสิทธิ์และระบบได้ตั้งค่าโปรเจ็กต์เป็นรหัสโปรเจ็กต์ของคุณ

  1. เรียกใช้คำสั่งต่อไปนี้ใน Cloud Shell เพื่อยืนยันว่าคุณได้รับการตรวจสอบสิทธิ์แล้ว
gcloud auth list

เอาต์พุตจากคำสั่ง

 Credentialed Accounts
ACTIVE  ACCOUNT
*       <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. เรียกใช้คำสั่งต่อไปนี้ใน Cloud Shell เพื่อยืนยันว่าคำสั่ง gcloud รู้จักโปรเจ็กต์ของคุณ
gcloud config list project

เอาต์พุตจากคำสั่ง

[core]
project = <PROJECT_ID>

หากไม่ได้ตั้งค่าไว้ คุณสามารถตั้งค่าได้ด้วยคำสั่งนี้

gcloud config set project <PROJECT_ID>

เอาต์พุตจากคำสั่ง

Updated property [core/project].

3. เปิดใช้ API และตั้งค่าตัวแปรสภาพแวดล้อม

เปิดใช้ API

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

gcloud services enable run.googleapis.com \
    cloudbuild.googleapis.com \
    aiplatform.googleapis.com \
    secretmanager.googleapis.com

ตั้งค่าตัวแปรสภาพแวดล้อม

คุณตั้งค่าตัวแปรสภาพแวดล้อมที่จะใช้ตลอดทั้งโค้ดแล็บนี้ได้

PROJECT_ID=<YOUR_PROJECT_ID>
REGION=<YOUR_REGION, e.g. us-central1>
SERVICE=chat-with-gemini
SERVICE_ACCOUNT="vertex-ai-caller"
SERVICE_ACCOUNT_ADDRESS=$SERVICE_ACCOUNT@$PROJECT_ID.iam.gserviceaccount.com
SECRET_ID="SESSION_SECRET"

4. สร้างและกำหนดค่าโปรเจ็กต์ Firebase

  1. ในคอนโซล Firebase ให้คลิกเพิ่มโปรเจ็กต์
  2. ป้อน <YOUR_PROJECT_ID> เพื่อเพิ่ม Firebase ไปยังโปรเจ็กต์ Google Cloud ที่มีอยู่
  3. เมื่อได้รับแจ้ง ให้อ่านและยอมรับข้อกำหนดของ Firebase
  4. คลิกต่อไป
  5. คลิกยืนยันแพ็กเกจเพื่อยืนยันแพ็กเกจการเรียกเก็บเงิน Firebase
  6. คุณจะเปิดใช้ Google Analytics สำหรับ Codelab นี้หรือไม่ก็ได้
  7. คลิกเพิ่ม Firebase
  8. เมื่อสร้างโปรเจ็กต์แล้ว ให้คลิกต่อไป
  9. จากเมนูสร้าง คลิกฐานข้อมูล Firestore
  10. คลิกสร้างฐานข้อมูล
  11. เลือกภูมิภาคจากเมนูแบบเลื่อนลงสถานที่ตั้ง แล้วคลิกถัดไป
  12. ใช้เริ่มต้นในโหมดที่ใช้งานจริงเริ่มต้น แล้วคลิกสร้าง

5. สร้างบัญชีบริการ

Cloud Run จะใช้บัญชีบริการนี้เพื่อเรียกใช้ Vertex AI Gemini API บัญชีบริการนี้จะมีสิทธิ์อ่านและเขียนไปยัง Firestore รวมถึงอ่านข้อมูลลับจาก Secret Manager ด้วย

ก่อนอื่น ให้สร้างบัญชีบริการโดยเรียกใช้คำสั่งนี้

gcloud iam service-accounts create $SERVICE_ACCOUNT \
  --display-name="Cloud Run to access Vertex AI APIs"

ประการที่ 2 ให้สิทธิ์บทบาทผู้ใช้ Vertex AI แก่บัญชีบริการ

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member serviceAccount:$SERVICE_ACCOUNT_ADDRESS \
  --role=roles/aiplatform.user

ตอนนี้ให้สร้างข้อมูลลับใน Secret Manager บริการ Cloud Run จะเข้าถึงข้อมูลลับนี้เป็นตัวแปรสภาพแวดล้อม ซึ่งจะได้รับการแก้ไขในเวลาเริ่มต้นอินสแตนซ์ ดูข้อมูลเพิ่มเติมเกี่ยวกับข้อมูลลับและ Cloud Run

gcloud secrets create $SECRET_ID --replication-policy="automatic"
printf "keyboard-cat" | gcloud secrets versions add $SECRET_ID --data-file=-

และให้สิทธิ์เข้าถึงข้อมูลลับของเซสชันด่วนใน Secret Manager แก่บัญชีบริการ

gcloud secrets add-iam-policy-binding $SECRET_ID \
    --member serviceAccount:$SERVICE_ACCOUNT_ADDRESS \
    --role='roles/secretmanager.secretAccessor'

สุดท้าย ให้สิทธิ์การอ่านและการเขียน Firestore แก่บัญชีบริการ

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member serviceAccount:$SERVICE_ACCOUNT_ADDRESS \
  --role=roles/datastore.user

6. สร้างบริการ Cloud Run

ก่อนอื่นให้สร้างไดเรกทอรีสำหรับซอร์สโค้ดและใช้คำสั่ง cd เพื่อไปยังไดเรกทอรีนั้น

mkdir chat-with-gemini && cd chat-with-gemini

จากนั้นสร้างไฟล์ package.json ที่มีเนื้อหาต่อไปนี้

{
  "name": "chat-with-gemini",
  "version": "1.0.0",
  "description": "",
  "main": "app.js",
  "scripts": {
    "start": "node app.js",
    "nodemon": "nodemon app.js",
    "cssdev": "npx tailwindcss -i ./input.css -o ./public/output.css --watch",
    "tailwind": "npx tailwindcss -i ./input.css -o ./public/output.css",
    "dev": "npm run tailwind && npm run nodemon"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@google-cloud/connect-firestore": "^3.0.0",
    "@google-cloud/firestore": "^7.5.0",
    "@google-cloud/vertexai": "^0.4.0",
    "axios": "^1.6.8",
    "express": "^4.18.2",
    "express-session": "^1.18.0",
    "express-ws": "^5.0.2",
    "htmx.org": "^1.9.10"
  },
  "devDependencies": {
    "nodemon": "^3.1.0",
    "tailwindcss": "^3.4.1"
  }
}

จากนั้นสร้างไฟล์ต้นฉบับ app.js ที่มีเนื้อหาด้านล่าง ไฟล์นี้มีจุดแรกเข้าสำหรับบริการและมีตรรกะหลักสำหรับแอป

const express = require("express");
const app = express();
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
const path = require("path");

const fs = require("fs");
const util = require("util");
const { spinnerSvg } = require("./spinnerSvg.js");

// cloud run retrieves secret at instance startup time
const secret = process.env.SESSION_SECRET;

const { Firestore } = require("@google-cloud/firestore");
const { FirestoreStore } = require("@google-cloud/connect-firestore");
var session = require("express-session");
app.set("trust proxy", 1); // trust first proxy
app.use(
    session({
        store: new FirestoreStore({
            dataset: new Firestore(),
            kind: "express-sessions"
        }),
        secret: secret,
        /* set secure to false for local dev session history testing */
        /* see more at https://expressjs.com/en/resources/middleware/session.html */
        cookie: { secure: true },
        resave: false,
        saveUninitialized: true
    })
);

const expressWs = require("express-ws")(app);

app.use(express.static("public"));

// Vertex AI Section
const { VertexAI } = require("@google-cloud/vertexai");

// instance of Vertex model
let generativeModel;

// on startup
const port = parseInt(process.env.PORT) || 8080;
app.listen(port, async () => {
    console.log(`demo1: listening on port ${port}`);

    // get project and location from metadata service
    const metadataService = require("./metadataService.js");

    const project = await metadataService.getProjectId();
    const location = await metadataService.getRegion();

    // Vertex client library instance
    const vertex_ai = new VertexAI({
        project: project,
        location: location
    });

    // Instantiate models
    generativeModel = vertex_ai.getGenerativeModel({
        model: "gemini-1.0-pro-001"
    });
});

app.ws("/sendMessage", async function (ws, req) {
    if (!req.session.chathistory || req.session.chathistory.length == 0) {
        req.session.chathistory = [];
    }

    let chatWithModel = generativeModel.startChat({
        history: req.session.chathistory
    });

    ws.on("message", async function (message) {

        console.log("req.sessionID: ", req.sessionID);
        // get session id

        let questionToAsk = JSON.parse(message).message;
        console.log("WebSocket message: " + questionToAsk);

        ws.send(`<div hx-swap-oob="beforeend:#toupdate"><div
                        id="questionToAsk"
                        class="text-black m-2 text-right border p-2 rounded-lg ml-24">
                        ${questionToAsk}
                    </div></div>`);

        // to simulate a natural pause in conversation
        await sleep(500);

        // get timestamp for div to replace
        const now = "fromGemini" + Date.now();

        ws.send(`<div hx-swap-oob="beforeend:#toupdate"><div
                        id=${now}
                        class=" text-blue-400 m-2 text-left border p-2 rounded-lg mr-24">
                        ${spinnerSvg} 
                    </div></div>`);

        const results = await chatWithModel.sendMessage(questionToAsk);
        const answer =
            results.response.candidates[0].content.parts[0].text;

        ws.send(`<div
                        id=${now}
                        hx-swap-oob="true"
                        hx-swap="outerHTML"
                        class="text-blue-400 m-2 text-left border p-2 rounded-lg mr-24">
                        ${answer}
                    </div>`);

                    // save to current chat history
        let userHistory = {
            role: "user",
            parts: [{ text: questionToAsk }]
        };
        let modelHistory = {
            role: "model",
            parts: [{ text: answer }]
        };

        req.session.chathistory.push(userHistory);
        req.session.chathistory.push(modelHistory);

        // console.log(
        //     "newly saved chat history: ",
        //     util.inspect(req.session.chathistory, {
        //         showHidden: false,
        //         depth: null,
        //         colors: true
        //     })
        // );
        req.session.save();
    });

    ws.on("close", () => {
        console.log("WebSocket was closed");
    });
});

function sleep(ms) {
    return new Promise((resolve) => {
        setTimeout(resolve, ms);
    });
}

// gracefully close the web sockets
process.on("SIGTERM", () => {
    server.close();
});

สร้างไฟล์ tailwind.config.js สำหรับ tailwindCSS

/** @type {import('tailwindcss').Config} */
module.exports = {
    content: ["./**/*.{html,js}"],
    theme: {
        extend: {}
    },
    plugins: []
};

สร้างไฟล์ metadataService.js เพื่อรับรหัสโปรเจ็กต์และภูมิภาคสำหรับบริการ Cloud Run ที่ใช้งาน ระบบจะใช้ค่าเหล่านี้เพื่อสร้างอินสแตนซ์ของไลบรารีของไคลเอ็นต์ Vertex AI

const your_project_id = "YOUR_PROJECT_ID";
const your_region = "YOUR_REGION";

const axios = require("axios");

module.exports = {
    getProjectId: async () => {
        let project = "";
        try {
            // Fetch the token to make a GCF to GCF call
            const response = await axios.get(
                "http://metadata.google.internal/computeMetadata/v1/project/project-id",
                {
                    headers: {
                        "Metadata-Flavor": "Google"
                    }
                }
            );

            if (response.data == "") {
                // running locally on Cloud Shell
                project = your_project_id;
            } else {
                // running on Clodu Run. Use project id from metadata service
                project = response.data;
            }
        } catch (ex) {
            // running locally on local terminal
            project = your_project_id;
        }

        return project;
    },

    getRegion: async () => {
        let region = "";
        try {
            // Fetch the token to make a GCF to GCF call
            const response = await axios.get(
                "http://metadata.google.internal/computeMetadata/v1/instance/region",
                {
                    headers: {
                        "Metadata-Flavor": "Google"
                    }
                }
            );

            if (response.data == "") {
                // running locally on Cloud Shell
                region = your_region;
            } else {
                // running on Clodu Run. Use region from metadata service
                let regionFull = response.data;
                const index = regionFull.lastIndexOf("/");
                region = regionFull.substring(index + 1);
            }
        } catch (ex) {
            // running locally on local terminal
            region = your_region;
        }
        return region;
    }
};

สร้างไฟล์ชื่อ spinnerSvg.js

module.exports.spinnerSvg = `<svg class="animate-spin -ml-1 mr-3 h-5 w-5 text-blue-500"
                    xmlns="http://www.w3.org/2000/svg"
                    fill="none"
                    viewBox="0 0 24 24"
                >
                    <circle
                        class="opacity-25"
                        cx="12"
                        cy="12"
                        r="10"
                        stroke="currentColor"
                        stroke-width="4"
                    ></circle>
                    <path
                        class="opacity-75"
                        fill="currentColor"
                        d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
                    ></path></svg>`;

สุดท้าย ให้สร้างไฟล์ input.css สำหรับ tailwindCSS

@tailwind base;
@tailwind components;
@tailwind utilities;

ตอนนี้ให้สร้างไดเรกทอรี public ใหม่

mkdir public
cd public

และภายในไดเรกทอรีสาธารณะนั้น ให้สร้างไฟล์ index.html สำหรับฟรอนท์เอนด์ซึ่งจะใช้ htmx

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta
            name="viewport"
            content="width=device-width, initial-scale=1.0"
        />
        <script
            src="https://unpkg.com/htmx.org@1.9.10"
            integrity="sha384-D1Kt99CQMDuVetoL1lrYwg5t+9QdHe7NLX/SoJYkXDFfX37iInKRy5xLSi8nO7UC"
            crossorigin="anonymous"
        ></script>

        <link href="./output.css" rel="stylesheet" />
        <script src="https://unpkg.com/htmx.org/dist/ext/ws.js"></script>

        <title>Demo 1</title>
    </head>
    <body>
        <div id="herewego" text-center>
            <!-- <div id="replaceme2" hx-swap-oob="true">Hello world</div> -->
            <div
                class="container mx-auto mt-8 text-center max-w-screen-lg"
            >
                <div
                    class="overflow-y-scroll bg-white p-2 border h-[500px] space-y-4 rounded-lg m-auto"
                >
                    <div id="toupdate"></div>
                </div>
                <form
                    hx-trigger="submit, keyup[keyCode==13] from:body"
                    hx-ext="ws"
                    ws-connect="/sendMessage"
                    ws-send=""
                    hx-on="htmx:wsAfterSend: document.getElementById('message').value = ''"
                >
                    <div class="mb-6 mt-6 flex gap-4">
                        <textarea
                            rows="2"
                            type="text"
                            id="message"
                            name="message"
                            class="block grow rounded-lg border p-6 resize-none"
                            required
                        >
Is C# a programming language or a musical note?</textarea
                        >
                        <button
                            type="submit"
                            class="bg-blue-500 text-white px-4 py-2 rounded-lg text-center text-sm font-medium"
                        >
                            Send
                        </button>
                    </div>
                </form>
            </div>
        </div>
    </body>
</html>

7. เรียกใช้บริการในเครื่อง

ก่อนอื่น ให้ตรวจสอบว่าคุณอยู่ในไดเรกทอรีราก chat-with-gemini สำหรับโค้ดแล็บ

cd .. && pwd

จากนั้นติดตั้งการอ้างอิงโดยเรียกใช้คำสั่งต่อไปนี้

npm install

การใช้ ADC เมื่อเรียกใช้ในเครื่อง

หากคุณใช้งานใน Cloud Shell แสดงว่าคุณกำลังใช้งานเครื่องเสมือนของ Google Compute Engine อยู่แล้ว ข้อมูลรับรองที่เชื่อมโยงกับเครื่องเสมือนนี้ (ตามที่แสดงโดยการเรียกใช้ gcloud auth list) จะถูกใช้โดยข้อมูลรับรองเริ่มต้นของแอปพลิเคชันโดยอัตโนมัติ จึงไม่จำเป็นต้องใช้คำสั่ง gcloud auth application-default login คุณข้ามไปยังส่วนสร้างลับเซสชันในเครื่องได้

อย่างไรก็ตาม หากคุณเรียกใช้ในเทอร์มินัลในเครื่อง (เช่น ไม่ได้อยู่ใน Cloud Shell) คุณจะต้องใช้ข้อมูลรับรองเริ่มต้นของแอปพลิเคชันเพื่อตรวจสอบสิทธิ์ใน Google APIs คุณสามารถ 1) เข้าสู่ระบบโดยใช้ข้อมูลเข้าสู่ระบบ (หากมีทั้งบทบาทผู้ใช้ Vertex AI และผู้ใช้ Datastore) หรือ 2) เข้าสู่ระบบโดยการแอบอ้างเป็นบัญชีบริการที่ใช้ในโค้ดแล็บนี้

ตัวเลือกที่ 1) ใช้ข้อมูลเข้าสู่ระบบสำหรับ ADC

หากต้องการใช้ข้อมูลเข้าสู่ระบบ คุณสามารถเรียกใช้ gcloud auth list ก่อนเพื่อตรวจสอบวิธีที่คุณได้รับการตรวจสอบสิทธิ์ใน gcloud จากนั้น คุณอาจต้องให้บทบาทผู้ใช้ Vertex AI แก่ข้อมูลประจำตัว หากข้อมูลประจำตัวของคุณมีบทบาทเจ้าของ แสดงว่าคุณมีบทบาทผู้ใช้ Vertex AI นี้อยู่แล้ว หากไม่ได้ ให้เรียกใช้คำสั่งนี้เพื่อมอบบทบาทผู้ใช้ Vertex AI และบทบาทผู้ใช้ Datastore ให้กับข้อมูลประจำตัวของคุณ

USER=<YOUR_PRINCIPAL_EMAIL>

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member user:$USER \
  --role=roles/aiplatform.user

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member user:$USER \
  --role=roles/datastore.user

จากนั้นเรียกใช้คำสั่งต่อไปนี้

gcloud auth application-default login

ตัวเลือกที่ 2) การแอบอ้างบัญชีบริการสำหรับ ADC

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

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member user:$USER \
  --role=roles/iam.serviceAccountTokenCreator

จากนั้นคุณจะเรียกใช้คำสั่งต่อไปนี้เพื่อใช้ ADC กับบัญชีบริการ

gcloud auth application-default login --impersonate-service-account=$SERVICE_ACCOUNT_ADDRESS

สร้างข้อมูลลับของเซสชันในเครื่อง

ตอนนี้ให้สร้างความลับของเซสชันในเครื่องสำหรับการพัฒนาในเครื่อง

export SESSION_SECRET=local-secret

เรียกใช้แอปในเครื่อง

สุดท้าย คุณสามารถเริ่มแอปได้โดยเรียกใช้สคริปต์ต่อไปนี้ นอกจากนี้ สคริปต์นี้จะสร้างไฟล์ output.css จาก tailwindCSS ด้วย

npm run dev

คุณสามารถดูตัวอย่างเว็บไซต์ได้โดยเปิดปุ่มแสดงตัวอย่างเว็บแล้วเลือกพอร์ตแสดงตัวอย่าง 8080

ตัวอย่างเว็บ - ปุ่มแสดงตัวอย่างบนพอร์ต 8080

8. ติดตั้งใช้งานบริการ

ก่อนอื่น ให้เรียกใช้คำสั่งนี้เพื่อเริ่มการติดตั้งใช้งานและระบุบัญชีบริการที่จะใช้ หากไม่ได้ระบุบัญชีบริการ ระบบจะใช้บัญชีบริการ Compute เริ่มต้น

gcloud run deploy $SERVICE \
 --service-account $SERVICE_ACCOUNT_ADDRESS \
 --source . \
  --region $REGION \
  --allow-unauthenticated \
  --set-secrets="SESSION_SECRET=$(echo $SECRET_ID):1"

หากระบบแจ้งว่า "การติดตั้งใช้งานจากแหล่งที่มาต้องใช้ที่เก็บ Docker ของ Artifact Registry เพื่อจัดเก็บคอนเทนเนอร์ที่สร้างขึ้น ระบบจะสร้างที่เก็บชื่อ [cloud-run-source-deploy] ในภูมิภาค [us-central1]" ให้กด "y" เพื่อยอมรับและดำเนินการต่อ

9. ทดสอบบริการ

เมื่อติดตั้งใช้งานแล้ว ให้เปิด URL ของบริการในเว็บเบราว์เซอร์ จากนั้นถามคำถามกับ Gemini เช่น "ฉันฝึกเล่นกีตาร์แต่ก็เป็นวิศวกรซอฟต์แวร์ด้วย เมื่อเห็น "C#" ฉันควรคิดว่าเป็นภาษาโปรแกรมหรือโน้ตดนตรี ฉันควรเลือกอันไหน

10. ยินดีด้วย

ขอแสดงความยินดีที่ทำ Codelab นี้เสร็จสมบูรณ์

เราขอแนะนำให้อ่านเอกสารประกอบ Cloud Run และ Vertex AI Gemini API

สิ่งที่เราได้พูดถึง

  • วิธีใช้ htmx, tailwindcss และ express.js เพื่อสร้างบริการ Cloud Run
  • วิธีใช้ไลบรารีของไคลเอ็นต์ Vertex AI เพื่อตรวจสอบสิทธิ์กับ Google API
  • วิธีสร้างแชทบอทเพื่อโต้ตอบกับโมเดล Gemini
  • วิธีทำให้บริการ Cloud Run ใช้งานได้โดยไม่ต้องใช้ Dockerfile
  • วิธีใช้ที่เก็บเซสชันด่วนที่ขับเคลื่อนโดย Google Cloud Firestore

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

หากต้องการหลีกเลี่ยงการเรียกเก็บเงินโดยไม่ตั้งใจ (เช่น หากมีการเรียกใช้บริการ Cloud Run โดยไม่ตั้งใจมากกว่าการจัดสรรการเรียกใช้ Cloud Run รายเดือนในระดับฟรี) คุณสามารถลบ Cloud Run หรือลบโปรเจ็กต์ที่สร้างในขั้นตอนที่ 2 ได้

หากต้องการลบบริการ Cloud Run ให้ไปที่ Cloud Console ของ Cloud Run ที่ https://console.cloud.google.com/run แล้วลบchat-with-geminiบริการ นอกจากนี้ คุณอาจต้องลบบัญชีบริการ vertex-ai-caller หรือเพิกถอนบทบาทผู้ใช้ Vertex AI เพื่อหลีกเลี่ยงการเรียกใช้ Gemini โดยไม่ตั้งใจ

หากเลือกที่จะลบทั้งโปรเจ็กต์ ให้ไปที่ https://console.cloud.google.com/cloud-resource-manager เลือกโปรเจ็กต์ที่สร้างในขั้นตอนที่ 2 แล้วเลือก "ลบ" หากลบโปรเจ็กต์ คุณจะต้องเปลี่ยนโปรเจ็กต์ใน Cloud SDK คุณดูรายการโปรเจ็กต์ทั้งหมดที่พร้อมใช้งานได้โดยเรียกใช้ gcloud projects list