diff --git a/smart-embed-model/adapters/transformers_iframe.js b/smart-embed-model/adapters/transformers_iframe.js index 44b23e23..2dabe058 100644 --- a/smart-embed-model/adapters/transformers_iframe.js +++ b/smart-embed-model/adapters/transformers_iframe.js @@ -5,5 +5,14 @@ export class SmartEmbedTransformersIframeAdapter extends SmartEmbedIframeAdapter constructor(smart_embed) { super(smart_embed); this.connector = transformers_connector; + if(this.smart_embed.env.settings.legacy_transformers){ + this.connector = this.connector + .replace('@xenova/transformers', 'https://cdn.jsdelivr.net/npm/@xenova/transformers@2.17.2') + ; + this.smart_embed.opts.use_gpu = false; + } + else this.connector = this.connector + .replace('@xenova/transformers', 'https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.0.0-alpha.13') + ; } } \ No newline at end of file diff --git a/smart-embed-model/build/esbuild.js b/smart-embed-model/build/esbuild.js index 26134ca5..e474310a 100644 --- a/smart-embed-model/build/esbuild.js +++ b/smart-embed-model/build/esbuild.js @@ -19,7 +19,7 @@ async function build_transformers_iframe_connector() { const outputContent = result.outputFiles[0].text; const wrappedContent = `export const transformers_connector = ${JSON.stringify(outputContent)};` - .replace('@xenova/transformers', 'https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.0.0-alpha.13') + // .replace('@xenova/transformers', 'https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.0.0-alpha.13') // escape ${} // .replace(/\$\{([\w.]+)\}/g, '\\`+$1+\\`') ; diff --git a/smart-embed-model/connectors/transformers_iframe.js b/smart-embed-model/connectors/transformers_iframe.js index f8a2d74d..e76890ac 100644 --- a/smart-embed-model/connectors/transformers_iframe.js +++ b/smart-embed-model/connectors/transformers_iframe.js @@ -1 +1 @@ -export const transformers_connector = "// models.json\nvar models_default = {\n \"TaylorAI/bge-micro-v2\": {\n model_key: \"TaylorAI/bge-micro-v2\",\n batch_size: 1,\n dims: 384,\n max_tokens: 512,\n name: \"BGE-micro-v2\",\n description: \"Local, 512 tokens, 384 dim\",\n adapter: \"transformers\"\n },\n \"andersonbcdefg/bge-small-4096\": {\n model_key: \"andersonbcdefg/bge-small-4096\",\n batch_size: 1,\n dims: 384,\n max_tokens: 4096,\n name: \"BGE-small-4K\",\n description: \"Local, 4,096 tokens, 384 dim\",\n adapter: \"transformers\"\n },\n \"Xenova/jina-embeddings-v2-base-zh\": {\n model_key: \"Xenova/jina-embeddings-v2-base-zh\",\n batch_size: 1,\n dims: 512,\n max_tokens: 8192,\n name: \"Jina-v2-base-zh-8K\",\n description: \"Local, 8,192 tokens, 512 dim, Chinese/English bilingual\",\n adapter: \"transformers\"\n },\n \"text-embedding-3-small\": {\n model_key: \"text-embedding-3-small\",\n batch_size: 50,\n dims: 1536,\n max_tokens: 8191,\n name: \"OpenAI Text-3 Small\",\n description: \"API, 8,191 tokens, 1,536 dim\",\n endpoint: \"https://api.openai.com/v1/embeddings\",\n adapter: \"openai\"\n },\n \"text-embedding-3-large\": {\n model_key: \"text-embedding-3-large\",\n batch_size: 50,\n dims: 3072,\n max_tokens: 8191,\n name: \"OpenAI Text-3 Large\",\n description: \"API, 8,191 tokens, 3,072 dim\",\n endpoint: \"https://api.openai.com/v1/embeddings\",\n adapter: \"openai\"\n },\n \"text-embedding-3-small-512\": {\n model_key: \"text-embedding-3-small\",\n batch_size: 50,\n dims: 512,\n max_tokens: 8191,\n name: \"OpenAI Text-3 Small - 512\",\n description: \"API, 8,191 tokens, 512 dim\",\n endpoint: \"https://api.openai.com/v1/embeddings\",\n adapter: \"openai\"\n },\n \"text-embedding-3-large-256\": {\n model_key: \"text-embedding-3-large\",\n batch_size: 50,\n dims: 256,\n max_tokens: 8191,\n name: \"OpenAI Text-3 Large - 256\",\n description: \"API, 8,191 tokens, 256 dim\",\n endpoint: \"https://api.openai.com/v1/embeddings\",\n adapter: \"openai\"\n },\n \"text-embedding-ada-002\": {\n model_key: \"text-embedding-ada-002\",\n batch_size: 50,\n dims: 1536,\n max_tokens: 8191,\n name: \"OpenAI Ada\",\n description: \"API, 8,191 tokens, 1,536 dim\",\n endpoint: \"https://api.openai.com/v1/embeddings\",\n adapter: \"openai\"\n },\n \"Xenova/jina-embeddings-v2-small-en\": {\n model_key: \"Xenova/jina-embeddings-v2-small-en\",\n batch_size: 1,\n dims: 512,\n max_tokens: 8192,\n name: \"Jina-v2-small-en\",\n description: \"Local, 8,192 tokens, 512 dim\",\n adapter: \"transformers\"\n },\n \"nomic-ai/nomic-embed-text-v1.5\": {\n model_key: \"nomic-ai/nomic-embed-text-v1.5\",\n batch_size: 1,\n dims: 256,\n max_tokens: 8192,\n name: \"Nomic-embed-text-v1.5\",\n description: \"Local, 8,192 tokens, 256 dim\",\n adapter: \"transformers\"\n },\n \"Xenova/bge-small-en-v1.5\": {\n model_key: \"Xenova/bge-small-en-v1.5\",\n batch_size: 1,\n dims: 384,\n max_tokens: 512,\n name: \"BGE-small\",\n description: \"Local, 512 tokens, 384 dim\",\n adapter: \"transformers\"\n },\n \"nomic-ai/nomic-embed-text-v1\": {\n model_key: \"nomic-ai/nomic-embed-text-v1\",\n batch_size: 1,\n dims: 768,\n max_tokens: 2048,\n name: \"Nomic-embed-text\",\n description: \"Local, 2,048 tokens, 768 dim\",\n adapter: \"transformers\"\n }\n};\n\n// smart_embed_model.js\nvar SmartEmbedModel = class _SmartEmbedModel {\n /**\n * Create a SmartEmbed instance.\n * @param {string} env - The environment to use.\n * @param {object} opts - Full model configuration object or at least a model_key and adapter\n */\n constructor(env, opts = {}) {\n this.env = env;\n this.opts = {\n ...models_default[opts.embed_model_key],\n ...opts\n };\n console.log(this.opts);\n if (!this.opts.adapter)\n return console.warn(\"SmartEmbedModel adapter not set\");\n if (!this.env.opts.smart_embed_adapters[this.opts.adapter])\n return console.warn(`SmartEmbedModel adapter ${this.opts.adapter} not found`);\n this.opts.use_gpu = !!navigator.gpu && this.opts.gpu_batch_size !== 0;\n if (this.opts.use_gpu)\n this.opts.batch_size = this.opts.gpu_batch_size || 10;\n this.adapter = new this.env.opts.smart_embed_adapters[this.opts.adapter](this);\n }\n /**\n * Used to load a model with a given configuration.\n * @param {*} env \n * @param {*} opts \n */\n static async load(env, opts = {}) {\n try {\n const model2 = new _SmartEmbedModel(env, opts);\n await model2.adapter.load();\n env.smart_embed_active_models[opts.embed_model_key] = model2;\n return model2;\n } catch (error) {\n console.error(`Error loading model ${opts.model_key}:`, error);\n return null;\n }\n }\n /**\n * Count the number of tokens in the input string.\n * @param {string} input - The input string to process.\n * @returns {Promise} A promise that resolves with the number of tokens.\n */\n async count_tokens(input) {\n return this.adapter.count_tokens(input);\n }\n /**\n * Embed the input into a numerical array.\n * @param {string|Object} input - The input to embed. Can be a string or an object with an \"embed_input\" property.\n * @returns {Promise} A promise that resolves with an object containing the embedding vector at `vec` and the number of tokens at `tokens`.\n */\n async embed(input) {\n if (typeof input === \"string\")\n input = { embed_input: input };\n return (await this.embed_batch([input]))[0];\n }\n /**\n * Embed a batch of inputs into arrays of numerical arrays.\n * @param {Array} inputs - The array of inputs to embed. Each input can be a string or an object with an \"embed_input\" property.\n * @returns {Promise>} A promise that resolves with an array of objects containing `vec` and `tokens` properties.\n */\n async embed_batch(inputs) {\n return await this.adapter.embed_batch(inputs);\n }\n get batch_size() {\n return this.opts.batch_size || 1;\n }\n get max_tokens() {\n return this.opts.max_tokens || 512;\n }\n};\n\n// adapters/_adapter.js\nvar SmartEmbedAdapter = class {\n constructor(smart_embed) {\n this.smart_embed = smart_embed;\n }\n async load() {\n throw new Error(\"Not implemented\");\n }\n async count_tokens(input) {\n throw new Error(\"Not implemented\");\n }\n async embed(input) {\n throw new Error(\"Not implemented\");\n }\n async embed_batch(input) {\n throw new Error(\"Not implemented\");\n }\n};\n\n// adapters/transformers.js\nvar SmartEmbedTransformersAdapter = class extends SmartEmbedAdapter {\n constructor(smart_embed) {\n super(smart_embed);\n this.model = null;\n this.tokenizer = null;\n }\n get batch_size() {\n if (this.use_gpu && this.smart_embed.opts.gpu_batch_size)\n return this.smart_embed.opts.gpu_batch_size;\n return this.smart_embed.opts.batch_size || 1;\n }\n get max_tokens() {\n return this.smart_embed.opts.max_tokens || 512;\n }\n get use_gpu() {\n return this.smart_embed.opts.use_gpu || false;\n }\n async load() {\n const { pipeline, env, AutoTokenizer } = await import(\"https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.0.0-alpha.13\");\n env.allowLocalModels = false;\n const pipeline_opts = {\n quantized: true\n };\n if (this.use_gpu) {\n console.log(\"[Transformers] Using GPU\");\n pipeline_opts.device = \"webgpu\";\n pipeline_opts.dtype = \"fp32\";\n } else {\n console.log(\"[Transformers] Using CPU\");\n env.backends.onnx.wasm.numThreads = 8;\n }\n this.model = await pipeline(\"feature-extraction\", this.smart_embed.opts.model_key, pipeline_opts);\n this.tokenizer = await AutoTokenizer.from_pretrained(this.smart_embed.opts.model_key);\n }\n async count_tokens(input) {\n if (!this.tokenizer)\n await this.load();\n const { input_ids } = await this.tokenizer(input);\n return { tokens: input_ids.data.length };\n }\n async embed_batch(inputs) {\n if (!this.model)\n await this.load();\n const filtered_inputs = inputs.filter((item) => item.embed_input?.length > 0);\n if (!filtered_inputs.length)\n return [];\n if (filtered_inputs.length > this.batch_size) {\n throw new Error(`Input size (${filtered_inputs.length}) exceeds maximum batch size (${this.batch_size})`);\n }\n const tokens = await Promise.all(filtered_inputs.map((item) => this.count_tokens(item.embed_input)));\n const embed_inputs = await Promise.all(filtered_inputs.map(async (item, i) => {\n if (tokens[i].tokens < this.max_tokens)\n return item.embed_input;\n let token_ct = tokens[i].tokens;\n let truncated_input = item.embed_input;\n while (token_ct > this.max_tokens) {\n const pct = this.max_tokens / token_ct;\n const max_chars = Math.floor(truncated_input.length * pct * 0.9);\n truncated_input = truncated_input.substring(0, max_chars) + \"...\";\n token_ct = (await this.count_tokens(truncated_input)).tokens;\n }\n tokens[i].tokens = token_ct;\n return truncated_input;\n }));\n try {\n const resp = await this.model(embed_inputs, { pooling: \"mean\", normalize: true });\n return filtered_inputs.map((item, i) => {\n item.vec = Array.from(resp[i].data).map((val) => Math.round(val * 1e8) / 1e8);\n item.tokens = tokens[i].tokens;\n return item;\n });\n } catch (err) {\n console.error(\"error_embedding_batch\", err);\n return Promise.all(filtered_inputs.map((item) => this.embed(item.embed_input)));\n }\n }\n};\n\n// build/transformers_iframe_script.js\nvar model = null;\nvar smart_env = {\n smart_embed_active_models: {},\n opts: {\n smart_embed_adapters: {\n transformers: SmartEmbedTransformersAdapter\n }\n }\n};\nasync function processMessage(data) {\n const { method, params, id, iframe_id } = data;\n try {\n let result;\n switch (method) {\n case \"init\":\n console.log(\"init\");\n break;\n case \"load\":\n console.log(\"load\", params);\n model = await SmartEmbedModel.load(smart_env, { adapter: \"transformers\", model_key: params.model_key, ...params });\n result = { model_loaded: true };\n break;\n case \"embed_batch\":\n if (!model)\n throw new Error(\"Model not loaded\");\n result = await model.embed_batch(params.inputs);\n break;\n case \"count_tokens\":\n if (!model)\n throw new Error(\"Model not loaded\");\n result = await model.count_tokens(params);\n break;\n default:\n throw new Error(`Unknown method: ${method}`);\n }\n return { id, result, iframe_id };\n } catch (error) {\n console.error(\"Error processing message:\", error);\n return { id, error: error.message, iframe_id };\n }\n}\nprocessMessage({ method: \"init\" });\n"; \ No newline at end of file +export const transformers_connector = "// models.json\nvar models_default = {\n \"TaylorAI/bge-micro-v2\": {\n model_key: \"TaylorAI/bge-micro-v2\",\n batch_size: 1,\n dims: 384,\n max_tokens: 512,\n name: \"BGE-micro-v2\",\n description: \"Local, 512 tokens, 384 dim\",\n adapter: \"transformers\"\n },\n \"andersonbcdefg/bge-small-4096\": {\n model_key: \"andersonbcdefg/bge-small-4096\",\n batch_size: 1,\n dims: 384,\n max_tokens: 4096,\n name: \"BGE-small-4K\",\n description: \"Local, 4,096 tokens, 384 dim\",\n adapter: \"transformers\"\n },\n \"Xenova/jina-embeddings-v2-base-zh\": {\n model_key: \"Xenova/jina-embeddings-v2-base-zh\",\n batch_size: 1,\n dims: 512,\n max_tokens: 8192,\n name: \"Jina-v2-base-zh-8K\",\n description: \"Local, 8,192 tokens, 512 dim, Chinese/English bilingual\",\n adapter: \"transformers\"\n },\n \"text-embedding-3-small\": {\n model_key: \"text-embedding-3-small\",\n batch_size: 50,\n dims: 1536,\n max_tokens: 8191,\n name: \"OpenAI Text-3 Small\",\n description: \"API, 8,191 tokens, 1,536 dim\",\n endpoint: \"https://api.openai.com/v1/embeddings\",\n adapter: \"openai\"\n },\n \"text-embedding-3-large\": {\n model_key: \"text-embedding-3-large\",\n batch_size: 50,\n dims: 3072,\n max_tokens: 8191,\n name: \"OpenAI Text-3 Large\",\n description: \"API, 8,191 tokens, 3,072 dim\",\n endpoint: \"https://api.openai.com/v1/embeddings\",\n adapter: \"openai\"\n },\n \"text-embedding-3-small-512\": {\n model_key: \"text-embedding-3-small\",\n batch_size: 50,\n dims: 512,\n max_tokens: 8191,\n name: \"OpenAI Text-3 Small - 512\",\n description: \"API, 8,191 tokens, 512 dim\",\n endpoint: \"https://api.openai.com/v1/embeddings\",\n adapter: \"openai\"\n },\n \"text-embedding-3-large-256\": {\n model_key: \"text-embedding-3-large\",\n batch_size: 50,\n dims: 256,\n max_tokens: 8191,\n name: \"OpenAI Text-3 Large - 256\",\n description: \"API, 8,191 tokens, 256 dim\",\n endpoint: \"https://api.openai.com/v1/embeddings\",\n adapter: \"openai\"\n },\n \"text-embedding-ada-002\": {\n model_key: \"text-embedding-ada-002\",\n batch_size: 50,\n dims: 1536,\n max_tokens: 8191,\n name: \"OpenAI Ada\",\n description: \"API, 8,191 tokens, 1,536 dim\",\n endpoint: \"https://api.openai.com/v1/embeddings\",\n adapter: \"openai\"\n },\n \"Xenova/jina-embeddings-v2-small-en\": {\n model_key: \"Xenova/jina-embeddings-v2-small-en\",\n batch_size: 1,\n dims: 512,\n max_tokens: 8192,\n name: \"Jina-v2-small-en\",\n description: \"Local, 8,192 tokens, 512 dim\",\n adapter: \"transformers\"\n },\n \"nomic-ai/nomic-embed-text-v1.5\": {\n model_key: \"nomic-ai/nomic-embed-text-v1.5\",\n batch_size: 1,\n dims: 256,\n max_tokens: 8192,\n name: \"Nomic-embed-text-v1.5\",\n description: \"Local, 8,192 tokens, 256 dim\",\n adapter: \"transformers\"\n },\n \"Xenova/bge-small-en-v1.5\": {\n model_key: \"Xenova/bge-small-en-v1.5\",\n batch_size: 1,\n dims: 384,\n max_tokens: 512,\n name: \"BGE-small\",\n description: \"Local, 512 tokens, 384 dim\",\n adapter: \"transformers\"\n },\n \"nomic-ai/nomic-embed-text-v1\": {\n model_key: \"nomic-ai/nomic-embed-text-v1\",\n batch_size: 1,\n dims: 768,\n max_tokens: 2048,\n name: \"Nomic-embed-text\",\n description: \"Local, 2,048 tokens, 768 dim\",\n adapter: \"transformers\"\n }\n};\n\n// smart_embed_model.js\nvar SmartEmbedModel = class _SmartEmbedModel {\n /**\n * Create a SmartEmbed instance.\n * @param {string} env - The environment to use.\n * @param {object} opts - Full model configuration object or at least a model_key and adapter\n */\n constructor(env, opts = {}) {\n this.env = env;\n this.opts = {\n ...models_default[opts.embed_model_key],\n ...opts\n };\n console.log(this.opts);\n if (!this.opts.adapter) return console.warn(\"SmartEmbedModel adapter not set\");\n if (!this.env.opts.smart_embed_adapters[this.opts.adapter]) return console.warn(`SmartEmbedModel adapter ${this.opts.adapter} not found`);\n this.opts.use_gpu = !!navigator.gpu && this.opts.gpu_batch_size !== 0;\n if (this.opts.adapter === \"transformers\" && this.opts.use_gpu) this.opts.batch_size = this.opts.gpu_batch_size || 10;\n this.adapter = new this.env.opts.smart_embed_adapters[this.opts.adapter](this);\n }\n /**\n * Used to load a model with a given configuration.\n * @param {*} env \n * @param {*} opts \n */\n static async load(env, opts = {}) {\n try {\n const model2 = new _SmartEmbedModel(env, opts);\n await model2.adapter.load();\n env.smart_embed_active_models[opts.embed_model_key] = model2;\n return model2;\n } catch (error) {\n console.error(`Error loading model ${opts.model_key}:`, error);\n return null;\n }\n }\n /**\n * Count the number of tokens in the input string.\n * @param {string} input - The input string to process.\n * @returns {Promise} A promise that resolves with the number of tokens.\n */\n async count_tokens(input) {\n return this.adapter.count_tokens(input);\n }\n /**\n * Embed the input into a numerical array.\n * @param {string|Object} input - The input to embed. Can be a string or an object with an \"embed_input\" property.\n * @returns {Promise} A promise that resolves with an object containing the embedding vector at `vec` and the number of tokens at `tokens`.\n */\n async embed(input) {\n if (typeof input === \"string\") input = { embed_input: input };\n return (await this.embed_batch([input]))[0];\n }\n /**\n * Embed a batch of inputs into arrays of numerical arrays.\n * @param {Array} inputs - The array of inputs to embed. Each input can be a string or an object with an \"embed_input\" property.\n * @returns {Promise>} A promise that resolves with an array of objects containing `vec` and `tokens` properties.\n */\n async embed_batch(inputs) {\n return await this.adapter.embed_batch(inputs);\n }\n get batch_size() {\n return this.opts.batch_size || 1;\n }\n get max_tokens() {\n return this.opts.max_tokens || 512;\n }\n};\n\n// adapters/_adapter.js\nvar SmartEmbedAdapter = class {\n constructor(smart_embed) {\n this.smart_embed = smart_embed;\n }\n async load() {\n throw new Error(\"Not implemented\");\n }\n async count_tokens(input) {\n throw new Error(\"Not implemented\");\n }\n async embed(input) {\n throw new Error(\"Not implemented\");\n }\n async embed_batch(input) {\n throw new Error(\"Not implemented\");\n }\n};\n\n// adapters/transformers.js\nvar SmartEmbedTransformersAdapter = class extends SmartEmbedAdapter {\n constructor(smart_embed) {\n super(smart_embed);\n this.model = null;\n this.tokenizer = null;\n }\n get batch_size() {\n if (this.use_gpu && this.smart_embed.opts.gpu_batch_size) return this.smart_embed.opts.gpu_batch_size;\n return this.smart_embed.opts.batch_size || 1;\n }\n get max_tokens() {\n return this.smart_embed.opts.max_tokens || 512;\n }\n get use_gpu() {\n return this.smart_embed.opts.use_gpu || false;\n }\n async load() {\n const { pipeline, env, AutoTokenizer } = await import(\"@xenova/transformers\");\n env.allowLocalModels = false;\n const pipeline_opts = {\n quantized: true\n };\n if (this.use_gpu) {\n console.log(\"[Transformers] Using GPU\");\n pipeline_opts.device = \"webgpu\";\n pipeline_opts.dtype = \"fp32\";\n } else {\n console.log(\"[Transformers] Using CPU\");\n env.backends.onnx.wasm.numThreads = 8;\n }\n this.model = await pipeline(\"feature-extraction\", this.smart_embed.opts.model_key, pipeline_opts);\n this.tokenizer = await AutoTokenizer.from_pretrained(this.smart_embed.opts.model_key);\n }\n async count_tokens(input) {\n if (!this.tokenizer) await this.load();\n const { input_ids } = await this.tokenizer(input);\n return { tokens: input_ids.data.length };\n }\n async embed_batch(inputs) {\n if (!this.model) await this.load();\n const filtered_inputs = inputs.filter((item) => item.embed_input?.length > 0);\n if (!filtered_inputs.length) return [];\n if (filtered_inputs.length > this.batch_size) {\n throw new Error(`Input size (${filtered_inputs.length}) exceeds maximum batch size (${this.batch_size})`);\n }\n const tokens = await Promise.all(filtered_inputs.map((item) => this.count_tokens(item.embed_input)));\n const embed_inputs = await Promise.all(filtered_inputs.map(async (item, i) => {\n if (tokens[i].tokens < this.max_tokens) return item.embed_input;\n let token_ct = tokens[i].tokens;\n let truncated_input = item.embed_input;\n while (token_ct > this.max_tokens) {\n const pct = this.max_tokens / token_ct;\n const max_chars = Math.floor(truncated_input.length * pct * 0.9);\n truncated_input = truncated_input.substring(0, max_chars) + \"...\";\n token_ct = (await this.count_tokens(truncated_input)).tokens;\n }\n tokens[i].tokens = token_ct;\n return truncated_input;\n }));\n try {\n const resp = await this.model(embed_inputs, { pooling: \"mean\", normalize: true });\n return filtered_inputs.map((item, i) => {\n item.vec = Array.from(resp[i].data).map((val) => Math.round(val * 1e8) / 1e8);\n item.tokens = tokens[i].tokens;\n return item;\n });\n } catch (err) {\n console.error(\"error_embedding_batch\", err);\n return Promise.all(filtered_inputs.map((item) => this.embed(item.embed_input)));\n }\n }\n};\n\n// build/transformers_iframe_script.js\nvar model = null;\nvar smart_env = {\n smart_embed_active_models: {},\n opts: {\n smart_embed_adapters: {\n transformers: SmartEmbedTransformersAdapter\n }\n }\n};\nasync function processMessage(data) {\n const { method, params, id, iframe_id } = data;\n try {\n let result;\n switch (method) {\n case \"init\":\n console.log(\"init\");\n break;\n case \"load\":\n console.log(\"load\", params);\n model = await SmartEmbedModel.load(smart_env, { adapter: \"transformers\", model_key: params.model_key, ...params });\n result = { model_loaded: true };\n break;\n case \"embed_batch\":\n if (!model) throw new Error(\"Model not loaded\");\n result = await model.embed_batch(params.inputs);\n break;\n case \"count_tokens\":\n if (!model) throw new Error(\"Model not loaded\");\n result = await model.count_tokens(params);\n break;\n default:\n throw new Error(`Unknown method: ${method}`);\n }\n return { id, result, iframe_id };\n } catch (error) {\n console.error(\"Error processing message:\", error);\n return { id, error: error.message, iframe_id };\n }\n}\nprocessMessage({ method: \"init\" });\n"; \ No newline at end of file diff --git a/smart-embed-model/connectors/transformers_worker.js b/smart-embed-model/connectors/transformers_worker.js index 75c6a1aa..0ba6bdba 100644 --- a/smart-embed-model/connectors/transformers_worker.js +++ b/smart-embed-model/connectors/transformers_worker.js @@ -129,13 +129,10 @@ var SmartEmbedModel = class _SmartEmbedModel { ...opts }; console.log(this.opts); - if (!this.opts.adapter) - return console.warn("SmartEmbedModel adapter not set"); - if (!this.env.opts.smart_embed_adapters[this.opts.adapter]) - return console.warn(`SmartEmbedModel adapter ${this.opts.adapter} not found`); + if (!this.opts.adapter) return console.warn("SmartEmbedModel adapter not set"); + if (!this.env.opts.smart_embed_adapters[this.opts.adapter]) return console.warn(`SmartEmbedModel adapter ${this.opts.adapter} not found`); this.opts.use_gpu = !!navigator.gpu && this.opts.gpu_batch_size !== 0; - if (this.opts.use_gpu) - this.opts.batch_size = this.opts.gpu_batch_size || 10; + if (this.opts.adapter === "transformers" && this.opts.use_gpu) this.opts.batch_size = this.opts.gpu_batch_size || 10; this.adapter = new this.env.opts.smart_embed_adapters[this.opts.adapter](this); } /** @@ -168,8 +165,7 @@ var SmartEmbedModel = class _SmartEmbedModel { * @returns {Promise} A promise that resolves with an object containing the embedding vector at `vec` and the number of tokens at `tokens`. */ async embed(input) { - if (typeof input === "string") - input = { embed_input: input }; + if (typeof input === "string") input = { embed_input: input }; return (await this.embed_batch([input]))[0]; } /** @@ -215,8 +211,7 @@ var SmartEmbedTransformersAdapter = class extends SmartEmbedAdapter { this.tokenizer = null; } get batch_size() { - if (this.use_gpu && this.smart_embed.opts.gpu_batch_size) - return this.smart_embed.opts.gpu_batch_size; + if (this.use_gpu && this.smart_embed.opts.gpu_batch_size) return this.smart_embed.opts.gpu_batch_size; return this.smart_embed.opts.batch_size || 1; } get max_tokens() { @@ -243,24 +238,20 @@ var SmartEmbedTransformersAdapter = class extends SmartEmbedAdapter { this.tokenizer = await AutoTokenizer.from_pretrained(this.smart_embed.opts.model_key); } async count_tokens(input) { - if (!this.tokenizer) - await this.load(); + if (!this.tokenizer) await this.load(); const { input_ids } = await this.tokenizer(input); return { tokens: input_ids.data.length }; } async embed_batch(inputs) { - if (!this.model) - await this.load(); + if (!this.model) await this.load(); const filtered_inputs = inputs.filter((item) => item.embed_input?.length > 0); - if (!filtered_inputs.length) - return []; + if (!filtered_inputs.length) return []; if (filtered_inputs.length > this.batch_size) { throw new Error(`Input size (${filtered_inputs.length}) exceeds maximum batch size (${this.batch_size})`); } const tokens = await Promise.all(filtered_inputs.map((item) => this.count_tokens(item.embed_input))); const embed_inputs = await Promise.all(filtered_inputs.map(async (item, i) => { - if (tokens[i].tokens < this.max_tokens) - return item.embed_input; + if (tokens[i].tokens < this.max_tokens) return item.embed_input; let token_ct = tokens[i].tokens; let truncated_input = item.embed_input; while (token_ct > this.max_tokens) { @@ -307,13 +298,11 @@ async function process_message(data) { result = { model_loaded: true }; break; case "embed_batch": - if (!model) - throw new Error("Model not loaded"); + if (!model) throw new Error("Model not loaded"); result = await model.embed_batch(params.inputs); break; case "count_tokens": - if (!model) - throw new Error("Model not loaded"); + if (!model) throw new Error("Model not loaded"); result = await model.count_tokens(params); break; default: