اجرای اسکریپت‌های سمت سرور سفارشی قبل و بعد از درخواست‌ها


شما می‌توانید اسکریپت‌های سمت سرور سفارشی خود را قبل و بعد از هر درخواستی که برنامه شما از طریق Firebase AI Logic به API Gemini ارسال می‌کند، اجرا کنید - بدون اینکه کد کلاینت خود را تغییر دهید . شما این اسکریپت‌ها را به عنوان توابع به سبک فراخوانی پیاده‌سازی می‌کنید که در Cloud Functions for Firebase مستقر شده‌اند.

با این قابلیت، می‌توانید کارهایی مانند تعدیل اعلان‌ها، استفاده از توکن cap، ایجاد لاگ برای تجزیه و تحلیل یا ویرایش محتوای پاسخ را انجام دهید.

دو نوع رویداد در دسترس است:

  • beforeGenerateContent : قبل از اینکه درخواستی به API Gemini برسد، اجرا می‌شود. این تابع می‌تواند درخواست را بررسی یا اصلاح کند، یا با ارسال خطا، درخواست را به طور کامل مسدود کند.

  • afterGenerateContent : پس از ارسال پاسخ از API Gemini و قبل از بازگشت آن به برنامه کلاینت اجرا می‌شود. این تابع می‌تواند پاسخ را بررسی یا تغییر دهد، پاسخ را به طور کامل مسدود کند یا فقط آن را مشاهده کند (مانند ثبت وقایع یا حسابرسی).

زمانی که اسکریپت‌های شما به عنوان توابع در Cloud Functions for Firebase مستقر شدند، به عنوان triggerهای Firebase AI Logic ثبت می‌شوند، به این معنی که برای هر درخواست generateContent در پروژه شما به Gemini API از طریق Firebase AI Logic (از جمله درخواست‌های ارسالی با الگوهای اعلان سرور ) اجرا می‌شوند.

این توابع توسط درخواست‌هایی که به API Gemini ارسال می‌شوند و از طریق Firebase AI Logic ارسال نمی‌شوند، فعال نمی‌شوند .

پیش‌نیازها

مرحله 1 : پروژه خود را برای Cloud Functions for Firebase تنظیم کنید

اگر تا به حال Cloud Functions for Firebase در پروژه فایربیس خود استفاده نکرده‌اید، تنظیمات زیر را انجام دهید.

  1. مطمئن شوید که پروژه Firebase شما در طرح قیمت‌گذاری Blaze با پرداخت به ازای استفاده قرار دارد (برای استفاده Cloud Functions for Firebase لازم است).

  2. نصب رابط‌های خط فرمان (CLI): gcloud CLI و Firebase CLI

  3. به حساب سرویس محاسباتی پیش‌فرض، نقش Cloud Build Service Account ( 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. Cloud Functions for Firebase در پروژه فایربیس خود مقداردهی اولیه کنید:

    1. دستور Firebase CLI زیر را اجرا کنید:

      firebase init functions
      
    2. وقتی از شما خواسته شد، TypeScript را انتخاب کنید.

    3. مطمئن شوید که firebase-functions در functions/package.json شما نسخه ۶.۳.۰ یا بالاتر باشد . برای بررسی نسخه خود، مراحل زیر را دنبال کنید:

      npm --prefix functions list firebase-functions
      

مرحله ۲ : نوشتن توابع

یک تابع پیش از درخواست ( beforeGenerateContent ) بنویسید یک تابع پس از درخواست ( ) بنویسید afterGenerateContent

یک تابع پیش درخواست ( beforeGenerateContent ) بنویسید

با نوع رویداد beforeGenerateContent ، این تابع زمانی فعال می‌شود که پروکسی Firebase AI Logic یک درخواست generateContent دریافت کند. این تابع قبل از ارسال درخواست به Gemini API، در مقابل آن اجرا می‌شود . این تابع می‌تواند درخواست را تغییر دهد یا درخواست را به طور کامل مسدود کند.

قبل از نوشتن تابع، حتماً اطلاعات زیر را بررسی کنید:

مثال

در اینجا یک مثال از تابع پیش‌درخواست را مشاهده می‌کنید که کارهای زیر را انجام می‌دهد:

  • مشخص می‌کند که تابع فقط زمانی اجرا شود که درخواست برای یک ارائه‌دهنده API خاص Gemini باشد.

  • اعلان موضوعات مسدود شده را بررسی می‌کند و با نمایش خطا، درخواست را رد می‌کند.

  • حداکثر توکن‌های خروجی را برای مدل‌های تولید متن محدود می‌کند.

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

ملاحظات کلیدی برای عملکردهای پیش از درخواست

  • ارائه‌دهنده‌ی API مربوط به Gemini را مشخص کنید: event.data.request می‌تواند برای Gemini Developer API یا Agent Platform Gemini API (که قبلاً Vertex AI نام داشت) باشد. اشیاء درخواست برای این APIهای مختلف، شکل‌های متفاوتی دارند. برای کار ایمن با شیء درخواست، باید 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.
});

