অনুরোধের আগে এবং পরে কাস্টম সার্ভার-সাইড স্ক্রিপ্ট চালান


আপনার ক্লায়েন্ট কোড পরিবর্তন না করেই , আপনি Firebase AI Logic- এর মাধ্যমে আপনার অ্যাপ থেকে Gemini API- তে পাঠানো প্রতিটি অনুরোধের আগে ও পরে আপনার নিজস্ব কাস্টম সার্ভার-সাইড স্ক্রিপ্ট চালাতে পারেন। আপনি এই স্ক্রিপ্টগুলোকে Cloud Functions for Firebase এ ডেপ্লয় করা কলব্যাক-স্টাইলের ফাংশন হিসেবে প্রয়োগ করেন।

এই সক্ষমতার মাধ্যমে, আপনি প্রম্পট নিয়ন্ত্রণ, টোকেন ব্যবহারের সীমা নির্ধারণ, অ্যানালিটিক্সের জন্য লগ তৈরি, বা প্রতিক্রিয়ার বিষয়বস্তু গোপন করার মতো কাজ করতে পারেন।

দুই ধরনের ইভেন্ট উপলব্ধ আছে:

  • beforeGenerateContent : কোনো অনুরোধ Gemini API-তে পৌঁছানোর আগে এটি চলে। এই ফাংশনটি অনুরোধটি পরীক্ষা বা পরিবর্তন করতে পারে, অথবা একটি ত্রুটি দেখিয়ে অনুরোধটি সম্পূর্ণরূপে ব্লক করে দিতে পারে।

  • afterGenerateContent : Gemini API থেকে রেসপন্স ফেরত পাঠানোর পর এবং ক্লায়েন্ট অ্যাপে তা ফেরত পাঠানোর আগে এই ফাংশনটি চলে। এই ফাংশনটি রেসপন্সটি পরীক্ষা বা পরিবর্তন করতে পারে, রেসপন্সটি পুরোপুরি ব্লক করতে পারে, অথবা শুধু পর্যবেক্ষণ করতে পারে (যেমন লগিং বা অডিটিং-এর জন্য)।

একবার আপনার স্ক্রিপ্টগুলি Cloud Functions for Firebase ফাংশন হিসাবে ডেপ্লয় করা হলে, সেগুলি Firebase AI Logic ট্রিগার হিসাবে নিবন্ধিত হয়, যার অর্থ হল সেগুলি আপনার প্রোজেক্টে Gemini API- তে Firebase AI Logic-এর মাধ্যমে করা প্রতিটি generateContent অনুরোধের জন্য রান করবে ( সার্ভার প্রম্পট টেমপ্লেট দিয়ে করা অনুরোধগুলি সহ)।

যেসব অনুরোধ Firebase AI Logic-এর মাধ্যমে করা হয় না, Gemini API- তে সেগুলোর দ্বারা এই ফাংশনগুলো সক্রিয় হয় না

পূর্বশর্ত

ধাপ ১ : Cloud Functions for Firebase ব্যবহার করতে আপনার প্রজেক্টটি সেট আপ করুন।

আপনি যদি আপনার Firebase প্রজেক্টে আগে কখনো Cloud Functions for Firebase ব্যবহার না করে থাকেন, তাহলে নিচের সেটআপটি সম্পন্ন করুন।

  1. নিশ্চিত করুন যে আপনার Firebase প্রজেক্টটি Blaze-এর পে-অ্যাজ-ইউ-গো প্রাইসিং প্ল্যানে রয়েছে ( Cloud Functions for Firebase ব্যবহার করার জন্য এটি আবশ্যক)।

  2. কমান্ড-লাইন ইন্টারফেস (CLI) ইনস্টল করুন: gcloud CLI এবং Firebase CLI

  3. আপনার ফাংশনটি বিল্ড করার জন্য ডিফল্ট কম্পিউট সার্ভিস অ্যাকাউন্টকে প্রয়োজনীয় ক্লাউড বিল্ড সার্ভিস অ্যাকাউন্ট রোল ( roles/cloudbuild.builds.builder ) প্রদান করুন। নিম্নলিখিত gcloud CLI কমান্ডটি চালান:

    gcloud projects add-iam-policy-binding PROJECT_ID \
      --member="serviceAccount:PROJECT_NUMBER-compute@developer.gserviceaccount.com" \
      --role="roles/cloudbuild.builds.builder"
    
  4. আপনার Firebase প্রোজেক্টে Cloud Functions for Firebase চালু করুন:

    1. নিম্নলিখিত Firebase CLI কমান্ডটি চালান:

      firebase init functions
      
    2. নির্দেশিত হলে TypeScript নির্বাচন করুন।

    3. আপনার functions/package.json ফাইলে থাকা firebase-functions ভার্সন ৬.৩.০ বা তার পরবর্তী সংস্করণ আছে কিনা, তা নিশ্চিত করুন। আপনার ভার্সন যাচাই করার পদ্ধতি নিচে দেওয়া হলো:

      npm --prefix functions list firebase-functions
      

