UNPKG

jina-ai-provider

Version:

Jina AI Provider for running Jina AI models with Vercel AI SDK

242 lines (237 loc) 7.31 kB
// src/jina-provider.ts import { loadApiKey, withoutTrailingSlash } from "@ai-sdk/provider-utils"; // src/jina-embedding-model.ts import { TooManyEmbeddingValuesForCallError } from "@ai-sdk/provider"; import { combineHeaders, createJsonResponseHandler, parseProviderOptions, postJsonToApi } from "@ai-sdk/provider-utils"; import { z as z3 } from "zod/v4"; // src/jina-embedding-options.ts import { z } from "zod/v4"; var jinaEmbeddingOptions = z.object({ /** * The input type for the embeddings. * * Defaults to `retrieval.passage`. * * Used to convey intended downstream application to help the model produce better embeddings. * * Must be one of the following values: * - `retrieval.query`: Specifies the given text is a query in a search or retrieval setting. * - `retrieval.passage`: Specifies the given text is a document in a search or retrieval setting. * - `text-matching`: Specifies the given text is used for Semantic Textual Similarity. * - `classification`: Specifies that the embedding is used for classification. * - `separation`: Specifies that the embedding is used for clustering. */ inputType: z.enum([ "text-matching", "retrieval.query", "retrieval.passage", "separation", "classification" ]).optional(), /** * The number of dimensions for the resulting output embeddings. * * - `jina-embeddings-v3`: * - Min Output Dimensions: 32 for better performance * - Max Output Dimensions: 1,024 * * - `jina-clip-v2`: * - Min Output Dimensions: 64 * - Max Output Dimensions: 1,024 * * - `jina-clip-v1`: * - Output Dimensions: 768 * * Please refer to the model documentation for the supported values. * * @see https://jina.ai/api-dashboard/embedding */ outputDimension: z.number().optional(), /** * Late chunking * * When enabled, the model will automatically split the input into chunks of 1024 tokens each. * * @see https://jina.ai/news/jina-embeddings-v3-a-frontier-multilingual-embedding-model/#parameter-latechunking * * Defaults to false. * * This is only supported in text embedding models. */ lateChunking: z.boolean().optional(), /** * The data type for the resulting output embeddings. * * Defaults to `float`. * * - `float`: 32-bit floating-point numbers * - `binary`: 8-bit binary values * - `ubinary`: 8-bit unsigned binary values * - `base64`: Base64 encoded strings */ embeddingType: z.enum(["float", "binary", "ubinary", "base64"]).optional(), /** * Whether to normalize the resulting output embeddings. * Scales the embedding so its Euclidean (L2) norm becomes 1, preserving direction. Useful when downstream involves dot-product, classification, visualization. * Defaults to true. */ normalized: z.boolean().optional(), /** * Truncate at Maximum Context Length which is 8k tokens * * When enabled, the model will automatically drop the tail that extends beyond the maximum context length allowed by the model instead of throwing an error. * * Defaults to false. */ truncate: z.boolean().optional() }); // src/jina-error.ts import { createJsonErrorResponseHandler } from "@ai-sdk/provider-utils"; import { z as z2 } from "zod"; var voyageErrorDataSchema = z2.object({ error: z2.object({ code: z2.string().nullable(), message: z2.string(), param: z2.any().nullable(), type: z2.string() }) }); var voyageFailedResponseHandler = createJsonErrorResponseHandler({ errorSchema: voyageErrorDataSchema, errorToMessage: (data) => data.error.message }); // src/jina-embedding-model.ts var JinaEmbeddingModel = class { specificationVersion = "v2"; modelId; config; get provider() { return this.config.provider; } get maxEmbeddingsPerCall() { return 2048; } get supportsParallelCalls() { return false; } constructor(modelId, config) { this.modelId = modelId; this.config = config; } async doEmbed({ abortSignal, values, headers, providerOptions }) { const embeddingOptions = await parseProviderOptions({ provider: "jina", providerOptions, schema: jinaEmbeddingOptions }); if (values.length > this.maxEmbeddingsPerCall) { throw new TooManyEmbeddingValuesForCallError({ maxEmbeddingsPerCall: this.maxEmbeddingsPerCall, modelId: this.modelId, provider: this.provider, values }); } const { responseHeaders, value: response } = await postJsonToApi({ abortSignal, body: { model: this.modelId, input: values, task: embeddingOptions?.inputType, embedding_type: embeddingOptions?.embeddingType, dimensions: embeddingOptions?.outputDimension, normalized: embeddingOptions?.normalized ?? true, late_chunking: embeddingOptions?.lateChunking, truncate: embeddingOptions?.truncate ?? false }, failedResponseHandler: voyageFailedResponseHandler, fetch: this.config.fetch, headers: combineHeaders(this.config.headers(), headers), successfulResponseHandler: createJsonResponseHandler( jinaEmbeddingResponseSchema ), url: `${this.config.baseURL}/embeddings` }); return { embeddings: response.data.map((item) => item.embedding), usage: response.usage ? { tokens: response.usage.total_tokens } : void 0, response: { headers: responseHeaders } }; } }; var jinaEmbeddingResponseSchema = z3.object({ data: z3.array( z3.object({ object: z3.literal("embedding"), embedding: z3.array(z3.number()), index: z3.number().optional() }) ), usage: z3.object({ total_tokens: z3.number(), prompt_tokens: z3.number().optional() }).nullish(), model: z3.string().optional() }); // src/jina-provider.ts function createJina(options = {}) { const baseURL = withoutTrailingSlash(options.baseURL) ?? "https://api.jina.ai/v1"; const getHeaders = () => ({ Authorization: `Bearer ${loadApiKey({ apiKey: options.apiKey, environmentVariableName: "JINA_API_KEY", description: "Jina" })}`, ...options.headers }); const createTextEmbeddingModel = (modelId) => new JinaEmbeddingModel(modelId, { provider: "jina.text.embedding", baseURL, headers: getHeaders, fetch: options.fetch }); const createMultiModalEmbeddingModel = (modelId) => new JinaEmbeddingModel(modelId, { provider: "jina.multimodal.embedding", baseURL, headers: getHeaders, fetch: options.fetch }); const provider = function(modelId) { if (new.target) { throw new Error( "The Jina model function cannot be called with the new keyword." ); } return createTextEmbeddingModel(modelId); }; provider.textEmbeddingModel = createTextEmbeddingModel; provider.multiModalEmbeddingModel = createMultiModalEmbeddingModel; provider.chat = provider.languageModel = () => { throw new Error("languageModel method is not implemented."); }; provider.imageModel = () => { throw new Error("imageModel method is not implemented."); }; return provider; } var jina = createJina(); export { createJina, jina }; //# sourceMappingURL=index.js.map