ملاحظات کلیدی برای عملکردهای پس از درخواست

  • ارائه‌دهنده‌ی API مربوط به Gemini را مشخص کنید: event.data.response می‌تواند برای Gemini Developer API یا Agent Platform Gemini API (که قبلاً Vertex AI نام داشت) باشد. برای تبدیل ایمن و کار با شیء درخواست، باید event.data.api بررسی کنید (برای مثال، به ترتیب با geminiV1Beta یا vertexV1Beta1 مقایسه کنید).

  • بررسی تأخیر: بسته به کاری که تابع شما انجام می‌دهد، می‌تواند تأخیر ایجاد کند و بر تجربه کاربری تأثیر بگذارد.

مرحله ۳ : توابع خود را مستقر کنید

استقرار توابع شما در Firebase به عامل سرویس Firebase AI Logic اجازه می‌دهد تا این توابع را فراخوانی کند و هر تابع را به عنوان یک trigger Firebase AI Logic ثبت می‌کند.

  1. توابع خود را با استفاده از Firebase CLI مستقر کنید:

    firebase deploy --only functions
    
  2. پس از استقرار، تأیید کنید که توابع شما در Firebase مستقر شده‌اند:

    firebase functions:list
    
  3. اگر نیاز به تکرار روی تابع خود دارید:

    تابع را در دایرکتوری پروژه خود به‌روزرسانی کنید، و سپس firebase deploy --only functions دوباره اجرا کنید.

متوقف کردن اجرای یک تابع

برای متوقف کردن اجرای یکی از این توابع، باید آن را از سرورهای ما حذف کرده و به عنوان یک تریگر Firebase AI Logic ثبت نشده (unregistered) کنید. می‌توانید این کار را با استفاده از 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 : شناسه کاربری احراز هویت Firebase تماس‌گیرنده، در صورت ورود به سیستم.
  • event.authClaims : ادعاهای احراز هویت سفارشیِ فراخوانی‌کننده، در صورت وجود.
  • event.appId : شناسه برنامه Firebase که درخواست را ارسال کرده است.
  • event.androidPackageName / event.iosBundleId : نام بسته یا شناسه بسته برنامه فراخوانی (به ترتیب برای پلتفرم‌های اندروید یا اپل)
  • event.data : بار داده رویداد، که بین توابع پیش از درخواست و پس از درخواست متفاوت است:

پیش‌درخواست داده‌های رویداد ( beforeGenerateContent )

در یک تابع beforeGenerateContent ، event.data با یک شیء BeforeGenerateContentData پر می‌شود:

  • event.data.api : ارائه‌دهنده‌ی API مربوط به Gemini : geminiV1Beta ( رابط برنامه‌نویسی Gemini ) یا vertexV1Beta1 ( رابط برنامه‌نویسی پلتفرم Gemini (که قبلاً Vertex AI نام داشت) ).
  • event.data.model : مسیر کامل منبع مدل (برای مثال، projects/{PROJECT_ID}/locations/global/publishers/google/models/gemini-3.8-flash ).
  • event.data.template : در صورت وجود، متادیتای مربوط به الگوی اعلان سرور مورد استفاده ( PromptTemplateInfo ).
  • event.data.request : بار درخواست خروجی. نوع شیء و ویژگی‌ها به ارائه‌دهنده‌ی API Gemini بستگی دارد:

داده‌های رویداد پس از درخواست ( afterGenerateContent )

در یک تابع afterGenerateContent ، event.data با یک شیء AfterGenerateContentData پر می‌شود. این شیء BeforeGenerateContentData ارث‌بری می‌کند (شامل api ، model ، template و request ) و پاسخ مدل را اضافه می‌کند:

  • event.data.response : بار داده‌ی پاسخ مدل. نوع شیء و ویژگی‌ها به ارائه‌دهنده‌ی API Gemini بستگی دارد:



محدودیت‌ها و رفتارها

هنگام پیاده‌سازی این توابع، رفتارها و محدودیت‌های زیر را در نظر داشته باشید:

  • فقط درخواست‌های generateContent : این توابع فقط می‌توانند توسط درخواست‌های generateContent به API Gemini از طریق Firebase AI Logic فعال شوند.

    دستور زیر این توابع را فعال نمی‌کند و توابع برای آن درخواست به صورت بی‌صدا نادیده گرفته می‌شوند:

    • درخواست‌های generateContentStream این توابع را فعال نمی‌کنند .

    • درخواست‌ها به Gemini Live API این توابع را فعال نمی‌کنند .

  • بدون تغییر کد سمت کلاینت : به غیر از اطمینان از اینکه هنگام اجرای این توابع از درخواست‌های generateContent استفاده می‌کنید، هیچ تغییری در کدبیس سمت کلاینت شما لازم نیست.

    این توابع در سرورهای ما مستقر می‌شوند و به عنوان محرک‌های Firebase AI Logic ثبت می‌شوند تا پروکسی Firebase AI Logic بتواند درخواست‌ها و پاسخ‌ها را در سمت سرور رهگیری کند.

  • محدوده سطح پروژه : شما می‌توانید حداکثر یک تابع beforeGenerateContent و یک تابع afterGenerateContent را در هر پروژه Firebase مستقر کنید.

  • مکان‌های پیش‌فرض : این توابع به طور پیش‌فرض در us-central1 مستقر می‌شوند (درباره مکان‌های توابع اطلاعات کسب کنید). با این حال، این تابع صرف نظر از مکانی که تابع خود را در آن مستقر می‌کنید، به عنوان یک تریگر Firebase AI Logic در منطقه global ثبت خواهد شد.