ধাপ ২ : আপনার ফাংশনগুলো লিখুন

একটি প্রি-রিকোয়েস্ট ফাংশন ( beforeGenerateContent ) লিখুন একটি পোস্ট-রিকোয়েস্ট ফাংশন ( ) লিখুন afterGenerateContent

একটি প্রি-রিকোয়েস্ট ফাংশন ( beforeGenerateContent ) লিখুন।

beforeGenerateContent ইভেন্ট টাইপের ক্ষেত্রে, যখন Firebase AI Logic প্রক্সি একটি generateContent রিকোয়েস্ট পায়, তখন ফাংশনটি ট্রিগার হয়। রিকোয়েস্টটি Gemini API- তে পাঠানোর আগে ফাংশনটি সেটির উপর রান করে । ফাংশনটি রিকোয়েস্টটি পরিবর্তন করতে পারে অথবা সম্পূর্ণরূপে ব্লক করে দিতে পারে।

আপনার ফাংশনটি লেখার আগে নিম্নলিখিত তথ্যগুলো পর্যালোচনা করে নিন:

উদাহরণ

এখানে একটি প্রি-রিকোয়েস্ট ফাংশনের উদাহরণ দেওয়া হলো যা নিম্নলিখিত কাজগুলো করে:

  • এটি নির্দিষ্ট করে যে, ফাংশনটি শুধুমাত্র তখনই চলবে যখন অনুরোধটি একটি নির্দিষ্ট জেমিনি এপিআই প্রোভাইডারের জন্য হবে।

  • ব্লক করা টপিকগুলোর জন্য প্রম্পটটি পরীক্ষা করে এবং একটি এরর দেখিয়ে অনুরোধটি প্রত্যাখ্যান করে।

  • টেক্সট-জেনারেটিং মডেলগুলির জন্য সর্বাধিক আউটপুট টোকেনের সংখ্যা সীমিত করে।

import { logger } from "firebase-functions";
import {
  beforeGenerateContent,
  HttpsError,
  vertexV1Beta1,
  type VertexV1Beta1GenerateContentRequest,
} from "firebase-functions/v2/ai";

const BLOCKED_TOPICS = ["weapon", "explosive", "self-harm"];
const MAX_OUTPUT_TOKENS = 4000;

export const guardPrompts = beforeGenerateContent((event) => {
  // 1. Optional: If you want the function to only run for a specific Gemini API provider, specify it here.
  if (event.data.api !== vertexV1Beta1) return;
  const request = event.data.request as VertexV1Beta1GenerateContentRequest;

  // 2. Read the prompt: contents[] -> parts[] -> text
  const prompt = (request.contents ?? [])
    .flatMap((c) => c.parts ?? [])
    .map((p) => ("text" in p ? p.text : "") ?? "")
    .join(" ")
    .toLowerCase();

  // 3. Throwing rejects the request. The request is never sent to the Gemini API.
  const blocked = BLOCKED_TOPICS.find((t) => prompt.includes(t));
  if (blocked) {
    logger.warn("Blocked a prompt", { topic: blocked });
    throw new HttpsError("invalid-argument", `We don't return content about ${blocked}.`);
  }

  logger.info("Allowing generation", {
    model: event.data.model,
    authType: event.authType,
    authId: event.authId,
    appId: event.appId,
  });

  // 4. The next step truncates the response, but that will break images.
  if (event.data.model.includes("image")) return;

  // 5. Return the WHOLE request, edited. Returning nothing leaves it untouched.
  return {
    ...request,
    generationConfig: {
      ...request.generationConfig,
      maxOutputTokens: Math.min(
        request.generationConfig?.maxOutputTokens ?? MAX_OUTPUT_TOKENS,
        MAX_OUTPUT_TOKENS,
      ),
    },
  };
});

