استقرار جریان ها با استفاده از توابع ابری برای Firebase

Genkit شامل افزونه‌ای است که به شما کمک می‌کند جریان‌های خود را در Cloud Functions برای Firebase مستقر کنید. جریان ها، پس از استقرار، به عنوان نقاط پایانی HTTPS در دسترس هستند و به عنوان توابع قابل فراخوانی با استفاده از کتابخانه های سرویس گیرنده Cloud Functions قابل دسترسی هستند.

قبل از شروع

  • Firebase CLI را نصب کنید.
  • شما باید با مفهوم جنکیت از جریان ها و نحوه نوشتن آنها آشنا باشید. دستورالعمل‌های موجود در این صفحه فرض می‌کنند که شما قبلاً برخی از جریان‌ها را تعریف کرده‌اید که می‌خواهید آن‌ها را اجرا کنید.
  • اگر قبلاً از Cloud Functions برای Firebase استفاده کرده باشید، مفید است، اما ضروری نیست.

1. یک پروژه Firebase راه اندازی کنید

اگر قبلاً پروژه Firebase با توابع ابری TypeScript راه‌اندازی نکرده‌اید، این مراحل را دنبال کنید:

  1. با استفاده از کنسول Firebase یک پروژه Firebase جدید ایجاد کنید یا یک پروژه موجود را انتخاب کنید.

  2. پروژه را به پلان Blaze ارتقا دهید، که برای استقرار توابع ابری لازم است.

  3. با Firebase CLI وارد شوید:

    firebase login
    firebase login --reauth # alternative, if necessary
    firebase login --no-localhost # if running in a remote shell
  4. یک فهرست پروژه جدید ایجاد کنید:

    export PROJECT_ROOT=~/tmp/genkit-firebase-project1
    mkdir -p $PROJECT_ROOT
  5. یک پروژه Firebase را در فهرست راه اندازی کنید:

    cd $PROJECT_ROOT
    firebase init genkit

    بقیه این صفحه فرض می کند که شما انتخاب کرده اید که توابع خود را در TypeScript بنویسید، اما اگر از جاوا اسکریپت استفاده می کنید می توانید جریان های Genkit خود را نیز مستقر کنید.

2. تعاریف جریان را به روز کنید

پس از راه‌اندازی یک پروژه Firebase با توابع Cloud، می‌توانید تعاریف جریان را در فهرست functions/src پروژه کپی یا بنویسید و آنها را در index.ts صادر کنید.

برای اینکه جریان های شما قابل اجرا باشند، باید تغییرات کوچکی در نحوه تعریف آنها ایجاد کنید. منطق اصلی یکسان خواهد ماند، اما شما اطلاعات بیشتری را اضافه خواهید کرد تا پس از استقرار، آنها را به راحتی قابل استقرار و ایمن تر کنید.

فرض کنید جریان زیر را دارید:

const generatePoemFlow = ai.defineFlow(
  {
    name: "generatePoem",
    inputSchema: z.string(),
    outputSchema: z.string(),
  },
  async (subject: string) => {
    const { text } = await ai.generate(`Compose a poem about ${subject}.`);
    return text;
  }
);

بخش‌های زیر تغییراتی را که باید قبل از اجرای آن انجام دهید، توضیح می‌دهد.

جریان ها را با onFlow تعریف کنید

به جای اینکه جریان خود را با Genkit.defineFlow() تعریف کنید، از تابع onFlow() پلاگین Firebase استفاده کنید. با استفاده از این تابع، منطق جریان شما را در یک کنترل کننده درخواست توابع ابری، مشابه onCall ، می پیچد.

import { onFlow } from "@genkit-ai/firebase/functions";

export const generatePoem = onFlow(
  ai,
  {
    // ...
  },
  async (subject: string) => {
    // ...
  }
);

توجه داشته باشید که onFlow یک متد از Genkit نیست، بلکه تابعی است که یک نمونه Genkit را به عنوان اولین پارامتر خود می گیرد. در غیر این صورت، نحو شبیه به defineFlow است.

خط مشی مجوز را تعریف کنید

همه جریان‌های مستقر شده، چه در Firebase مستقر شده باشند یا نه، باید دارای یک خط‌مشی مجوز باشند. بدون آن، جریان های بالقوه گران هوش مصنوعی مولد شما برای هر کسی قابل استناد خواهد بود. برای تعریف یک خط مشی مجوز، از پارامتر authPolicy در تعریف جریان استفاده کنید:

import { firebaseAuth } from "@genkit-ai/firebase/auth";

export const generatePoem = onFlow(
  ai,
  {
    name: "generatePoem",
    // ...
    authPolicy: firebaseAuth((user, input) => {
      if (!user.email_verified) {
        throw new Error("Verified email required to run flow");
      }
    }),
  },
  async (subject: string) => {
    // ...
  }
);

