ক্লাউড রানে একটি মিথুন-চালিত চ্যাট অ্যাপ কীভাবে স্থাপন করবেন

১. ভূমিকা

সংক্ষিপ্ত বিবরণ

এই কোডল্যাবে আপনি দেখবেন, কীভাবে Vertex AI Gemini API এবং Vertex AI ক্লায়েন্ট লাইব্রেরি ব্যবহার করে Node-এ লেখা একটি সাধারণ চ্যাটবট তৈরি করা যায়। এই অ্যাপটি Google Cloud Firestore দ্বারা সমর্থিত একটি Express সেশন স্টোর ব্যবহার করে।

আপনি যা শিখবেন

  • কীভাবে htmx, tailwindcss, এবং express.js ব্যবহার করে একটি ক্লাউড রান সার্ভিস তৈরি করবেন
  • গুগল এপিআই-তে প্রমাণীকরণের জন্য কীভাবে ভার্টেক্স এআই ক্লায়েন্ট লাইব্রেরি ব্যবহার করবেন
  • জেমিনি মডেলের সাথে আলাপচারিতার জন্য কীভাবে একটি চ্যাটবট তৈরি করবেন
  • ডকার ফাইল ছাড়া ক্লাউড রান সার্ভিসে কীভাবে ডিপ্লয় করবেন
  • গুগল ক্লাউড ফায়ারস্টোর দ্বারা সমর্থিত একটি এক্সপ্রেস সেশন স্টোর কীভাবে ব্যবহার করবেন

২. সেটআপ এবং প্রয়োজনীয়তা

পূর্বশর্ত

ক্লাউড শেল সক্রিয় করুন

  1. ক্লাউড কনসোল থেকে, অ্যাক্টিভেট ক্লাউড শেল-এ ক্লিক করুন। d1264ca30785e435.png .

cb81e7c8e34bc8d.png

আপনি যদি প্রথমবারের মতো ক্লাউড শেল চালু করেন, তাহলে এটি কী তা বর্ণনা করে একটি মধ্যবর্তী স্ক্রিন আপনার সামনে আসবে। যদি একটি মধ্যবর্তী স্ক্রিন আসে, তাহলে 'চালিয়ে যান' (Continue) এ ক্লিক করুন।

d95252b003979716.png

ক্লাউড শেল প্রস্তুত করতে এবং এর সাথে সংযোগ স্থাপন করতে মাত্র কয়েক মুহূর্ত সময় লাগা উচিত।

7833d5e1c5d18f54.png

এই ভার্চুয়াল মেশিনটিতে প্রয়োজনীয় সমস্ত ডেভেলপমেন্ট টুলস লোড করা আছে। এটি একটি স্থায়ী ৫ জিবি হোম ডিরেক্টরি প্রদান করে এবং গুগল ক্লাউডে চলে, যা নেটওয়ার্ক পারফরম্যান্স ও অথেনটিকেশনকে ব্যাপকভাবে উন্নত করে। এই কোডল্যাবে আপনার প্রায় সমস্ত কাজই একটি ব্রাউজার দিয়ে করা সম্ভব।

ক্লাউড শেলে সংযুক্ত হওয়ার পর, আপনি দেখতে পাবেন যে আপনাকে প্রমাণীকৃত করা হয়েছে এবং প্রজেক্টটি আপনার প্রজেক্ট আইডিতে সেট করা আছে।

  1. আপনি প্রমাণীকৃত কিনা তা নিশ্চিত করতে ক্লাউড শেলে নিম্নলিখিত কমান্ডটি চালান:
gcloud auth list

কমান্ড আউটপুট

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

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. gcloud কমান্ডটি আপনার প্রজেক্ট সম্পর্কে জানে কিনা তা নিশ্চিত করতে ক্লাউড শেলে নিম্নলিখিত কমান্ডটি চালান:
gcloud config list project

কমান্ড আউটপুট

[core]
project = <PROJECT_ID>

যদি তা না থাকে, তবে আপনি এই কমান্ডটি দিয়ে এটি সেট করতে পারেন:

gcloud config set project <PROJECT_ID>

কমান্ড আউটপুট

Updated property [core/project].

৩. এপিআই সক্রিয় করুন এবং এনভায়রনমেন্ট ভেরিয়েবল সেট করুন

এপিআই সক্ষম করুন

এই কোডল্যাবটি ব্যবহার শুরু করার আগে, আপনাকে কয়েকটি এপিআই (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"

৪. একটি ফায়ারবেস প্রজেক্ট তৈরি এবং কনফিগার করুন

  1. Firebase কনসোলে , 'Add project'- এ ক্লিক করুন।
  2. আপনার বিদ্যমান গুগল ক্লাউড প্রজেক্টগুলোর কোনো একটিতে ফায়ারবেস যোগ করতে <আপনার_প্রজেক্ট_আইডি> লিখুন।
  3. অনুরোধ করা হলে, Firebase-এর শর্তাবলী পর্যালোচনা করুন এবং মেনে নিন।
  4. চালিয়ে যান-এ ক্লিক করুন।
  5. Firebase বিলিং প্ল্যানটি নিশ্চিত করতে ‘Confirm Plan’-এ ক্লিক করুন।
  6. এই কোডল্যাবের জন্য গুগল অ্যানালিটিক্স চালু করা ঐচ্ছিক।
  7. ফায়ারবেস যোগ করুন -এ ক্লিক করুন।
  8. প্রজেক্টটি তৈরি হয়ে গেলে, 'চালিয়ে যান'-এ ক্লিক করুন।
  9. Build মেনু থেকে Firestore database-এ ক্লিক করুন।
  10. ডাটাবেস তৈরি করুন -এ ক্লিক করুন।
  11. লোকেশন ড্রপ-ডাউন থেকে আপনার অঞ্চল নির্বাচন করুন, তারপর নেক্সট-এ ক্লিক করুন।
  12. ডিফল্টভাবে প্রোডাকশন মোডে স্টার্ট করুন , তারপর ক্রিয়েট-এ ক্লিক করুন।

৫. একটি পরিষেবা অ্যাকাউন্ট তৈরি করুন

এই সার্ভিস অ্যাকাউন্টটি ক্লাউড রান দ্বারা ভার্টেক্স এআই জেমিনি এপিআই কল করার জন্য ব্যবহৃত হবে। এই সার্ভিস অ্যাকাউন্টটির ফায়ারস্টোরে পড়া ও লেখার এবং সিক্রেট ম্যানেজার থেকে গোপনীয় তথ্য পড়ার অনুমতিও থাকবে।

প্রথমে, এই কমান্ডটি চালিয়ে সার্ভিস অ্যাকাউন্টটি তৈরি করুন:

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

দ্বিতীয়ত, সার্ভিস অ্যাকাউন্টটিকে Vertex AI User রোলটি প্রদান করুন।

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

এখন, সিক্রেট ম্যানেজারে একটি সিক্রেট তৈরি করুন। ক্লাউড রান সার্ভিস এই সিক্রেটটিকে একটি এনভায়রনমেন্ট ভেরিয়েবল হিসেবে অ্যাক্সেস করবে, যা ইনস্ট্যান্স চালু হওয়ার সময় রিজলভ করা হয়। আপনি সিক্রেট এবং ক্লাউড রান সম্পর্কে আরও জানতে পারেন।

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

এবং সিক্রেট ম্যানেজারে সার্ভিস অ্যাকাউন্টটিকে এক্সপ্রেস সেশন সিক্রেটে অ্যাক্সেস প্রদান করুন।

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

সবশেষে, সার্ভিস অ্যাকাউন্টটিকে ফায়ারস্টোরে রিড এবং রাইট অ্যাক্সেস দিন।

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

৬. ক্লাউড রান পরিষেবাটি তৈরি করুন

প্রথমে, সোর্স কোডের জন্য একটি ডিরেক্টরি তৈরি করুন এবং সেই ডিরেক্টরিতে প্রবেশ করুন।

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

tailwindCSS-এর জন্য tailwind.config.js ফাইলটি তৈরি করুন।

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

ডেপ্লয় করা ক্লাউড রান সার্ভিসের প্রজেক্ট আইডি এবং রিজিয়ন পাওয়ার জন্য metadataService.js ফাইলটি তৈরি করুন। এই মানগুলো ভার্টেক্স এআই ক্লায়েন্ট লাইব্রেরির একটি ইনস্ট্যান্স তৈরি করতে ব্যবহৃত হবে।

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

সবশেষে, tailwindCSS-এর জন্য একটি input.css ফাইল তৈরি করুন।

@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>

৭. সার্ভিসটি স্থানীয়ভাবে চালান

প্রথমে, নিশ্চিত করুন যে আপনি আপনার কোডল্যাবের রুট ডিরেক্টরি chat-with-gemini তে আছেন।

cd .. && pwd

এরপর, নিচের কমান্ডটি চালিয়ে ডিপেন্ডেন্সিগুলো ইনস্টল করুন:

npm install

স্থানীয়ভাবে চালানোর সময় ADC ব্যবহার করা

আপনি যদি ক্লাউড শেলে (Cloud Shell) চালাচ্ছেন, তাহলে আপনি ইতিমধ্যেই একটি গুগল কম্পিউট ইঞ্জিন (Google Compute Engine) ভার্চুয়াল মেশিনে কাজ করছেন। এই ভার্চুয়াল মেশিনের সাথে যুক্ত আপনার ক্রেডেনশিয়াল (যা gcloud auth list চালালে দেখা যায়) অ্যাপ্লিকেশন ডিফল্ট ক্রেডেনশিয়াল (Application Default Credentials) দ্বারা স্বয়ংক্রিয়ভাবে ব্যবহৃত হবে, তাই gcloud auth application-default login কমান্ডটি ব্যবহার করার প্রয়োজন নেই। আপনি সরাসরি 'একটি স্থানীয় সেশন সিক্রেট তৈরি করুন' (Create a local session secret) অংশে চলে যেতে পারেন।

তবে, আপনি যদি আপনার লোকাল টার্মিনালে (অর্থাৎ ক্লাউড শেল-এ নয়) এটি চালান, তাহলে গুগল এপিআই-তে প্রমাণীকরণের জন্য আপনাকে অ্যাপ্লিকেশন ডিফল্ট ক্রেডেনশিয়াল ব্যবহার করতে হবে। আপনি হয় ১) আপনার ক্রেডেনশিয়াল ব্যবহার করে লগইন করতে পারেন (যদি আপনার ভার্টেক্স এআই ইউজার এবং ডেটাস্টোর ইউজার উভয় রোল থাকে) অথবা ২) এই কোডল্যাবে ব্যবহৃত সার্ভিস অ্যাকাউন্টটি ইমপারসোনেট করে লগইন করতে পারেন।