প্রাক-অনুরোধ ফাংশনগুলির জন্য মূল বিবেচ্য বিষয়গুলি

  • জেমিনি এপিআই প্রোভাইডার নির্দিষ্ট করুন: event.data.request হয় জেমিনি ডেভেলপার এপিআই অথবা এজেন্ট প্ল্যাটফর্ম জেমিনি এপিআই (পূর্বে ভার্টেক্স এআই) এর জন্য হতে পারে। এই বিভিন্ন এপিআই-এর জন্য রিকোয়েস্ট অবজেক্টগুলোর গঠন ভিন্ন ভিন্ন হয়। রিকোয়েস্ট অবজেক্ট নিয়ে নিরাপদে কাজ করার জন্য, আপনাকে অবশ্যই event.data.api চেক করতে হবে (উদাহরণস্বরূপ, যথাক্রমে geminiV1Beta বা vertexV1Beta1 এর সাথে তুলনা করুন)।

  • থ্রো করলে অনুরোধটি ব্লক হয়ে যায়: আপনি যদি একটি HttpsError থ্রো করেন, তাহলে অনুরোধটি প্রত্যাখ্যাত হবে।

  • সম্পূর্ণ অনুরোধটি ফেরত দিন: যদি আপনার ফাংশনটি অনুরোধটি পরিবর্তন করে, তাহলে আপনাকে অবশ্যই সম্পূর্ণ, পরিবর্তিত অনুরোধ অবজেক্টটি ফেরত দিতে হবে। কিছুই ফেরত না দিলে (বা undefined ) অনুরোধটি অপরিবর্তিত থাকে।

  • লেটেন্সি পরীক্ষা করুন: আপনার ফাংশনটি কী কাজ করে তার উপর নির্ভর করে, এটি লেটেন্সি বাড়াতে পারে এবং ব্যবহারকারীর অভিজ্ঞতার উপর প্রভাব ফেলতে পারে।

একটি পোস্ট-রিকোয়েস্ট ফাংশন ( afterGenerateContent ) লিখুন।

afterGenerateContent ইভেন্ট টাইপের ক্ষেত্রে, যখন Firebase AI Logic প্রক্সি একটি generateContent রিকোয়েস্ট থেকে রেসপন্স পায়, তখন ফাংশনটি ট্রিগার হয়। রেসপন্সটি ক্লায়েন্ট অ্যাপে ফেরত পাঠানোর আগেই ফাংশনটি সেই রেসপন্সের উপর রান করে । ফাংশনটি এর ব্যবহার লগ করতে, রেসপন্স পরিবর্তন করতে, অথবা রেসপন্সটিকে সম্পূর্ণরূপে ব্লক করতে পারে।

আপনার ফাংশনটি লেখার আগে নিম্নলিখিত তথ্যগুলো পর্যালোচনা করে নিন:

উদাহরণ

এখানে একটি পোস্ট-রিকোয়েস্ট ফাংশনের উদাহরণ দেওয়া হলো যা টোকেন ব্যবহার এবং সমাপ্তির কারণ লগ করে:

import { logger } from "firebase-functions";
import {
  afterGenerateContent,
  vertexV1Beta1,
  type VertexV1Beta1GenerateContentResponse,
} from "firebase-functions/v2/ai";

export const recordGenerationUsage = afterGenerateContent((event) => {
  // Optional: If you want the function to only run for a specific Gemini API provider, specify it here.
  if (event.data.api !== vertexV1Beta1) return;
  const response = event.data.response as VertexV1Beta1GenerateContentResponse;

  logger.info("Generation finished", {
    model: event.data.model,
    promptTokens: response.usageMetadata?.promptTokenCount,
    totalTokens: response.usageMetadata?.totalTokenCount,
    finishReason: response.candidates?.[0]?.finishReason,
  });

  // To leave the response untouched, return nothing.
  // To modify the response, return a modified response object here.
});

অনুরোধ-পরবর্তী ফাংশনগুলির জন্য মূল বিবেচ্য বিষয়গুলি

  • জেমিনি এপিআই প্রোভাইডার নির্দিষ্ট করুন: event.data.response হয় জেমিনি ডেভেলপার এপিআই অথবা এজেন্ট প্ল্যাটফর্ম জেমিনি এপিআই (পূর্বে ভার্টেক্স এআই) এর জন্য হতে পারে। রিকোয়েস্ট অবজেক্টটি নিরাপদে কাস্ট করতে এবং এর সাথে কাজ করার জন্য, আপনাকে অবশ্যই event.data.api চেক করতে হবে (উদাহরণস্বরূপ, যথাক্রমে geminiV1Beta বা vertexV1Beta1 সাথে তুলনা করুন)।

  • লেটেন্সি পরীক্ষা করুন: আপনার ফাংশনটি কী কাজ করে তার উপর নির্ভর করে, এটি লেটেন্সি বাড়াতে পারে এবং ব্যবহারকারীর অভিজ্ঞতার উপর প্রভাব ফেলতে পারে।

