تنفيذ نصوص برمجية مخصّصة من جهة الخادم قبل الطلبات وبعدها


يمكنك تشغيل نصوص برمجية مخصّصة من جهة الخادم قبل كل طلب ترسله إلى Gemini API وبعده عبر Firebase AI Logic، وذلك بدون تغيير رمز العميل. يمكنك تنفيذ هذه النصوص البرمجية كدوال على شكل عمليات ردّ يتم نشرها على Cloud Functions for Firebase.

باستخدام هذه الإمكانية، يمكنك تنفيذ إجراءات مثل الإشراف على الطلبات أو وضع حدّ أقصى لاستخدام الرموز المميزة أو تسجيل عمليات الإنشاء لأغراض إحصائية أو إخفاء محتوى الردود.

يتوفّر نوعان من الأحداث:

  • beforeGenerateContent: يتم تنفيذ هذا النوع قبل أن يصل الطلب إلى Gemini API. يمكن للدالة فحص الطلب أو تعديله أو حظره بالكامل من خلال عرض رسالة خطأ.

  • afterGenerateContent: يتم تنفيذها بعد إرسال الرد من Gemini API وقبل إرجاعه إلى تطبيق العميل. ويمكن لهذه الدالة فحص الرد أو تعديله أو حظره بالكامل أو مجرد مراقبته (مثل التسجيل أو التدقيق).

بعد نشر النصوص البرمجية كدوال في Cloud Functions for Firebase، سيتم تسجيلها كـ مشغّلات Firebase AI Logic، ما يعني أنّها ستعمل مع كل طلب generateContent في مشروعك إلى Gemini API من خلال Firebase AI Logic (بما في ذلك الطلبات التي يتم إجراؤها باستخدام نماذج طلبات الخادم).

لا يتم تشغيل هذه الدوال من خلال الطلبات المقدَّمة إلى Gemini API التي لا تتم من خلال Firebase AI Logic.

المتطلبات الأساسية

الخطوة 1: إعداد مشروعك لاستخدام Cloud Functions for Firebase

إذا لم يسبق لك استخدام Cloud Functions for Firebase في مشروع Firebase، عليك إكمال عملية الإعداد التالية.

  1. تأكَّد من أنّ مشروع Firebase الخاص بك يستخدم خطة Blaze المَرِنة بنظام الدفع حسب الاستخدام (مطلوب لاستخدام Cloud Functions for Firebase).

  2. ثبِّت واجهات سطر الأوامر (CLI): gcloud CLI وواجهة سطر الأوامرFirebase

  3. امنح حساب خدمة Compute Engine التلقائي دور حساب خدمة Cloud Build (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 في مشروعك على Firebase:

    1. نفِّذ أمر واجهة سطر الأوامر Firebase التالي:

      firebase init functions
      
    2. عندما يُطلب منك ذلك، اختَر TypeScript.

    3. تأكَّد من أنّ firebase-functions في functions/package.json هو الإصدار 6.3.0 أو إصدار أحدث. إليك كيفية التحقّق من الإصدار:

      npm --prefix functions list firebase-functions
      

الخطوة 2: كتابة الدوال

كتابة دالة ما قبل الطلب (beforeGenerateContent) كتابة دالة ما بعد الطلب (afterGenerateContent)

كتابة دالة ما قبل الطلب (beforeGenerateContent)

باستخدام نوع الحدث beforeGenerateContent، يتم تشغيل الدالة عندما يتلقّى الخادم الوكيل Firebase AI Logic طلب generateContent. يتم تنفيذ الدالة على الطلب قبل إرساله إلى Gemini API. يمكن أن تعدّل الدالة الطلب أو تحظره تمامًا.

يُرجى مراجعة المعلومات التالية قبل كتابة الدالة:

مثال

في ما يلي مثال لدالة ما قبل الطلب التي تنفّذ ما يلي:

  • تحدّد هذه السمة أنّه يجب ألا يتم تنفيذ الدالة إلا عندما يكون الطلب موجّهًا إلى موفّر خدمة محدّد 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,
      ),
    },
  };
});

اعتبارات أساسية لوظائف الطلب المُسبَق

  • تحديد موفّر Gemini API: يمكن أن تكون قيمة event.data.request إما Gemini Developer API أو Agent Platform Gemini API (formerly Vertex AI). تتضمّن عناصر الطلبات الخاصة بهذه الواجهات أشكالاً مختلفة. للتعامل بأمان مع عنصر الطلب، يجب التحقّق من 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.
});

اعتبارات أساسية لوظائف ما بعد الطلب

  • تحديد موفّر Gemini API: يمكن أن تكون قيمة event.data.response إما Gemini Developer API أو Agent Platform Gemini API (formerly Vertex AI). لإجراء عملية تحويل آمنة والتعامل مع عنصر الطلب، يجب التحقّق من event.data.api (على سبيل المثال، مقارنة geminiV1Beta أو vertexV1Beta1 على التوالي).

  • اختبار وقت الاستجابة: استنادًا إلى وظيفة تطبيقك، قد يؤدي ذلك إلى زيادة وقت الاستجابة والتأثير في تجربة المستخدم.