বিকল্প ১) ADC-এর জন্য আপনার পরিচয়পত্র ব্যবহার করা

আপনি যদি আপনার ক্রেডেনশিয়াল ব্যবহার করতে চান, তাহলে প্রথমে gcloud-এ আপনার অথেন্টিকেশন যাচাই করার জন্য gcloud auth list চালাতে পারেন। এরপর, আপনাকে আপনার আইডেন্টিটিকে Vertex AI User রোলটি প্রদান করতে হতে পারে। যদি আপনার আইডেন্টিটির Owner রোল থাকে, তাহলে আপনার কাছে ইতিমধ্যেই এই 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

বিকল্প ২) এডিসি-র জন্য একটি সার্ভিস অ্যাকাউন্টের ছদ্মবেশ ধারণ করা

আপনি যদি এই কোডল্যাবে তৈরি করা সার্ভিস অ্যাকাউন্টটি ব্যবহার করতে চান, তাহলে আপনার ইউজার অ্যাকাউন্টে ‘সার্ভিস অ্যাকাউন্ট টোকেন ক্রিয়েটর’ রোলটি থাকতে হবে। নিম্নলিখিত কমান্ডটি চালিয়ে আপনি এই রোলটি পেতে পারেন:

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

অ্যাপটি স্থানীয়ভাবে চালান

সবশেষে, নিচের স্ক্রিপ্টটি রান করে আপনি অ্যাপটি চালু করতে পারেন। এই স্ক্রিপ্টটি tailwindCSS থেকে output.css ফাইলটিও তৈরি করবে।

npm run dev

আপনি ওয়েব প্রিভিউ বাটনটি খুলে এবং প্রিভিউ পোর্ট ৮০৮০ নির্বাচন করে ওয়েবসাইটটি প্রিভিউ করতে পারেন।

ওয়েব প্রিভিউ - পোর্ট ৮০৮০-তে প্রিভিউ বাটন

৮. পরিষেবাটি স্থাপন করুন

প্রথমে, ডেপ্লয়মেন্ট শুরু করতে এই কমান্ডটি চালান এবং ব্যবহৃতব্য সার্ভিস অ্যাকাউন্টটি নির্দিষ্ট করুন। যদি কোনো সার্ভিস অ্যাকাউন্ট নির্দিষ্ট করা না থাকে, তাহলে ডিফল্ট কম্পিউট সার্ভিস অ্যাকাউন্টটি ব্যবহৃত হবে।

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