ধাপ ৩ : আপনার ফাংশনগুলো ডিপ্লয় করুন

Firebase-এ আপনার ফাংশনগুলো ডিপ্লয় করলে, তা Firebase AI Logic সার্ভিস এজেন্টকে এই ফাংশনগুলো কল করার অনুমতি দেয় এবং প্রতিটি ফাংশনকে একটি Firebase AI Logic ট্রিগার হিসেবে রেজিস্টার করে।

  1. Firebase CLI ব্যবহার করে আপনার ফাংশনগুলো ডিপ্লয় করুন:

    firebase deploy --only functions
    
  2. ডিপ্লয় করার পরে, আপনার ফাংশনগুলি Firebase-এ ডিপ্লয় হয়েছে কিনা তা নিশ্চিত করুন:

    firebase functions:list
    
  3. আপনার ফাংশনটিতে পুনরাবৃত্তি করার প্রয়োজন হলে:

    আপনার প্রজেক্ট ডিরেক্টরিতে ফাংশনটি আপডেট করুন, এবং তারপর আবার firebase deploy --only functions চালান।

একটি ফাংশন চালানো বন্ধ করুন

এই ফাংশনগুলোর কোনো একটির কার্যক্রম বন্ধ করতে হলে, সেটিকে আমাদের সার্ভার থেকে মুছে ফেলতে হবে এবং Firebase AI Logic ট্রিগার হিসেবে অনিবন্ধিত করতে হবে। আপনি নিম্নলিখিত বিকল্পগুলোর যেকোনো একটি ব্যবহার করে Firebase CLI-এর মাধ্যমে এটি করতে পারেন:

  • বিকল্প ১: ফাংশনটি পরোক্ষভাবে মুছে ফেলুন

    1. আপনার প্রজেক্ট ডিরেক্টরি কোডবেস থেকে ফাংশনটি সরিয়ে ফেলুন।

    2. নিম্নলিখিত Firebase CLI কমান্ডটি চালান:

      firebase deploy --only functions
      
  • বিকল্প ২: ফাংশনটি স্পষ্টভাবে মুছে ফেলুন

    1. আপনার প্রজেক্ট ডিরেক্টরি কোডবেস থেকে ফাংশনটি সরিয়ে ফেলুন।

    2. নিম্নলিখিত Firebase CLI কমান্ডটি চালান:

      firebase functions:delete FUNCTION_NAME
      



ইভেন্ট ডেটা রেফারেন্স

beforeGenerateContent এবং afterGenerateContent উভয়ই একটি AIBlockingEvent অবজেক্ট গ্রহণ করে, যেটিতে অনুরোধ সম্পর্কিত প্রাসঙ্গিক তথ্য এবং মেটাডেটা থাকে।

শীর্ষ-স্তরের অনুরোধ মেটাডেটা ( AIBlockingEvent )

শীর্ষ-স্তরের AIBlockingEvent অবজেক্টটি কলার এবং ট্রিগারিং এনভায়রনমেন্ট সম্পর্কে তথ্য প্রদান করে:

  • event.authType : আহ্বানকারীর প্রমাণীকরণ অবস্থা: "app_user" , "unauthenticated" , অথবা "unknown"
  • event.authId : কলারের ফায়ারবেস অথেনটিকেশন UID, যদি তিনি সাইন ইন করে থাকেন।
  • event.authClaims : কলারের নিজস্ব অথেন্টিকেশন ক্লেইম, যদি থাকে।
  • event.appId : যে ফায়ারবেস অ্যাপ আইডিটি অনুরোধটি করেছে।
  • event.androidPackageName / event.iosBundleId : আহ্বানকারী অ্যাপের প্যাকেজ নাম বা বান্ডেল আইডি (যথাক্রমে অ্যান্ড্রয়েড বা অ্যাপল প্ল্যাটফর্মের জন্য প্রযোজ্য)।
  • event.data : ইভেন্ট পেলোড, যা প্রি-রিকোয়েস্ট এবং পোস্ট-রিকোয়েস্ট ফাংশনগুলোর মধ্যে ভিন্ন হয়:

