{"version":3,"sources":["../../src/vertexai/embedder.ts"],"sourcesContent":["/**\n * Copyright 2024 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { z, type Document } from 'genkit';\nimport {\n  EmbedderInfo,\n  embedderRef,\n  type EmbedderAction,\n  type EmbedderReference,\n} from 'genkit/embedder';\nimport { embedder as pluginEmbedder } from 'genkit/plugin';\nimport { toGeminiMessage } from '../common/converters.mjs';\nimport { isKnownKey, warnDroppedConfigField } from '../common/utils.mjs';\nimport { embedContent, embedPredict } from './client.mjs';\nimport {\n  ClientOptions,\n  EmbedPredictRequest,\n  EmbeddingInstance,\n  EmbeddingPrediction,\n  EmbeddingResult,\n  TaskTypeSchema,\n  VertexPluginOptions,\n  isMultimodalEmbeddingPrediction,\n  isObject,\n} from './types.mjs';\nimport { checkModelName, extractVersion } from './utils.mjs';\n\nexport const EmbeddingConfigSchema = z\n  .object({\n    /**\n     * The `task_type` parameter is defined as the intended downstream application\n     * to help the model produce better quality embeddings.\n     **/\n    taskType: TaskTypeSchema.optional(),\n    title: z.string().optional(),\n    location: z.string().optional(),\n    version: z.string().optional(),\n    /**\n     * The `outputDimensionality` parameter allows you to specify the dimensionality of the embedding output.\n     * The default dimensions depend on the model (1408 for multimodalembedding@001).\n     * By selecting a smaller output dimensionality, users can save memory and storage space, leading to more efficient computations.\n     **/\n    outputDimensionality: z.number().min(1).optional(),\n    /**\n     * For newly released embedders this parameter provides a hint for the proper\n     * way to call the embedder. (Multimodal embedders have a different request\n     * structure than non-multimodal embedders).\n     * For well-known embedders, this value will be ignored since we will already\n     * know if it's multimodal or not.\n     */\n    multimodal: z.boolean().optional(),\n  })\n  .passthrough();\nexport type EmbeddingConfigSchemaType = typeof EmbeddingConfigSchema;\nexport type EmbeddingConfig = z.infer<EmbeddingConfigSchemaType>;\n\n// for commonRef\ntype ConfigSchemaType = EmbeddingConfigSchemaType;\n\nfunction commonRef(\n  name: string,\n  info?: EmbedderInfo,\n  configSchema: ConfigSchemaType = EmbeddingConfigSchema\n): EmbedderReference<ConfigSchemaType> {\n  return embedderRef({\n    name: `vertexai/${name}`,\n    configSchema,\n    info: info ?? {\n      dimensions: 768,\n      supports: {\n        input: ['text'],\n      },\n    },\n  });\n}\n\nconst GENERIC_TEXT_MODEL = commonRef('text', {\n  dimensions: 3072,\n  supports: { input: ['text'] },\n});\nconst GENERIC_MULTIMODAL_MODEL = commonRef('multimodal', {\n  dimensions: 1408,\n  supports: { input: ['text', 'image', 'video'] },\n});\n\nexport const KNOWN_MODELS = {\n  'text-embedding-005': commonRef('text-embedding-005'),\n  'text-multilingual-embedding-002': commonRef(\n    'text-multilingual-embedding-002'\n  ),\n  'multimodalembedding@001': commonRef('multimodalembedding@001', {\n    dimensions: 1408,\n    supports: { input: ['text', 'image', 'video'] },\n  }),\n  'gemini-embedding-001': commonRef('gemini-embedding-001', {\n    dimensions: 3072,\n    supports: { input: ['text'] },\n  }),\n  // Uses the `:embedContent` method (see usesEmbedContent).\n  'gemini-embedding-2': commonRef('gemini-embedding-2', {\n    dimensions: 3072,\n    supports: { input: ['text', 'image', 'video'] },\n  }),\n} as const;\nexport type KnownModels = keyof typeof KNOWN_MODELS; // For autocomplete\n\n// Models we no longer suggest, but that still work: they still resolve and\n// are still registered as embedders, but aren't in the KnownModels type, so\n// they don't show up in autocomplete. Remove a model once the server returns\n// 404 for it.\nconst HIDDEN_MODELS = {\n  // Older model (retires Apr 1 2027). Listed so its routing is explicit: it\n  // uses `:predict`, while newer embedders may use `:embedContent` (like\n  // gemini-embedding-2). If the default for unlisted names ever changes,\n  // this one must stay on `:predict`.\n  'text-embedding-004': commonRef('text-embedding-004', {\n    dimensions: 768,\n    supports: { input: ['text'] },\n  }),\n} as const;\n\nconst ALL_MODELS = {\n  ...HIDDEN_MODELS,\n  ...KNOWN_MODELS,\n};\n\n/**\n * Whether a model uses the `:embedContent` method (one content with\n * interleaved text and media parts per request) instead of `:predict`.\n * Newer Gemini embedders (gemini-embedding-2 and later, including unlisted\n * ones) use it; gemini-embedding-001, text-embedding-* and\n * multimodalembedding@001 use `:predict`.\n */\nfunction usesEmbedContent(name: string): boolean {\n  return (\n    name.startsWith('gemini-embedding-') && name !== 'gemini-embedding-001'\n  );\n}\n\nexport type EmbedderModelName = `${string}embedding${string}`;\nexport function isEmbedderName(value: string): value is EmbedderModelName {\n  return value.includes('embedding');\n}\n\nexport function model(\n  version: string,\n  config: EmbeddingConfig = {}\n): EmbedderReference<ConfigSchemaType> {\n  const name = checkModelName(version);\n\n  if (isKnownKey(name, ALL_MODELS)) {\n    const known = ALL_MODELS[name];\n    return embedderRef({\n      name: known.name,\n      info: known.info,\n      configSchema: known.configSchema,\n      config,\n    });\n  }\n\n  if (config.multimodal) {\n    // Generic multimodal embedder format\n    return embedderRef({\n      name: `vertexai/${name}`,\n      configSchema: EmbeddingConfigSchema,\n      config,\n      info: {\n        ...GENERIC_MULTIMODAL_MODEL.info,\n      },\n    });\n  }\n  // Generic text-only embedder format\n  return embedderRef({\n    name: `vertexai/${name}`,\n    configSchema: EmbeddingConfigSchema,\n    config,\n    info: {\n      ...GENERIC_TEXT_MODEL.info,\n    },\n  });\n}\n\nexport function listKnownModels(\n  clientOptions: ClientOptions,\n  pluginOptions?: VertexPluginOptions\n) {\n  return Object.keys(ALL_MODELS).map((name) =>\n    defineEmbedder(name, clientOptions, pluginOptions)\n  );\n}\n\n/**\n * Embeds each document with the `:embedContent` method: one request per\n * document, with its text and media as parts.\n */\nasync function embedWithEmbedContent(\n  modelVersion: string,\n  docs: Document[],\n  options: EmbeddingConfig | undefined,\n  clientOptions: ClientOptions\n): Promise<EmbeddingResult[]> {\n  if (options?.taskType !== undefined) {\n    // The model has no task type field; the task goes in the text instead.\n    warnDroppedConfigField(modelVersion, 'taskType');\n  }\n  if (options?.title !== undefined) {\n    warnDroppedConfigField(modelVersion, 'title');\n  }\n  return Promise.all(\n    docs.map(async (doc) => {\n      const response = await embedContent(\n        modelVersion,\n        {\n          content: toGeminiMessage({ role: 'user', content: doc.content }),\n          outputDimensionality: options?.outputDimensionality,\n        },\n        clientOptions\n      );\n      return { embedding: response.embedding.values };\n    })\n  );\n}\n\nexport function defineEmbedder(\n  name: string,\n  clientOptions: ClientOptions,\n  pluginOptions?: VertexPluginOptions\n): EmbedderAction<any> {\n  const ref = model(name);\n\n  return pluginEmbedder(\n    {\n      name: ref.name,\n      configSchema: ref.configSchema,\n      info: ref.info!,\n    },\n    async (request) => {\n      const modelVersion = extractVersion(ref);\n      if (usesEmbedContent(modelVersion)) {\n        return {\n          embeddings: await embedWithEmbedContent(\n            modelVersion,\n            request.input,\n            request.options,\n            clientOptions\n          ),\n        };\n      }\n\n      const embedPredictRequest: EmbedPredictRequest = {\n        instances: request.input.map((doc: Document) =>\n          toEmbeddingInstance(ref, doc, request.options)\n        ),\n        parameters: {\n          outputDimensionality: request.options?.outputDimensionality,\n        },\n      };\n\n      const response = await embedPredict(\n        modelVersion,\n        embedPredictRequest,\n        clientOptions\n      );\n\n      return {\n        embeddings: response.predictions\n          .map(toEmbeddingResult)\n          .reduce((accumulator, value) => {\n            return accumulator.concat(value);\n          }, []),\n      };\n    }\n  );\n}\n\nfunction toEmbeddingInstance(\n  embedder: EmbedderReference<ConfigSchemaType>,\n  doc: Document,\n  options?: EmbeddingConfig\n): EmbeddingInstance {\n  let instance: EmbeddingInstance;\n  if (\n    isMultiModalEmbedder(embedder) ||\n    embedder.config?.multimodal ||\n    options?.multimodal\n  ) {\n    instance = {};\n    if (doc.text) {\n      instance.text = doc.text;\n    }\n    for (var media of doc.media) {\n      if (\n        isObject(media) &&\n        typeof media.url === 'string' &&\n        typeof media.contentType === 'string'\n      ) {\n        if (media.contentType?.startsWith('image/')) {\n          if (media.url.startsWith('http') || media.url.startsWith('gs://')) {\n            instance.image = {\n              gcsUri: media.url,\n              mimeType: media.contentType,\n            };\n          } else {\n            instance.image = {\n              bytesBase64Encoded: media.url,\n              mimeType: media.contentType,\n            };\n          }\n        } else if (media.contentType.startsWith('video/')) {\n          if (media.url.startsWith('http') || media.url.startsWith('gs://')) {\n            instance.video = {\n              gcsUri: media.url,\n            };\n          } else {\n            instance.video = {\n              bytesBase64Encoded: media.url,\n            };\n          }\n          if (\n            instance.video &&\n            doc.metadata &&\n            doc.metadata.videoSegmentConfig\n          ) {\n            instance.video.videoSegmentConfig = doc.metadata.videoSegmentConfig;\n          }\n        } else {\n          throw new Error(`Unsupported contentType: '${media.contentType}`);\n        }\n      } else {\n        // It needs to be a {url:string, contentType:string} object.\n        throw new Error('Invalid media specified.');\n      }\n    }\n  } else {\n    // Text only embedder\n    instance = {\n      content: doc.text,\n      task_type: options?.taskType,\n      title: options?.title,\n    };\n  }\n  return instance;\n}\n\n/**\n * Converts an `EmbeddingPrediction` object to an array of `EmbeddingResult` objects.\n *\n * There will only be multiple EmbeddingResult objects in the array if it is a\n * multimodal embedding prediction for a video.\n * A single video gets automatically broken into chunks and an embedding is\n * returned for each chunk. The metadata identifies which chunk of the video\n * it is for.\n *\n * @param prediction The input `EmbeddingPrediction` object.\n * @returns An array of `EmbeddingResult` objects, each representing a different embedding.\n */\nfunction toEmbeddingResult(prediction: EmbeddingPrediction): EmbeddingResult[] {\n  if (isMultimodalEmbeddingPrediction(prediction)) {\n    const eArray: EmbeddingResult[] = [];\n    if (prediction.imageEmbedding?.length) {\n      const imageResult: EmbeddingResult = {\n        embedding: prediction.imageEmbedding,\n        metadata: { embedType: 'imageEmbedding' },\n      };\n      eArray.push(imageResult);\n    }\n    if (prediction.textEmbedding?.length) {\n      const textResult: EmbeddingResult = {\n        embedding: prediction.textEmbedding,\n        metadata: { embedType: 'textEmbedding' },\n      };\n      eArray.push(textResult);\n    }\n    if (prediction.videoEmbeddings?.length) {\n      for (const ve of prediction.videoEmbeddings) {\n        if (ve.embedding?.length) {\n          const { embedding, ...metadata } = ve;\n          (metadata as Record<string, unknown>).embedType = 'videoEmbedding';\n          const videoResult: EmbeddingResult = {\n            embedding,\n            metadata,\n          };\n          eArray.push(videoResult);\n        }\n      }\n    }\n    return eArray;\n  } else {\n    // Text-only embedding\n    return [\n      {\n        embedding: prediction.embeddings.values,\n      },\n    ];\n  }\n}\n\nfunction isMultiModalEmbedder(\n  embedder: EmbedderReference<ConfigSchemaType>\n): boolean {\n  if (embedder.config?.multimodal) {\n    return true;\n  }\n  const input = embedder.info?.supports?.input || '';\n  return (input.includes('text') && input.includes('image')) || false;\n}\n\nexport const TEST_ONLY = { KNOWN_MODELS, HIDDEN_MODELS, ALL_MODELS };\n"],"mappings":"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","names":[]}