যদি আপনাকে এই বার্তাটি দেখানো হয় যে, "সোর্স থেকে ডিপ্লয় করার জন্য বিল্ড করা কন্টেইনারগুলো সংরক্ষণের জন্য একটি আর্টিফ্যাক্ট রেজিস্ট্রি ডকার রিপোজিটরি প্রয়োজন। [us-central1] অঞ্চলে [cloud-run-source-deploy] নামের একটি রিপোজিটরি তৈরি করা হবে।", তবে তা গ্রহণ করে চালিয়ে যাওয়ার জন্য 'y' চাপুন।

৯. পরিষেবাটি পরীক্ষা করুন

একবার ডেপ্লয় করা হয়ে গেলে, আপনার ওয়েব ব্রাউজারে সার্ভিস ইউআরএলটি খুলুন। এরপর জেমিনিকে একটি প্রশ্ন করুন, যেমন: "আমি গিটার বাজাই কিন্তু আমি একজন সফটওয়্যার ইঞ্জিনিয়ারও। যখন আমি 'C#' দেখি, তখন কি এটিকে একটি প্রোগ্রামিং ল্যাঙ্গুয়েজ নাকি একটি মিউজিক্যাল নোট হিসেবে ভাবব? আমার কোনটি বেছে নেওয়া উচিত?"

১০. অভিনন্দন!

কোডল্যাবটি সম্পন্ন করার জন্য অভিনন্দন!

আমরা Cloud Run এবং Vertex AI Gemini API-এর ডকুমেন্টেশন পর্যালোচনা করার পরামর্শ দিই।

আমরা যা আলোচনা করেছি

  • কীভাবে htmx, tailwindcss, এবং express.js ব্যবহার করে একটি ক্লাউড রান সার্ভিস তৈরি করবেন
  • গুগল এপিআই-তে প্রমাণীকরণের জন্য কীভাবে ভার্টেক্স এআই ক্লায়েন্ট লাইব্রেরি ব্যবহার করবেন
  • জেমিনি মডেলের সাথে আলাপচারিতার জন্য কীভাবে একটি চ্যাট বট তৈরি করবেন
  • ডকার ফাইল ছাড়া ক্লাউড রান সার্ভিসে কীভাবে ডিপ্লয় করবেন
  • গুগল ক্লাউড ফায়ারস্টোর দ্বারা সমর্থিত একটি এক্সপ্রেস সেশন স্টোর কীভাবে ব্যবহার করবেন

১১. পরিষ্কার করুন

অনিচ্ছাকৃত চার্জ এড়াতে (উদাহরণস্বরূপ, যদি ফ্রি টিয়ারে আপনার মাসিক ক্লাউড রান ব্যবহারের বরাদ্দের চেয়ে ক্লাউড রান পরিষেবাগুলো অনিচ্ছাকৃতভাবে বেশিবার চালু করা হয়), আপনি হয় ক্লাউড রানটি অথবা ধাপ ২-এ তৈরি করা প্রজেক্টটি ডিলিট করে দিতে পারেন।

ক্লাউড রান পরিষেবাটি মুছে ফেলার জন্য, https://console.cloud.google.com/run-এ অবস্থিত ক্লাউড রান ক্লাউড কনসোলে যান এবং chat-with-gemini পরিষেবাটি মুছে ফেলুন। জেমিনিতে কোনো অনিচ্ছাকৃত কল এড়ানোর জন্য, আপনি vertex-ai-caller পরিষেবা অ্যাকাউন্টটি মুছে ফেলতে পারেন অথবা Vertex AI ব্যবহারকারীর ভূমিকাটি বাতিল করতে পারেন।

আপনি যদি পুরো প্রজেক্টটি মুছে ফেলতে চান, তাহলে আপনি https://console.cloud.google.com/cloud-resource-manager -এ গিয়ে, ধাপ ২-এ তৈরি করা প্রজেক্টটি নির্বাচন করে 'ডিলিট' (Delete) বিকল্পটি বেছে নিতে পারেন। প্রজেক্টটি মুছে ফেললে, আপনাকে আপনার ক্লাউড এসডিকে (Cloud SDK)-তে প্রজেক্ট পরিবর্তন করতে হবে। আপনি gcloud projects list চালিয়ে সমস্ত উপলব্ধ প্রজেক্টের তালিকা দেখতে পারেন।