অনুরোধের পূর্ববর্তী ইভেন্টের ডেটা ( beforeGenerateContent )

beforeGenerateContent ফাংশনের মধ্যে, event.data একটি BeforeGenerateContentData অবজেক্ট দিয়ে পূরণ করা হয়:

  • event.data.api : জেমিনি এপিআই প্রোভাইডার: geminiV1Beta ( জেমিনি ডেভেলপার এপিআই ) অথবা vertexV1Beta1 ( এজেন্ট প্ল্যাটফর্ম জেমিনি এপিআই (পূর্বে ভার্টেক্স এআই) )।
  • event.data.model : সম্পূর্ণ মডেল রিসোর্স পাথ (উদাহরণস্বরূপ, projects/{PROJECT_ID}/locations/global/publishers/google/models/gemini-3.8-flash )।
  • event.data.template : ব্যবহৃত সার্ভার প্রম্পট টেমপ্লেট ( PromptTemplateInfo ) সম্পর্কিত মেটাডেটা, যদি প্রযোজ্য হয়।
  • event.data.request : বহির্গামী অনুরোধের পেলোড। অবজেক্টের ধরন এবং বৈশিষ্ট্যগুলো জেমিনি এপিআই প্রোভাইডারের উপর নির্ভর করে:

অনুরোধ-পরবর্তী ইভেন্টের ডেটা ( afterGenerateContent )

afterGenerateContent ফাংশনের মধ্যে, event.data একটি AfterGenerateContentData অবজেক্ট দিয়ে পূরণ করা হয়। এই অবজেক্টটি BeforeGenerateContentData এক্সটেন্ড করে (যা api , model , template , এবং request প্রদান করে), এবং মডেলের রেসপন্স যোগ করে:

  • event.data.response : মডেলের রেসপন্স পেলোড। অবজেক্টের ধরন এবং প্রোপার্টিগুলো জেমিনি এপিআই প্রোভাইডারের উপর নির্ভর করে:



সীমাবদ্ধতা এবং আচরণ

এই ফাংশনগুলো প্রয়োগ করার সময় নিম্নলিখিত আচরণ ও সীমাবদ্ধতাগুলো মনে রাখবেন:

  • শুধুমাত্র generateContent অনুরোধের মাধ্যমে : এই ফাংশনগুলি শুধুমাত্র Firebase AI Logic- এর মাধ্যমে Gemini API- তে generateContent অনুরোধের দ্বারাই সক্রিয় করা যায়।

    নিম্নলিখিতগুলি এই ফাংশনগুলিকে সক্রিয় করবে না এবং সেই অনুরোধের জন্য ফাংশনগুলি নীরবে এড়িয়ে যাওয়া হবে:

    • generateContentStream এর অনুরোধগুলো এই ফাংশনগুলোকে সক্রিয় করবে না

    • Gemini Live API -তে করা অনুরোধগুলো এই ফাংশনগুলোকে সক্রিয় করবে না

  • ক্লায়েন্ট-সাইড কোডে কোনো পরিবর্তনের প্রয়োজন নেই : এই ফাংশনগুলো চালানোর জন্য generateContent রিকোয়েস্ট ব্যবহার করা নিশ্চিত করা ছাড়া আপনার ক্লায়েন্ট-সাইড কোডবেসে আর কোনো পরিবর্তনের প্রয়োজন নেই।

    এই ফাংশনগুলো আমাদের সার্ভারগুলোতে ডেপ্লয় করা হয় এবং এগুলোকে Firebase AI Logic ট্রিগার হিসেবে রেজিস্টার করা হয়, যাতে Firebase AI Logic প্রক্সি সার্ভার-সাইডে রিকোয়েস্ট ও রেসপন্সগুলো ইন্টারসেপ্ট করতে পারে।

  • প্রজেক্ট-স্তরের পরিধি : আপনি প্রতিটি Firebase প্রজেক্টে সর্বাধিক একটি beforeGenerateContent ফাংশন এবং একটি afterGenerateContent ফাংশন স্থাপন করতে পারবেন।

  • ডিফল্ট অবস্থান : এই ফাংশনগুলি ডিফল্টরূপে us-central1 এ ডেপ্লয় করা হবে ( ফাংশনের অবস্থান সম্পর্কে জানুন)। তবে, আপনি আপনার ফাংশনটি যেখানেই ডেপ্লয় করুন না কেন, এটি global অঞ্চলে একটি Firebase AI Logic ট্রিগার হিসাবে নিবন্ধিত হবে।