الخطوة 3: نشر الدوال

يؤدي نشر الدوال إلى Firebase إلى منح Firebase AI Logic إذنًا لوكيل الخدمة بتنفيذ هذه الدوال، كما يسجّل كل دالة Firebase AI Logic كمشغّل.

  1. انشر الدوال باستخدام واجهة سطر الأوامر Firebase:

    firebase deploy --only functions
    
  2. بعد النشر، تأكَّد من أنّه تم نشر الدوال إلى Firebase:

    firebase functions:list
    
  3. إذا كنت بحاجة إلى تكرار الدالة:

    عدِّل الدالة في دليل مشروعك، ثم شغِّل firebase deploy --only functions مرة أخرى.

إيقاف تشغيل دالة

لإيقاف إحدى هذه الدوال، يجب حذفها من خوادمنا و إلغاء تسجيلها كـ مشغّل Firebase AI Logic. يمكنك إجراء ذلك باستخدام Firebase CLI مع أحد الخيارَين التاليَين:

  • الخيار 1: حذف الدالة ضمنيًا

    1. أزِل الدالة من قاعدة رموز دليل مشروعك.

    2. نفِّذ أمر واجهة سطر الأوامر Firebase التالي:

      firebase deploy --only functions
      
  • الخيار 2: حذف الدالة بشكل صريح

    1. أزِل الدالة من قاعدة رموز دليل مشروعك.

    2. نفِّذ أمر واجهة سطر الأوامر Firebase التالي:

      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: اسم الحزمة أو معرّف الحزمة للتطبيق الذي يتم استدعاؤه (ينطبق على منصتَي Android أو Apple، على التوالي).
  • event.data: حمولة الحدث التي تختلف بين وظائف ما قبل الطلب وما بعد الطلب:

بيانات أحداث ما قبل الطلب (beforeGenerateContent)

في دالة beforeGenerateContent، يتم ملء event.data بكائن BeforeGenerateContentData:

  • event.data.api: مقدّم خدمة Gemini API: geminiV1Beta (Gemini Developer API) أو vertexV1Beta1 (Agent Platform Gemini API (formerly Vertex AI)).
  • event.data.model: مسار مورد النموذج الكامل (على سبيل المثال، projects/{PROJECT_ID}/locations/global/publishers/google/models/gemini-3.8-flash)
  • event.data.template: بيانات وصفية حول نموذج طلب الخادم المستخدَم (PromptTemplateInfo)، إذا كان ذلك منطبقًا
  • event.data.request: حمولة الطلب الصادر. يعتمد نوع العنصر وخصائصه على مقدّم خدمة Gemini API:

بيانات أحداث ما بعد الطلب (afterGenerateContent)

في الدالة afterGenerateContent، تتم تعبئة event.data بكائن AfterGenerateContentData. يمتد هذا العنصر إلى BeforeGenerateContentData (ويوفّر api وmodel وtemplate وrequest)، ويضيف ردّ النموذج:



القيود والسلوكيات

عند تنفيذ هذه الدوال، يُرجى مراعاة السلوكيات والقيود التالية:

  • طلبات generateContent فقط: لا يمكن تشغيل هذه الدوال إلا من خلال طلبات generateContent إلى Gemini API عبر Firebase AI Logic.

    لن تؤدي الحالات التالية إلى تشغيل هذه الوظائف، وسيتم تجاهلها بدون إشعار في هذا الطلب:

    • لن تؤدي الطلبات إلى generateContentStream إلى تشغيل هذه الدوال .

    • لن تؤدي الطلبات إلى Gemini Live API إلى تشغيل هذه الدوال .

  • عدم الحاجة إلى إجراء أي تغييرات على الرموز البرمجية من جهة العميل: باستثناء التأكّد من استخدام طلبات generateContent عند الرغبة في تنفيذ هذه الدوال، لن تحتاج إلى إجراء أي تغييرات على قاعدة الرموز البرمجية من جهة العميل.

    يتم نشر هذه الدوال على خوادمنا، ويتم تسجيلها Firebase AI Logic كمشغّلات كي يتمكّن وكيل Firebase AI Logic من اعتراض الطلبات والردود من جهة الخادم.

  • النطاق على مستوى مشروع Firebase: يمكنك نشر وظيفة beforeGenerateContent واحدة ووظيفة afterGenerateContent واحدة على الأكثر لكل مشروع في Firebase.

  • المواقع الجغرافية التلقائية: سيتم نشر هذه الدوال في us-central1 تلقائيًا (تعرَّف على المواقع الجغرافية للدوال). ومع ذلك، سيتم تسجيل الدالة كـ مشغّل Firebase AI Logic في منطقة global بغض النظر عن المكان الذي تنشر فيه الدالة.