این خط‌مشی از راهنمای firebaseAuth() استفاده می‌کند تا فقط به کاربران ثبت‌نام‌شده برنامه شما با آدرس‌های ایمیل تأییدشده اجازه دسترسی بدهد. در سمت مشتری، باید سرصفحه Authorization: Bearer را روی یک نشانه Firebase ID تنظیم کنید که خط‌مشی شما را برآورده می‌کند. SDKهای سرویس گیرنده Cloud Functions متدهای تابع قابل فراخوانی را ارائه می دهند که این را خودکار می کند. به عنوان مثال، بخش را امتحان کنید .

اعتبارنامه های API را برای جریان های مستقر در دسترس قرار دهید

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

برای این مثال، بسته به ارائه دهنده مدلی که انتخاب کرده اید، یکی از موارد زیر را انجام دهید:

جمینی (گوگل هوش مصنوعی)

  1. مطمئن شوید که Google AI در منطقه شما در دسترس است.

  2. با استفاده از Google AI Studio یک کلید API برای Gemini API ایجاد کنید .

  3. کلید API خود را در Cloud Secret Manager ذخیره کنید:

    firebase functions:secrets:set GOOGLE_GENAI_API_KEY

    این مرحله برای جلوگیری از نشت تصادفی کلید API شما که امکان دسترسی به یک سرویس بالقوه اندازه‌گیری شده را می‌دهد، مهم است.

    برای اطلاعات بیشتر در مورد مدیریت اسرار، به ذخیره و دسترسی به اطلاعات پیکربندی حساس مراجعه کنید.

  4. src/index.ts را ویرایش کنید و موارد زیر را بعد از واردات موجود اضافه کنید:

    import {defineSecret} from "firebase-functions/params";
    const googleAIapiKey = defineSecret("GOOGLE_GENAI_API_KEY");
    

    سپس، در تعریف جریان، اعلام کنید که تابع ابری نیاز به دسترسی به این مقدار مخفی دارد:

    export const generatePoem = onFlow(
      {
        name: "generatePoem",
        // ...
        httpsOptions: {
          secrets: [googleAIapiKey],  // Add this line.
        },
      },
      async (subject) => {
        // ...
      }
    );
    

اکنون، هنگامی که این تابع را اجرا می کنید، کلید API شما در Cloud Secret Manager ذخیره می شود و از محیط Cloud Functions در دسترس است.

Gemini (Vertex AI)

  1. در کنسول Cloud، Vertex AI API را برای پروژه Firebase خود فعال کنید .

  2. در صفحه IAM ، اطمینان حاصل کنید که به حساب پیش‌فرض خدمات محاسباتی نقش Vertex AI User اعطا شده است.

تنها رازی که باید برای این آموزش راه اندازی کنید، مربوط به ارائه دهنده مدل است، اما به طور کلی، باید برای هر سرویسی که جریان شما استفاده می کند، کاری مشابه انجام دهید.

یک خط مشی CORS تنظیم کنید

اگر از یک برنامه وب به جریان خود دسترسی دارید (که در بخش Try the Deployed flow انجام می دهید)، در پارامتر httpsOptions ، یک خط مشی CORS تنظیم کنید:

export const generatePoem = onFlow(
  ai,
  {
    name: "generatePoem",
    // ...
    httpsOptions: {
      cors: '*',
    },
  },
  async (subject: string) => {
    // ...
  }
);

احتمالاً سیاست محدودتری برای برنامه های تولیدی می خواهید، اما این کار برای این آموزش انجام می شود.

مثال کامل

پس از انجام تمام تغییرات توضیح داده شده در بالا، جریان قابل استقرار شما چیزی شبیه به مثال زیر خواهد بود:

const googleAIapiKey = defineSecret("GOOGLE_GENAI_API_KEY");

export const generatePoem = onFlow(
  ai,
  {
    name: "generatePoem",
    inputSchema: z.string(),
    outputSchema: z.string(),
    authPolicy: firebaseAuth((user, input) => {
      if (!user.email_verified) {
        throw new Error("Verified email required to run flow");
      }
    }),
    httpsOptions: {
      secrets: [googleAIapiKey],
      cors: '*',
    },
  },
  async (subject: string) => {
    const { text } = await ai.generate(`Compose a poem about ${subject}.`);
    return text;
  }
);

3. جریان ها را به Firebase مستقر کنید

پس از اینکه جریان‌ها را با استفاده از onFlow تعریف کردید، می‌توانید آنها را مانند سایر توابع Cloud مستقر کنید:

cd $PROJECT_ROOT
firebase deploy --only functions

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

اختیاری: جریان مستقر را امتحان کنید

