{"id":7699,"date":"2024-05-29T13:56:05","date_gmt":"2024-05-29T04:56:05","guid":{"rendered":"https:\/\/www.lancard.com\/blog\/?p=7699"},"modified":"2025-03-12T11:22:15","modified_gmt":"2025-03-12T02:22:15","slug":"firebase-genkit","status":"publish","type":"post","link":"https:\/\/www.lancard.com\/blog\/2024\/05\/29\/firebase-genkit\/","title":{"rendered":"Firebase Genkit\u3092\u8a66\u3057\u3066\u307f\u305f"},"content":{"rendered":"<p>Firebase Genkit \u306f\u3001\u672c\u756a\u74b0\u5883\u306b\u5bfe\u5fdc\u3057\u305f AI \u642d\u8f09\u30a2\u30d7\u30ea\u306e\u69cb\u7bc9\u3001\u30c7\u30d7\u30ed\u30a4\u3001\u30e2\u30cb\u30bf\u30ea\u30f3\u30b0\u306b\u5f79\u7acb\u3064\u30aa\u30fc\u30d7\u30f3\u30bd\u30fc\u30b9 \u30d5\u30ec\u30fc\u30e0\u30ef\u30fc\u30af\u3067\u3059\u3002<\/p>\n<p>\u4eca\u56de\u3001\u4ee5\u4e0b\u3092\u8a66\u3057\u3066\u307f\u307e\u3059\u3002<\/p>\n<ul>\n<li>\u30d6\u30e9\u30a6\u30b6\u304b\u3089Firebase Function\u3092\u547c\u3073\u51fa\u3057\u5b9f\u884c<\/li>\n<li>\n  <a href=\"https:\/\/firebase.google.com\/docs\/emulator-suite?hl=ja\">Firebase Local Emulator Suite<\/a>\u3092\u4f7f\u3063\u3066\u30ed\u30fc\u30ab\u30eb\u3067\u958b\u767a\n<\/li>\n<li>\n  Cloud Firestore vector store\u3092\u4f7f\u3063\u3066RAG\uff08Retrieval Augmented Generation\uff09\u306e\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u4f5c\u6210\u3068\u691c\u7d22\u3092\u884c\u3046\n<\/li>\n<li>\n  \u30e2\u30c7\u30eb\u306bGoogle AI\u306eGemini Pro\u3068OpenAI\u306eGPT-4o\u3092\u4f7f\u3046\n<\/li>\n<\/ul>\n<p><!--more--><\/p>\n<h2>\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7<\/h2>\n<p><a href=\"https:\/\/github.com\/firebase\/genkit\/blob\/main\/docs\/firebase.md\">\u3053\u3053<\/a>\u3092\u53c2\u8003\u306b\u3057\u3066\u3044\u307e\u3059\u3002<br \/>\nNode.js\u306e\u30d0\u30fc\u30b8\u30e7\u30f320\u4ee5\u964d\u304c\u5fc5\u8981\u3067\u3059\u3002<br \/>\nGoogle AI\u306eGemini\u3092\u4f7f\u3046\u305f\u3081\u3001<a href=\"https:\/\/console.cloud.google.com\/apis\/library\/generativelanguage.googleapis.com?hl=ja\">Generative Language API<\/a>\u3092\u6709\u52b9\u306b\u3057\u3001API\u30ad\u30fc\u3092\u4f5c\u6210\u3057\u3066\u304a\u304d\u307e\u3059\u3002<\/p>\n<p>\u7a7a\u306e\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u3092\u4f5c\u6210\u3057\u3001\u305d\u3053\u3067\u4ee5\u4e0b\u306e\u30b3\u30de\u30f3\u30c9\u3092\u5b9f\u884c\u3057\u3001\u3044\u304f\u3064\u304b\u306e\u8cea\u554f\u306b\u7b54\u3048\u308b\u3068Firebase\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u304c\u4f5c\u6210\u3055\u308c\u307e\u3059\u3002<\/p>\n<pre><code class=\"sh\">firebase init genkit\n<\/code><\/pre>\n<p>\u8cea\u554f\u306e\u4e2d\u3067\u30b5\u30f3\u30d7\u30eb\u30d5\u30ed\u30fc\u3092\u751f\u6210\u3059\u308b\u304b\u805e\u304b\u308c\u307e\u3059\u306e\u3067\u3001\u300cY\u300d\u3092\u9078\u629e\u3057\u307e\u3059\u3002<\/p>\n<p>Gemini API\u30ad\u30fc\u3092\u74b0\u5883\u5909\u6570\u306b\u30bb\u30c3\u30c8\u3057\u307e\u3059\u3002<\/p>\n<pre><code class=\"sh\">export GOOGLE_GENAI_API_KEY=*********\n<\/code><\/pre>\n<p>functions\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u3067<code>npm run build<\/code>\u3067\u30d3\u30eb\u30c9\u3057\u305f\u5f8c\u3001\u4ee5\u4e0b\u3092\u5b9f\u884c\u3057\u30a8\u30df\u30e5\u30ec\u30fc\u30bf\u3092\u8d77\u52d5\u3057\u307e\u3059\u3002<\/p>\n<pre><code class=\"sh\">GENKIT_ENV=dev firebase emulators:start --inspect-functions\n<\/code><\/pre>\n<p>\u3055\u3089\u306b\u4ee5\u4e0b\u3092\u5b9f\u884c\u3057Genkit Dev UI\u3092\u8d77\u52d5\u3057\u307e\u3059\u3002<\/p>\n<pre><code class=\"sh\">genkit start --attach http:\/\/localhost:3100 --port 4001\n<\/code><\/pre>\n<p>\u30d6\u30e9\u30a6\u30b6\u3067http:\/\/localhost:4001\/ \u306b\u30a2\u30af\u30bb\u30b9\u3059\u308b\u3068\u3001\u30b5\u30f3\u30d7\u30eb\u30d5\u30ed\u30fc\u306e<code>menuSuggestionFlow<\/code>\u304c\u3042\u308a\u307e\u3059\u3002\u8a66\u3057\u306b\u3001Auth JSON\u306b<code>{\"uid\": 0,\"email_verified\": true}<\/code>\u3092\u5165\u529b\u3057\uff08\u30b5\u30f3\u30d7\u30eb\u30b3\u30fc\u30c9\u3067\u30e1\u30fc\u30eb\u78ba\u8a8d\u6e08\u30e6\u30fc\u30b6\u306e\u307f\u3068\u306a\u3063\u3066\u3044\u308b\uff09\u3001input JSON\u306b\u300c\u725b\u4e3c\u300d\u3068\u5165\u308c\u3066\u307f\u307e\u3057\u305f\u3002<br \/>\n\u7d50\u679c\u3001\u4ee5\u4e0b\u306e\u3088\u3046\u306a \u6c41\u3060\u304f\u7279\u76db\u725b\u4e3c\u3092\u63d0\u6848\u3055\u308c\u307e\u3057\u305f\u3002<\/p>\n<pre><code class=\"sh\">**\"Gyu-don Grande\"**\n\nA super-sized portion of traditional gyudon, featuring:\n\n* Double the amount of tender and juicy beef\n* Extra fluffy rice with a hint of soy sauce and mirin glaze\n* Ample servings of savory onions\n* Topped with a generous drizzle of umami-rich sauce\n* Served in a large bowl taller than a skyscraper\n\nPairs well with:\n\n* Miso soup\n* Cold soba noodles\n* Pickled side dishes\n<\/code><\/pre>\n<h2>\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u4f5c\u6210<\/h2>\n<p>Cloud Firestore vector store\u3092\u4f7f\u3063\u305f\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u4f5c\u6210\u3057\u307e\u3059\u3002<br \/>\n<a href=\"https:\/\/github.com\/firebase\/genkit\/blob\/main\/docs\/plugins\/firebase.md\">\u3053\u3053<\/a>\u3092\u53c2\u8003\u306b\u3057\u3066\u3044\u307e\u3059\u3002<\/p>\n<p>\u30a8\u30df\u30e5\u30ec\u30fc\u30bf\u3067Firestore\u3092\u4f7f\u3046\u306e\u3067\u3001<code>firebase init emulators<\/code>\u3092\u5b9f\u884c\u3057\u3001<code>Firestore Emulator<\/code>\u3092\u4f7f\u3048\u308b\u3088\u3046\u306b\u8a2d\u5b9a\u3057\u307e\u3059\u3002\u3064\u3044\u3067\u306b\u5f8c\u3067\u8a8d\u8a3c\u3068\u30db\u30b9\u30c6\u30a3\u30f3\u30b0\u3082\u4f7f\u3046\u306e\u3067<code>Authentication emulator<\/code>\u3068<code>Hosting Emulator<\/code>\u3082\u4f7f\u3048\u308b\u3088\u3046\u306b\u8a2d\u5b9a\u3057\u3066\u304a\u304d\u307e\u3059\u3002<br \/>\n\u3042\u3068\u3001<code>firebase init hosting<\/code>\u3067\u30db\u30b9\u30c6\u30a3\u30f3\u30b0\u7528\u306e\u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb\u3092\u4f5c\u6210\u3057\u3066\u304a\u304d\u307e\u3059\u3002<\/p>\n<p>\u4ee5\u4e0b\u306e\u5185\u5bb9\u306e\u30d5\u30a1\u30a4\u30eb\u3092<code>functions\/src\/populate_collection.ts<\/code>\u306b\u4f5c\u6210\u3057\u307e\u3059\u3002<br \/>\n\u51e6\u7406\u5185\u5bb9\u306f\u4ee5\u4e0b\u3067\u3059\u3002<\/p>\n<ul>\n<li>\u30c6\u30ad\u30b9\u30c8\u30d5\u30a1\u30a4\u30eb<code>functions\/company.txt<\/code>\u3092\u8aad\u3093\u3067\u3001\u6539\u884c\uff12\u3064\u3092\u533a\u5207\u308a\u3068\u3057\u3066\u30c1\u30e3\u30f3\u30af\u306b\u5206\u3051\u308b<\/li>\n<li>textEmbeddingGecko001\u3067\u30a8\u30f3\u30d9\u30c7\u30a3\u30f3\u30b0\u3057\u30d9\u30af\u30bf\u30fc\u60c5\u5831\u3068\u30c1\u30e3\u30f3\u30af\u3092Firestore\u306e\u30b3\u30ec\u30af\u30b7\u30e7\u30f3\u300ccompany\u300d\u306b\u4fdd\u5b58\n<\/ul>\n<pre><code class=\"sh\">import { configureGenkit } from \"@genkit-ai\/core\";\nimport { embed } from \"@genkit-ai\/ai\/embedder\";\nimport { defineFlow, run } from \"@genkit-ai\/flow\";\nimport { textEmbeddingGecko001, googleAI } from \"@genkit-ai\/googleai\";\n\nimport { FieldValue, getFirestore } from \"firebase-admin\/firestore\";\n\nimport { chunk } from \"llm-chunk\";\nimport * as z from \"zod\";\n\nimport { readFile } from \"fs\/promises\";\nimport path from \"path\";\n\nconst indexConfig = {\n  collection: \"company\",\n  contentField: \"text\",\n  vectorField: \"embedding\",\n  embedder: textEmbeddingGecko001,\n};\n\nconfigureGenkit({\n  plugins: [googleAI()],\n  enableTracingAndMetrics: false,\n});\n\nconst firestore = getFirestore();\n\n\/\/ Firebase function\u306b\u3057\u306a\u3044\u306e\u3067onFlow\u3067\u306f\u306a\u304fdefineFlow\u95a2\u6570\u3092\u4f7f\u3046\nexport const indexFlow = defineFlow(\n  {\n    name: \"indexFlow\",\n    inputSchema: z.void(),\n    outputSchema: z.void(),\n  },\n  async () =&gt; {\n    const filePath = path.resolve('.\/company.txt');\n\n    const txt = await run(\"extract-text\", () =&gt;\n      extractText(filePath)\n    );\n\n    \/\/ \u6539\u884c\uff12\u3064\u3092\u533a\u5207\u308a\u3068\u3057\u3066\u30c1\u30e3\u30f3\u30af\u4f5c\u6210\n    const chunks = await run(\"chunk-it\", async () =&gt; chunk(txt, {delimiters: '\\n\\n' }));\n\n    \/\/ Add chunks to the index.\n    await run(\"index-chunks\", async () =&gt; indexToFirestore(chunks));\n  }\n);\n\nasync function indexToFirestore(data: string[]) {\n  for (const text of data) {\n    const embedding = await embed({\n      embedder: indexConfig.embedder,\n      content: text,\n    });\n    await firestore.collection(indexConfig.collection).add({\n      [indexConfig.vectorField]: FieldValue.vector(embedding),\n      [indexConfig.contentField]: text,\n    });\n  }\n}\n\nasync function extractText (filePath: string) {\n  const f = path.resolve(filePath);\n  return await readFile(f, 'utf-8');\n}\n<\/code><\/pre>\n<p>\u4e0a\u8a18\u3092\u5b9f\u884c\u3059\u308b\u305f\u3081\u3001<code>functions\/src\/index.ts<\/code>\u306b\u4ee5\u4e0b\u3092\u8ffd\u52a0\u3057\u307e\u3059\u3002<\/p>\n<pre><code class=\"bash\">export { indexFlow } from '.\/populate_collection';\n<\/code><\/pre>\n<p>\u7d50\u679c\u3001Genkit Dev UI\u306e\u30d5\u30ed\u30fc\u306b\u300cindexFlow\u300d\u304c\u8ffd\u52a0\u3055\u308c\u307e\u3057\u305f\u3002<br \/>\ninput JSON\u306b\u4f55\u3082\u5165\u529b\u305b\u305a\u3001\u300cRUN\u300d\u30dc\u30bf\u30f3\u3092\u62bc\u3057\u307e\u3059\u3002<br \/>\n\u6210\u529f\u3059\u308b\u3068\u3001Firestore\u306b<code>company<\/code>\u30b3\u30ec\u30af\u30b7\u30e7\u30f3\u304c\u4f5c\u6210\u3055\u308c\u307e\u3059\u3002<br \/>\n\u30a8\u30df\u30e5\u30ec\u30fc\u30bf\u3067\u78ba\u8a8d\u3057\u3066\u307f\u308b\u3068\u3001embedding\u3068text\u30d5\u30a3\u30fc\u30eb\u30c9\u3092\u6301\u3064\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u304c\u8907\u6570\u3042\u308a\u3001embedding.value\u306b\u306f\u30d9\u30af\u30bf\u30fc\u60c5\u5831\u304c\u3042\u308a\u307e\u3059\u3002<\/p>\n<h2>RAG\u306e\u30d7\u30ed\u30f3\u30d7\u30c8\u751f\u6210<\/h2>\n<p>functions\/src\/index.ts\u3092\u4ee5\u4e0b\u306e\u5185\u5bb9\u306b\u7f6e\u304d\u63db\u3048\u307e\u3059\u3002<\/p>\n<pre><code class=\"sh\">import {retrieve} from \"@genkit-ai\/ai\";\nimport {configureGenkit} from \"@genkit-ai\/core\";\nimport {firebaseAuth} from \"@genkit-ai\/firebase\/auth\";\nimport {onFlow} from \"@genkit-ai\/firebase\/functions\";\nimport {geminiPro, textEmbeddingGecko001} from \"@genkit-ai\/googleai\";\nimport * as z from \"zod\";\nimport {defineFirestoreRetriever, firebase} from \"@genkit-ai\/firebase\";\nimport {googleAI} from \"@genkit-ai\/googleai\";\nimport { getFirestore } from \"firebase-admin\/firestore\";\nimport { defineDotprompt } from '@genkit-ai\/dotprompt';\nimport { initializeApp } from \"firebase-admin\/app\";\nimport { dotprompt } from '@genkit-ai\/dotprompt';\n\ninitializeApp()\n\nconfigureGenkit({\n  plugins: [\n    dotprompt(),\n    firebase(),\n    googleAI(),\n  ],\n  flowStateStore: 'firebase',\n  logLevel: 'debug',\n  traceStore: 'firebase',\n  enableTracingAndMetrics: true,\n});\n\nconst firestore = getFirestore();\n\nconst retrieverRef = defineFirestoreRetriever({\n  name: \"companyRetriever\",\n  firestore,\n  collection: \"company\",\n  contentField: \"text\",\n  vectorField: \"embedding\",\n  embedder: textEmbeddingGecko001,\n  distanceMeasure: \"COSINE\", \/\/ \"EUCLIDEAN\", \"DOT_PRODUCT\", or \"COSINE\" (default)\n});\n\n\nconst CompanyQuestionInputSchema = z.object({\n  data: z.array(z.string()),\n  question: z.string(),\n});\n\nconst companyPrompt = defineDotprompt(\n  {\n    name: 'companyPrompt',\n    model: geminiPro,\n    input: { schema: CompanyQuestionInputSchema },\n    output: { format: 'text' },\n    config: { temperature: 0.3 },\n  },\n  `\n\u3042\u306a\u305f\u306f\u6709\u9650\u4f1a\u793e\u30e9\u30f3\u30ab\u30fc\u30c9\u30b3\u30e0\u306e\u5e83\u5831\u62c5\u5f53\u8005\u3067\u3059\u3002\n\u4ee5\u4e0b\u306f\u6709\u9650\u4f1a\u793e\u30e9\u30f3\u30ab\u30fc\u30c9\u30b3\u30e0\u306e\u4f1a\u793e\u6982\u8981\u3067\u3059\u3002\n{{#each data~}}\n- {{this}}\n{{~\/each}}\n\n\u4f1a\u793e\u6982\u8981\u3092\u5143\u306b\u4ee5\u4e0b\u306e\u30ab\u30b9\u30bf\u30de\u30fc\u306e\u8cea\u554f\u306b\u56de\u7b54\u3057\u3066\u304f\u3060\u3055\u3044:\n{{question}}?\n`\n);\n\nexport const companyFlow = onFlow(\n  {\n    name: \"companyFlow\",\n    inputSchema: z.string(),\n    outputSchema: z.string(),\n    authPolicy: firebaseAuth((user) =&gt; {\n      if (!user.email_verified) {\n        throw new Error(\"Verified email required to run flow\");\n      }\n    }),\n  },\n  async (question) =&gt; {\n    const docs = await retrieve({\n      retriever: retrieverRef,\n      query: question,\n      options: {limit: 5},\n    });\n    const llmResponse = await companyPrompt.generate({\n      input: {\n        data: docs.map(doc =&gt; doc.content[0].text || ''),\n        question,\n      },\n    });\n\n    return llmResponse.text();\n  }\n);\n\nexport { indexFlow } from '.\/populate_collection';\n<\/code><\/pre>\n<p>Genkit Dev UI\u306e\u30d5\u30ed\u30fc<code>companyFlow<\/code>\u3067Auth JSON\u306b<code>{\"uid\": 0,\"email_verified\": true}<\/code>\u3092\u5165\u529b\u3057\u3001\u9069\u5f53\u306a\u8cea\u554f\u3092input JSON\u306b\u5165\u529b\u3057\u5b9f\u884c\u3059\u308b\u3068\u3001\u6b63\u3057\u304f\u56de\u7b54\u304c\u8fd4\u3063\u3066\u304d\u307e\u3057\u305f\u3002<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.lancard.com\/blog\/wp-content\/uploads\/2024\/05\/companyFlow.png\" alt=\"\" width=\"673\" height=\"532\" class=\"aligncenter size-full wp-image-7734\" srcset=\"https:\/\/www.lancard.com\/blog\/wp-content\/uploads\/2024\/05\/companyFlow.png 673w, https:\/\/www.lancard.com\/blog\/wp-content\/uploads\/2024\/05\/companyFlow-400x316.png 400w, https:\/\/www.lancard.com\/blog\/wp-content\/uploads\/2024\/05\/companyFlow-602x476.png 602w\" sizes=\"auto, (max-width: 673px) 100vw, 673px\" \/><\/p>\n<h2>\u30e2\u30c7\u30eb\u3092OpenAI\u306eGPT-4o\u306b\u5909\u66f4<\/h2>\n<p><a href=\"https:\/\/github.com\/TheFireCo\/genkit-plugins\">genkitx-openai<\/a>\u3092\u4f7f\u3044\u307e\u3059\u3002<\/p>\n<pre><code class=\"sh\">cd functions\nnpm i genkitx-openai\n<\/code><\/pre>\n<pre><code class=\"sh\">- import {geminiPro, textEmbeddingGecko001} from \"@genkit-ai\/googleai\";\n- import {googleAI} from \"@genkit-ai\/googleai\";\n+ import { gpt4o, openAI, textEmbedding3Small } from \"genkitx-openai\";\n<\/code><\/pre>\n<p><code>googleAI<\/code>\u3092<code>openAI<\/code>\u306b\u3001<code>geminiPro<\/code>\u3092<code>gpt4o<\/code>\u3001<code>textEmbeddingGecko001<\/code>\u3092<code>textEmbedding3Small<\/code>\u306b\u7f6e\u63db\u3057\u307e\u3059\u3002<\/p>\n<p>OpenAI\u306e\u74b0\u5883\u5909\u6570\u3092\u30bb\u30c3\u30c8\u3057\u3001\u30a8\u30df\u30e5\u30ec\u30fc\u30bf\u3092\u8d77\u52d5\u3057\u307e\u3059\u3002<\/p>\n<pre><code class=\"sh\">export OPENAI_API_KEY=*************\nGENKIT_ENV=dev firebase emulators:start --inspect-functions\n<\/code><\/pre>\n<p>indexFlow\u3067\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u4f5c\u6210\u3057\u3001companyFlow\u3067\u6b63\u3057\u304f\u56de\u7b54\u3055\u308c\u308b\u304b\u78ba\u8a8d\u3057\u307e\u3059\u3002<\/p>\n<h2>\u30d6\u30e9\u30a6\u30b6\u304b\u3089Firebase Function\u3092\u547c\u3073\u51fa\u3057\u5b9f\u884c<\/h2>\n<p>public\/index.html\u3092\u4ee5\u4e0b\u306e\u5185\u5bb9\u306b\u66f8\u304d\u63db\u3048\u307e\u3059\u3002<br \/>\n<a href=\"https:\/\/github.com\/firebase\/genkit\/blob\/main\/docs\/firebase.md\">\u3053\u3053<\/a>\u306e<code>4.Replace public\/index.html with the following:<\/code>\u3092\u3001\u30a8\u30df\u30e5\u30ec\u30fc\u30bf\u3067\u52d5\u4f5c\u3059\u308b\u3088\u3046\u306b\u4fee\u6b63\u3057\u307e\u3057\u305f\u3002<\/p>\n<pre><code class=\"html\">&lt;!doctype html&gt;\n&lt;html&gt;\n  &lt;head&gt;\n    &lt;title&gt;Genkit demo&lt;\/title&gt;\n  &lt;\/head&gt;\n  &lt;body&gt;\n    &lt;div id=\"signin\" hidden&gt;\n      &lt;button id=\"signinBtn\"&gt;Sign in with Google&lt;\/button&gt;\n    &lt;\/div&gt;\n    &lt;div id=\"callGenkit\" hidden&gt;\n      &lt;div&gt;\u6709\u9650\u4f1a\u793e\u30e9\u30f3\u30ab\u30fc\u30c9\u30b3\u30e0\u306b\u3064\u3044\u3066\u304a\u805e\u304d\u304f\u3060\u3055\u3044\u3002&lt;\/div&gt;\n      &lt;textarea id=\"question\" rows=\"5\" cols=\"33\"&gt;&lt;\/textarea&gt;\n      &lt;div&gt;\n        &lt;button id=\"submit\"&gt;\u9001\u4fe1&lt;\/button&gt;\n      &lt;\/div&gt;\n      &lt;p id=\"answer\"&gt;&lt;\/p&gt;\n    &lt;\/div&gt;\n    &lt;script type=\"module\"&gt;\n      import { initializeApp } from 'https:\/\/www.gstatic.com\/firebasejs\/10.10.0\/firebase-app.js';\n      import {\n        getAuth,\n        connectAuthEmulator,\n        onAuthStateChanged,\n        GoogleAuthProvider,\n        signInWithPopup,\n      } from 'https:\/\/www.gstatic.com\/firebasejs\/10.10.0\/firebase-auth.js';\n      import {\n        getFunctions,\n        httpsCallable,\n        connectFunctionsEmulator\n      } from 'https:\/\/www.gstatic.com\/firebasejs\/10.10.0\/firebase-functions.js';\n      import {\n        getFirestore,\n        connectFirestoreEmulator\n      } from 'https:\/\/www.gstatic.com\/firebasejs\/10.10.0\/firebase-firestore.js';\n      const firebaseConfig = await fetch('\/__\/firebase\/init.json');\n      const firebaseApp = initializeApp(await firebaseConfig.json());\n\n      if (location.hostname === 'localhost') {\n        const auth = getAuth(firebaseApp)\n        const firestore = getFirestore(firebaseApp)\n        const functions = getFunctions(firebaseApp)\n\n        connectFirestoreEmulator(firestore, location.hostname, 8080, { ssl: false })\n        connectFunctionsEmulator(functions, location.hostname, 5001)\n        connectAuthEmulator(auth, `http:\/\/${location.hostname}:9099`)\n      }\n\n\n\n      async function generateAnswer() {\n        const companyFlow = httpsCallable(\n          getFunctions(),\n          'companyFlow'\n        );\n        const question = document.querySelector('#question').value;\n        const response = await companyFlow(question);\n        document.querySelector('#answer').innerText = response.data;\n      }\n\n      function signIn() {\n        signInWithPopup(getAuth(), new GoogleAuthProvider());\n      }\n\n      document\n        .querySelector('#signinBtn')\n        .addEventListener('click', signIn);\n      document\n        .querySelector('#submit')\n        .addEventListener('click', generateAnswer);\n\n      const signinEl = document.querySelector('#signin');\n      const genkitEl = document.querySelector('#callGenkit');\n\n      onAuthStateChanged(getAuth(), (user) =&gt; {\n        if (!user) {\n          signinEl.hidden = false;\n          genkitEl.hidden = true;\n        } else {\n          signinEl.hidden = true;\n          genkitEl.hidden = false;\n        }\n      });\n    &lt;\/script&gt;\n  &lt;\/body&gt;\n&lt;\/html&gt;\n<\/code><\/pre>\n<p>http:\/\/localhost:5002\/\u306b\u30a2\u30af\u30bb\u30b9\u3057\u3001\u300cSign in with Google\u300d\u30dc\u30bf\u30f3\u3092\u62bc\u3059\u3068\u30a8\u30df\u30e5\u30ec\u30fc\u30bf\u306eAuthentication\u306b\u30a2\u30ab\u30a6\u30f3\u30c8\u3092\u4f5c\u6210\u3067\u304d\u307e\u3059\u3002\u30c6\u30ad\u30b9\u30c8\u30a8\u30ea\u30a2\u306b\u8cea\u554f\u5165\u529b\u3057\u9001\u4fe1\u3057\u3001\u56de\u7b54\u304c\u8fd4\u3063\u3066\u304f\u308c\u3070\u6210\u529f\u3067\u3059\u3002<\/p>\n<p>\u56de\u7b54\u4f8b<br \/>\n<img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.lancard.com\/blog\/wp-content\/uploads\/2024\/05\/answer.png\" alt=\"\" width=\"1306\" height=\"1214\" class=\"aligncenter size-full wp-image-7736\" srcset=\"https:\/\/www.lancard.com\/blog\/wp-content\/uploads\/2024\/05\/answer.png 1306w, https:\/\/www.lancard.com\/blog\/wp-content\/uploads\/2024\/05\/answer-400x372.png 400w, https:\/\/www.lancard.com\/blog\/wp-content\/uploads\/2024\/05\/answer-602x560.png 602w, https:\/\/www.lancard.com\/blog\/wp-content\/uploads\/2024\/05\/answer-768x714.png 768w\" sizes=\"auto, (max-width: 1306px) 100vw, 1306px\" \/><\/p>\n<h2>\u8ab2\u984c<\/h2>\n<h4>\u30b9\u30c8\u30ea\u30fc\u30e0\u3067\u56de\u7b54\u51fa\u529b<\/h4>\n<p>Genkit\u5074\u3067\u306f<a href=\"https:\/\/firebase.google.com\/docs\/genkit\/models?hl=ja#streaming_responses\">generateStream<\/a>\u3067\u30b9\u30c8\u30ea\u30fc\u30e0\u51fa\u529b\u3067\u304d\u307e\u3059\u304c\u3001onFlow\uff08https.onCall\u306e\u30d7\u30ed\u30c8\u30b3\u30eb\u306b\u6e96\u62e0\uff09\u3092\u4f7f\u3063\u3066\u3001\u30d6\u30e9\u30a6\u30b6\u306b\u3069\u3046\u3084\u3063\u3066\u9010\u6b21\u30c7\u30fc\u30bf\u3092\u8fd4\u305b\u3070\u3044\u3044\u306e\u304b\u3001\u5206\u304b\u308a\u307e\u305b\u3093\u3067\u3057\u305f\u3002Firestore\u306b\u30c1\u30e3\u30f3\u30af\u30c7\u30fc\u30bf\u3092\u9010\u6b21\u4fdd\u5b58\u3059\u308c\u3070\u3001onSnapshot\u3067\u30b9\u30c8\u30ea\u30fc\u30df\u30f3\u30b0\u3067\u30c7\u30fc\u30bf\u3092\u8fd4\u3059\u3053\u3068\u306f\u3067\u304d\u307e\u3059\u304c\u3001\u8ab2\u91d1\u304a\u3088\u3073\u901f\u5ea6\u7684\u306b\u3044\u3044\u65b9\u6cd5\u3068\u306f\u601d\u3048\u307e\u305b\u3093\u3002<br \/>\nFirebase Genkit\u306f\u307e\u3060\u30d9\u30fc\u30bf\u7248\u306a\u306e\u3067\u3001\u4eca\u5f8cFirebase functions\u3067\u30b9\u30c8\u30ea\u30fc\u30df\u30f3\u30b0\u3067\u8fd4\u305b\u308b\u3088\u3046\u306b\u306a\u308b\u3053\u3068\u3092\u671f\u5f85\u3057\u3066\u3044\u307e\u3059\u3002<br \/>\n2024\/08\/01\u8ffd\u8a18<br \/>\nonFlow\u3092\u4f7f\u308f\u305a\u3001onRequest\u3092\u4f7f\u3048\u3070\u3001\u30b9\u30c8\u30ea\u30fc\u30e0\u3067\u56de\u7b54\u51fa\u529b\u3067\u304d\u307e\u3057\u305f\u3002onRequest\u306fHTTP\u30d7\u30ed\u30c8\u30b3\u30eb\u306a\u306e\u3067\u3001\u30b5\u30fc\u30d0\u30fc\u9001\u4fe1\u30a4\u30d9\u30f3\u30c8 (Server-Sent Events\u3001SSE) \u3092\u4f7f\u3046\u3053\u3068\u304c\u3067\u304d\u3001\u3053\u308c\u3092\u4f7f\u3044\u307e\u3057\u305f\u3002\u305f\u3060\u4f5c\u6210\u3057\u305fdefineFlow\u3092onRequest\u306b\u66f8\u304d\u76f4\u3059\u306e\u306f\u9762\u5012\u3067\u3059\u3002<br \/>\nonFlow\u306e\u3088\u3046\u306a\u611f\u3058\u3067onRequest\u306e\u30d7\u30ed\u30c8\u30b3\u30eb\u3092\u6301\u3064\u30d5\u30ed\u30fc\u3092\u4f5c\u6210\u3059\u308bGenkit\u306e\u30d7\u30e9\u30b0\u30a4\u30f3\u304c\u3042\u308c\u3070\u826f\u3044\u306e\u3067\u3059\u304c\u3002<\/p>\n<a class=\"synved-social-button synved-social-button-share synved-social-size-24 synved-social-resolution-single synved-social-provider-facebook nolightbox\" data-provider=\"facebook\" target=\"_blank\" rel=\"nofollow\" title=\"Share on Facebook\" href=\"https:\/\/www.facebook.com\/sharer.php?u=https%3A%2F%2Fwww.lancard.com%2Fblog%2Fwp-json%2Fwp%2Fv2%2Fposts%2F7699&#038;t=Firebase%20Genkit%E3%82%92%E8%A9%A6%E3%81%97%E3%81%A6%E3%81%BF%E3%81%9F&#038;s=100&#038;p&#091;url&#093;=https%3A%2F%2Fwww.lancard.com%2Fblog%2Fwp-json%2Fwp%2Fv2%2Fposts%2F7699&#038;p&#091;images&#093;&#091;0&#093;=https%3A%2F%2Fwww.lancard.com%2Fblog%2Fwp-content%2Fuploads%2F2024%2F05%2FcompanyFlow.png&#038;p&#091;title&#093;=Firebase%20Genkit%E3%82%92%E8%A9%A6%E3%81%97%E3%81%A6%E3%81%BF%E3%81%9F\" style=\"font-size: 0px;width:24px;height:24px;margin:0;margin-bottom:5px;margin-right:5px\"><img loading=\"lazy\" decoding=\"async\" alt=\"Facebook\" title=\"Share on Facebook\" class=\"synved-share-image synved-social-image synved-social-image-share\" width=\"24\" height=\"24\" style=\"display: inline;width:24px;height:24px;margin: 0;padding: 0;border: none;box-shadow: none\" src=\"https:\/\/www.lancard.com\/blog\/wp-content\/plugins\/social-media-feather\/synved-social\/image\/social\/regular\/48x48\/facebook.png\" \/><\/a><a class=\"synved-social-button synved-social-button-share synved-social-size-24 synved-social-resolution-single synved-social-provider-twitter nolightbox\" data-provider=\"twitter\" target=\"_blank\" rel=\"nofollow\" title=\"Share on Twitter\" href=\"http:\/\/twitter.com\/share?url=https%3A%2F%2Fwww.lancard.com%2Fblog%2Fwp-json%2Fwp%2Fv2%2Fposts%2F7699&#038;text=Firebase%20Genkit%E3%82%92%E8%A9%A6%E3%81%97%E3%81%A6%E3%81%BF%E3%81%9F\" style=\"font-size: 0px;width:24px;height:24px;margin:0;margin-bottom:5px;margin-right:5px\"><img loading=\"lazy\" decoding=\"async\" alt=\"twitter\" title=\"Share on Twitter\" class=\"synved-share-image synved-social-image synved-social-image-share\" width=\"24\" height=\"24\" style=\"display: inline;width:24px;height:24px;margin: 0;padding: 0;border: none;box-shadow: none\" src=\"https:\/\/www.lancard.com\/blog\/wp-content\/plugins\/social-media-feather\/synved-social\/image\/social\/regular\/48x48\/twitter.png\" \/><\/a><a class=\"synved-social-button synved-social-button-share synved-social-size-24 synved-social-resolution-single synved-social-provider-linkedin nolightbox\" data-provider=\"linkedin\" target=\"_blank\" rel=\"nofollow\" title=\"Share on Linkedin\" href=\"https:\/\/www.linkedin.com\/shareArticle?mini=true&#038;url=https%3A%2F%2Fwww.lancard.com%2Fblog%2Fwp-json%2Fwp%2Fv2%2Fposts%2F7699&#038;title=Firebase%20Genkit%E3%82%92%E8%A9%A6%E3%81%97%E3%81%A6%E3%81%BF%E3%81%9F\" style=\"font-size: 0px;width:24px;height:24px;margin:0;margin-bottom:5px;margin-right:5px\"><img loading=\"lazy\" decoding=\"async\" alt=\"linkedin\" title=\"Share on Linkedin\" class=\"synved-share-image synved-social-image synved-social-image-share\" width=\"24\" height=\"24\" style=\"display: inline;width:24px;height:24px;margin: 0;padding: 0;border: none;box-shadow: none\" src=\"https:\/\/www.lancard.com\/blog\/wp-content\/plugins\/social-media-feather\/synved-social\/image\/social\/regular\/48x48\/linkedin.png\" \/><\/a><a class=\"synved-social-button synved-social-button-share synved-social-size-24 synved-social-resolution-single synved-social-provider-tumblr nolightbox\" data-provider=\"tumblr\" target=\"_blank\" rel=\"nofollow\" title=\"Share on tumblr\" href=\"https:\/\/tumblr.com\/share?s=&#038;v=3&#038;t=Firebase%20Genkit%E3%82%92%E8%A9%A6%E3%81%97%E3%81%A6%E3%81%BF%E3%81%9F&#038;u=https%3A%2F%2Fwww.lancard.com%2Fblog%2Fwp-json%2Fwp%2Fv2%2Fposts%2F7699\" style=\"font-size: 0px;width:24px;height:24px;margin:0;margin-bottom:5px;margin-right:5px\"><img loading=\"lazy\" decoding=\"async\" alt=\"tumblr\" title=\"Share on tumblr\" class=\"synved-share-image synved-social-image synved-social-image-share\" width=\"24\" height=\"24\" style=\"display: inline;width:24px;height:24px;margin: 0;padding: 0;border: none;box-shadow: none\" src=\"https:\/\/www.lancard.com\/blog\/wp-content\/plugins\/social-media-feather\/synved-social\/image\/social\/regular\/48x48\/tumblr.png\" \/><\/a><a class=\"synved-social-button synved-social-button-share synved-social-size-24 synved-social-resolution-single synved-social-provider-mail nolightbox\" data-provider=\"mail\" rel=\"nofollow\" title=\"Share by email\" href=\"mailto:?subject=Firebase%20Genkit%E3%82%92%E8%A9%A6%E3%81%97%E3%81%A6%E3%81%BF%E3%81%9F&#038;body=%E3%82%B7%E3%82%A7%E3%82%A2%E3%81%99%E3%82%8B%EF%BC%9A:%20https%3A%2F%2Fwww.lancard.com%2Fblog%2Fwp-json%2Fwp%2Fv2%2Fposts%2F7699\" style=\"font-size: 0px;width:24px;height:24px;margin:0;margin-bottom:5px\"><img loading=\"lazy\" decoding=\"async\" alt=\"mail\" title=\"Share by email\" class=\"synved-share-image synved-social-image synved-social-image-share\" width=\"24\" height=\"24\" style=\"display: inline;width:24px;height:24px;margin: 0;padding: 0;border: none;box-shadow: none\" src=\"https:\/\/www.lancard.com\/blog\/wp-content\/plugins\/social-media-feather\/synved-social\/image\/social\/regular\/48x48\/mail.png\" \/><\/a>","protected":false},"excerpt":{"rendered":"<p>Firebase Genkit \u306f\u3001\u672c\u756a\u74b0\u5883\u306b\u5bfe\u5fdc\u3057\u305f AI \u642d\u8f09\u30a2\u30d7\u30ea\u306e\u69cb\u7bc9\u3001\u30c7\u30d7\u30ed\u30a4\u3001\u30e2\u30cb\u30bf\u30ea\u30f3\u30b0\u306b\u5f79\u7acb\u3064\u30aa\u30fc\u30d7\u30f3\u30bd\u30fc\u30b9 \u30d5\u30ec\u30fc\u30e0\u30ef\u30fc\u30af\u3067\u3059\u3002 \u4eca\u56de\u3001\u4ee5\u4e0b\u3092\u8a66\u3057\u3066\u307f\u307e\u3059\u3002 \u30d6\u30e9\u30a6\u30b6\u304b\u3089Firebase Functio [&hellip;]<\/p>\n","protected":false},"author":25,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[155],"tags":[190,230],"class_list":["post-7699","post","type-post","status-publish","format-standard","hentry","category-javascript","tag-firebase","tag-ai"],"_links":{"self":[{"href":"https:\/\/www.lancard.com\/blog\/wp-json\/wp\/v2\/posts\/7699","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.lancard.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.lancard.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.lancard.com\/blog\/wp-json\/wp\/v2\/users\/25"}],"replies":[{"embeddable":true,"href":"https:\/\/www.lancard.com\/blog\/wp-json\/wp\/v2\/comments?post=7699"}],"version-history":[{"count":40,"href":"https:\/\/www.lancard.com\/blog\/wp-json\/wp\/v2\/posts\/7699\/revisions"}],"predecessor-version":[{"id":7758,"href":"https:\/\/www.lancard.com\/blog\/wp-json\/wp\/v2\/posts\/7699\/revisions\/7758"}],"wp:attachment":[{"href":"https:\/\/www.lancard.com\/blog\/wp-json\/wp\/v2\/media?parent=7699"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.lancard.com\/blog\/wp-json\/wp\/v2\/categories?post=7699"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.lancard.com\/blog\/wp-json\/wp\/v2\/tags?post=7699"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}