برای امتحان نقطه پایانی جریان خود، می‌توانید نمونه حداقل برنامه وب زیر را اجرا کنید:

  1. در بخش تنظیمات پروژه کنسول Firebase، یک برنامه وب جدید اضافه کنید و گزینه تنظیم میزبانی را انتخاب کنید.

  2. در قسمت Authentication کنسول Firebase، ارائه دهنده Google را فعال کنید که در این مثال از آن استفاده خواهید کرد.

  3. در فهرست پروژه خود، میزبانی Firebase را راه‌اندازی کنید، جایی که برنامه نمونه را در آنجا مستقر خواهید کرد:

    cd $PROJECT_ROOT
    firebase init hosting

    پیش فرض ها را برای همه درخواست ها بپذیرید.

  4. public/index.html با عبارت زیر جایگزین کنید:

    <!DOCTYPE html>
    <html>
      <head>
        <title>Genkit demo</title>
      </head>
      <body>
        <div id="signin" hidden>
          <button id="signinBtn">Sign in with Google</button>
        </div>
        <div id="callGenkit" hidden>
          Subject: <input type="text" id="subject" />
          <button id="generatePoem">Compose a poem on this subject</button>
          <p id="generatedPoem"></p>
        </div>
        <script type="module">
          import { initializeApp } from "https://www.gstatic.com/firebasejs/11.0.1/firebase-app.js";
          import {
            getAuth,
            onAuthStateChanged,
            GoogleAuthProvider,
            signInWithPopup,
          } from "https://www.gstatic.com/firebasejs/11.0.1/firebase-auth.js";
          import {
            getFunctions,
            httpsCallable,
          } from "https://www.gstatic.com/firebasejs/11.0.1/firebase-functions.js";
    
          const firebaseConfig = await fetch("/__/firebase/init.json");
          initializeApp(await firebaseConfig.json());
    
          async function generatePoem() {
            const poemFlow = httpsCallable(getFunctions(), "generatePoem");
            const subject = document.querySelector("#subject").value;
            const response = await poemFlow(subject);
            document.querySelector("#generatedPoem").innerText = response.data;
          }
    
          function signIn() {
            signInWithPopup(getAuth(), new GoogleAuthProvider());
          }
    
          document.querySelector("#signinBtn").addEventListener("click", signIn);
          document
            .querySelector("#generatePoem")
            .addEventListener("click", generatePoem);
    
          const signinEl = document.querySelector("#signin");
          const genkitEl = document.querySelector("#callGenkit");
    
          onAuthStateChanged(getAuth(), (user) => {
            if (!user) {
              signinEl.hidden = false;
              genkitEl.hidden = true;
            } else {
              signinEl.hidden = true;
              genkitEl.hidden = false;
            }
          });
        </script>
      </body>
    </html>
    
  5. استقرار برنامه وب و عملکرد ابری:

    cd $PROJECT_ROOT
    firebase deploy

با مراجعه به URL چاپ شده توسط دستور deploy برنامه وب را باز کنید. این برنامه از شما می‌خواهد که با یک حساب Google وارد شوید، پس از آن می‌توانید درخواست‌های نقطه پایانی را آغاز کنید.

اختیاری: جریان‌ها را در رابط کاربری توسعه‌دهنده اجرا کنید

می‌توانید جریان‌های تعریف‌شده با استفاده از onFlow را در رابط کاربری توسعه‌دهنده اجرا کنید، دقیقاً به همان روشی که جریان‌های تعریف‌شده با استفاده از defineFlow را اجرا می‌کنید، بنابراین نیازی به جابجایی بین این دو بین استقرار و توسعه نیست.

cd $PROJECT_ROOT/functions
npx genkit start -- npx tsx --watch src/index.ts

یا

cd $PROJECT_ROOT/functions
npm run genkit:start

اکنون می توانید برای دسترسی به URL چاپ شده توسط دستور genkit start بروید.

اختیاری: در حال توسعه با استفاده از Firebase Local Emulator Suite

Firebase مجموعه ای از شبیه سازها را برای توسعه محلی ارائه می دهد که می توانید با Genkit از آنها استفاده کنید.

برای استفاده از Genkit Dev UI با Firebase Emulator Suite، شبیه سازهای Firebase را به این صورت شروع کنید:

npx genkit start -- firebase emulators:start --inspect-functions

این کد شما را در شبیه ساز اجرا می کند و چارچوب Genkit را در حالت توسعه اجرا می کند، که API بازتاب Genkit (اما نه Dev UI) را راه اندازی و در معرض نمایش قرار می دهد.

برای مشاهده ردپای Firestore در Dev UI می توانید به برگه Inspect بروید و سوئیچ "Dev/Prod" را تغییر دهید. وقتی روی "prod" تغییر دهید، ردپایی از firestore بارگیری می شود.