diff --git a/smart-embed-model/adapters/transformers.js b/smart-embed-model/adapters/transformers.js index 35b9c7ce..e824853e 100644 --- a/smart-embed-model/adapters/transformers.js +++ b/smart-embed-model/adapters/transformers.js @@ -69,7 +69,7 @@ export class SmartEmbedTransformersAdapter extends SmartEmbedAdapter { * @returns {Promise} */ async load_transformers() { - const { pipeline, env, AutoTokenizer } = await import('@xenova/transformers'); + const { pipeline, env, AutoTokenizer } = await import('@huggingface/transformers'); env.allowLocalModels = false; const pipeline_opts = { diff --git a/smart-embed-model/adapters/transformers_iframe.js b/smart-embed-model/adapters/transformers_iframe.js index 370a444f..791ba21a 100644 --- a/smart-embed-model/adapters/transformers_iframe.js +++ b/smart-embed-model/adapters/transformers_iframe.js @@ -28,12 +28,12 @@ export class SmartEmbedTransformersIframeAdapter extends SmartEmbedIframeAdapter this.connector = transformers_connector; if(this.settings.legacy_transformers || !this.use_gpu){ this.connector = this.connector - .replace('@xenova/transformers', 'https://cdn.jsdelivr.net/npm/@xenova/transformers@2.17.2') + .replace('@huggingface/transformers', 'https://cdn.jsdelivr.net/npm/@xenova/transformers@2.17.2') ; this.use_gpu = false; } else this.connector = this.connector - .replace('@xenova/transformers', 'https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.1.1') + .replace('@huggingface/transformers', 'https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.1.2') ; } diff --git a/smart-embed-model/build/esbuild.js b/smart-embed-model/build/esbuild.js index 295bb5c8..f5538281 100644 --- a/smart-embed-model/build/esbuild.js +++ b/smart-embed-model/build/esbuild.js @@ -14,7 +14,7 @@ async function build_transformers_iframe_connector() { target: 'es2020', outfile: join(__dirname, '../connectors/transformers_iframe.js'), write: false, - external: ['@xenova/transformers'], + external: ['@huggingface/transformers'], }); const outputContent = result.outputFiles[0].text; @@ -37,11 +37,11 @@ async function build_transformers_worker_connector() { target: 'es2020', outfile: join(__dirname, '../connectors/transformers_worker.js'), write: false, - external: ['@xenova/transformers'], + external: ['@huggingface/transformers'], }); const connector = result.outputFiles[0].text - .replace('@xenova/transformers', 'https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.1.1') + .replace('@huggingface/transformers', 'https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.1.2') ; writeFileSync(join(__dirname, '../connectors/transformers_worker.js'), connector); console.log('Build worker completed successfully.'); diff --git a/smart-embed-model/connectors/transformers_worker.js b/smart-embed-model/connectors/transformers_worker.js index e4a1fc51..35a9c6d8 100644 --- a/smart-embed-model/connectors/transformers_worker.js +++ b/smart-embed-model/connectors/transformers_worker.js @@ -736,7 +736,7 @@ var SmartEmbedTransformersAdapter = class extends SmartEmbedAdapter { * @returns {Promise} */ async load_transformers() { - const { pipeline, env, AutoTokenizer } = await import("https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.1.1"); + const { pipeline, env, AutoTokenizer } = await import("https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.1.2"); env.allowLocalModels = false; const pipeline_opts = { quantized: true diff --git a/smart-entities/smart_entities.js b/smart-entities/smart_entities.js index 88abc059..b24233e1 100644 --- a/smart-entities/smart_entities.js +++ b/smart-entities/smart_entities.js @@ -542,9 +542,9 @@ export class SmartEntities extends Collection { */ export const settings_config = { "min_chars": { - name: 'Minimum length of entity to embed', + name: 'Minimum length', type: "number", - description: "Minimum length of entity to embed.", + description: "Minimum length of entity to embed (in characters).", placeholder: "Enter number ex. 300", default: 300, }, diff --git a/smart-instruct-model/README.md b/smart-instruct-model/README.md deleted file mode 100644 index f87f5c14..00000000 --- a/smart-instruct-model/README.md +++ /dev/null @@ -1 +0,0 @@ -# TODO \ No newline at end of file diff --git a/smart-instruct-model/package.json b/smart-instruct-model/package.json deleted file mode 100644 index b1678eb8..00000000 --- a/smart-instruct-model/package.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "name": "smart-instruct-model", - "author": "Brian Joseph Petro (🌴 Brian)", - "license": "MIT", - "version": "1.0.3", - "description": "Simple instruct models", - "main": "smart_instruct_model.js", - "scripts": { - "test": "npx ava" - }, - "repository": { - "type": "git", - "url": "brianpetro/jsbrains" - }, - "keywords": [ - "AI", - "chat", - "models", - "universal", - "adapter" - ], - "bugs": { - "url": "https://github.com/brianpetro/jsbrains/issues" - }, - "homepage": "https://jsbrains.org", - "devDependencies": { - "ava": "^6.1.2", - "esbuild": "^0.20.2" - } -} diff --git a/smart-instruct-model/smart_instruct_model.js b/smart-instruct-model/smart_instruct_model.js deleted file mode 100644 index 0d0a05ef..00000000 --- a/smart-instruct-model/smart_instruct_model.js +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright (c) Brian Joseph Petro - -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: - -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. - -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -const { SmartStreamer } = require('./streamer'); -// const { getEncoding } = require("js-tiktoken"); -// const { SmartChatModel } = require('../smart-chat-model'); - -class SmartInstructModel { - constructor(opts={}) { - // this.main = main; - this.config = { - ...opts, - } - this.active_stream = null; - this._request_adapter = opts.request_adapter || null; - // this.tokenizer = getEncoding("cl100k_base"); - } - async complete(opts={}, done_handler=null) { - const req = await this.prepare_request(opts); - req.url = "https://api.openai.com/v1/completions"; - req.throw = false; - console.log(req); - try { - const resp = await this.request(req); - console.log(resp); - const json = await this.get_resp(resp); - console.log(json); - if(json.error) { - console.error(json.error); - return done_handler("*API Error. See console logs for details.*"); - } - if(done_handler) done_handler(this.get_message_content(json)); - return this.get_message_content(json); - // console.log(response); - } catch (err) { - console.error(err); - // new Notice(`Smart Connections API Error :: ${err}`); - } - } - get_message(json) { return json.choices[0].message; } - get_message_content(json) { return this.get_message(json).content; } - prepare_request_body(opts) { - if(!opts.model) opts.model = this.model_name; - if(this.max_output_tokens) opts.max_tokens = this.max_output_tokens; - return opts; - } - async prepare_request(opts) { - opts = JSON.parse(JSON.stringify(opts)); - // opts = await this.main.request_middlewares(opts); - const req = { - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${this.api_key}` - }, - method: "POST", - body: JSON.stringify(this.prepare_request_body(opts)) - }; - if (this.config.headers) req.headers = { ...req.headers, ...this.config.headers }; - if (this.config.api_key_header) { - if(this.config.api_key_header !== 'none') req.headers[this.config.api_key_header] = this.api_key; - delete req.headers.Authorization; - } - return req; - } - - async request(opts){ return await this.request_adapter(opts); } - // handle fallback to fetch (allows for overwriting in child classes) - async get_resp(resp) { return (typeof resp.json === 'function') ? await resp.json() : await resp.json; } - get request_adapter(){ return this._request_adapter || fetch; } - - async stream(opts, done_handler=this.done_handler.bind(this), chunk_handler=this.chunk_handler.bind(this)) { - if(!opts.stream) opts.stream = true; - const req = await this.prepare_request(opts); - const full_str = await new Promise((resolve, reject) => { - try { - // console.log("stream", opts); - this.active_stream = new SmartStreamer("https://api.openai.com/v1/completions", req); - let curr_text = ""; - this.active_stream.addEventListener("message", (e) => { - // console.log(e); - if(e.data === "[DONE]") { - // this.end_stream(); - this.stop_stream(); - return resolve(curr_text); - } - let resp = null; - let text_chunk = ''; - // DO: is this try/catch still necessary? - try { - resp = JSON.parse(e.data); - // text_chunk = resp.choices[0].delta.content; - text_chunk = resp.choices[0].text; - } catch (err) { - console.log(err); - console.log(e.data); - if (e.data.indexOf('}{') > -1) e.data = e.data.replace(/}{/g, '},{'); - resp = JSON.parse(`[${e.data}]`); - resp.forEach((r) => { - // if (r.choices) text_chunk += r.choices[0].delta.content; - if (r.choices) text_chunk += r.choices[0].text; - }); - } - if(!text_chunk) return; - curr_text += text_chunk; - if(chunk_handler) chunk_handler(text_chunk); // call the chunk handler if it exists - else done_handler(curr_text); // else call the done handler (less efficient) - }); - // unnecessary? - this.active_stream.addEventListener("readystatechange", (e) => { - if (e.readyState >= 2) console.log("ReadyState: " + e.readyState); - }); - this.active_stream.addEventListener("error", (e) => { - console.error(e); - // new Notice("Smart Connections Error Streaming Response. See console for details."); - done_handler("*API Error. See console logs for details.*"); - // this.end_stream(); - this.stop_stream(); - reject(e); - }); - this.active_stream.stream(); - } catch (err) { - console.error(err); - // new Notice("Smart Connections Error Streaming Response. See console for details."); - // this.end_stream(); - this.stop_stream(); - reject(err); - } - }); - // console.log(full_str); - done_handler(full_str); - } - - done_handler(full_str) { console.log(full_str); } - chunk_handler(text_chunk) { console.log(text_chunk); } - async count_tokens(input) { - if(typeof this.adapter?.count_tokens === 'function') return await this.adapter.count_tokens(input); - return this.estimate_tokens(input); - } - estimate_tokens(input) { - if(typeof this.adapter?.estimate_tokens === 'function') return this.adapter.estimate_tokens(input); - if(typeof input === 'object') input = JSON.stringify(input); - return input.length / 4; - } - // getters - get model_name() { return "gpt-3.5-turbo-instruct"; } -} -exports.SmartInstructModel = SmartInstructModel; \ No newline at end of file diff --git a/smart-instruct-model/streamer.js b/smart-instruct-model/streamer.js deleted file mode 100644 index 178b983e..00000000 --- a/smart-instruct-model/streamer.js +++ /dev/null @@ -1,181 +0,0 @@ -class SmartStreamer { - constructor(url, options = {}) { - const { - method = 'GET', - headers = {}, - body = null, - withCredentials = false - } = options; - - this.url = url; - this.method = method; - this.headers = headers; - this.body = body; - this.withCredentials = withCredentials; - this.listeners = {}; - this.readyState = this.CONNECTING; - this.progress = 0; - this.chunk = ''; - this.last_event_id = ''; - this.xhr = null; - this.FIELD_SEPARATOR = ':'; - this.INITIALIZING = -1; - this.CONNECTING = 0; - this.OPEN = 1; - this.CLOSED = 2; - } - - /** - * Adds an event listener for the specified event type. - * - * @param {string} type - The type of the event. - * @param {Function} listener - The listener function to be called when the event is triggered. - */ - addEventListener(type, listener) { - if (!this.listeners[type]) this.listeners[type] = []; - if (!this.listeners[type].includes(listener)) this.listeners[type].push(listener); - } - - /** - * Removes an event listener from the SmartStreamer instance. - * - * @param {string} type - The type of event to remove the listener from. - * @param {Function} listener - The listener function to remove. - */ - removeEventListener(type, listener) { - if (!this.listeners[type]) return; - this.listeners[type] = this.listeners[type].filter((callback) => callback !== listener); - if (this.listeners[type].length === 0) delete this.listeners[type]; - } - - /** - * Dispatches an event to the appropriate event handlers. - * - * @param {Event} event - The event to be dispatched. - * @returns {boolean} - Returns true if the event was successfully dispatched, false otherwise. - */ - dispatchEvent(event) { - if (!event) return true; - event.source = this; - const onHandler = 'on' + event.type; - if (Object.prototype.hasOwnProperty.call(this, onHandler)) { - this[onHandler].call(this, event); - if (event.defaultPrevented) return false; - } - if (this.listeners[event.type]) { - this.listeners[event.type].forEach((callback) => { - callback(event); - return !event.defaultPrevented; - }); - } - return true; - } - - /** - * Initiates the streaming process. - */ - stream() { - this.#setReadyState(this.CONNECTING); - this.xhr = new XMLHttpRequest(); - this.xhr.addEventListener('progress', this.#onStreamProgress.bind(this)); - this.xhr.addEventListener('load', this.#onStreamLoaded.bind(this)); - this.xhr.addEventListener('readystatechange', this.#checkStreamClosed.bind(this)); - this.xhr.addEventListener('error', this.#onStreamFailure.bind(this)); - this.xhr.addEventListener('abort', this.#onStreamAbort.bind(this)); - this.xhr.open(this.method, this.url); - for (const header in this.headers) { - this.xhr.setRequestHeader(header, this.headers[header]); - } - if (this.last_event_id) this.xhr.setRequestHeader('Last-Event-ID', this.last_event_id); - this.xhr.withCredentials = this.withCredentials; - this.xhr.send(this.body); - } - /** - * Ends the streamer connection. - * Aborts the current XHR request and sets the ready state to CLOSED. - */ - end() { - if (this.readyState === this.CLOSED) return; - this.xhr.abort(); - this.xhr = null; - this.#setReadyState(this.CLOSED); - } - - // private methods - #setReadyState(state) { - const event = new CustomEvent('readyStateChange'); - event.readyState = state; - this.readyState = state; - this.dispatchEvent(event); - } - #onStreamFailure(e) { - const event = new CustomEvent('error'); - event.data = e.currentTarget.response; - this.dispatchEvent(event); - this.end(); - } - #onStreamAbort(e) { - const event = new CustomEvent('abort'); - this.end(); - } - #onStreamProgress(e) { - if (!this.xhr) return; - if (this.xhr.status !== 200) { - this.#onStreamFailure(e); - return; - } - if (this.readyState === this.CONNECTING) { - this.dispatchEvent(new CustomEvent('open')); - this.#setReadyState(this.OPEN); - } - const data = this.xhr.responseText.substring(this.progress); - this.progress += data.length; - // data.split(/(\r\n|\r|\n){2}/g).forEach((part) => { - data.split(/(\r\n|\r|\n)/g).forEach((part) => { - if (part.trim().length === 0) { - this.dispatchEvent(this.#parseEventChunk(this.chunk.trim())); - this.chunk = ''; - } else { - this.chunk += part; - } - }); - } - #onStreamLoaded(e) { - this.#onStreamProgress(e); - this.dispatchEvent(this.#parseEventChunk(this.chunk)); - this.chunk = ''; - } - #parseEventChunk(chunk) { - if (!chunk || chunk.length === 0) return null; - const e = { id: null, retry: null, data: '', event: 'message', text: '' }; - chunk.split(/(\r\n|\r|\n)/).forEach((line) => { - // line = line.trimRight(); - line = line.trim(); - const index = line.indexOf(this.FIELD_SEPARATOR); - if (index <= 0) return; - // const field = line.substring(0, index); - // also remove quotes - const field = line.substring(0, index).replace(/^"|"$/g, ''); - if(!['id', 'retry', 'data', 'event', 'text'].includes(field)) return; - // if (!(field in e)) return; - // const value = line.substring(index + 1).trimLeft(); - const value = line.substring(index + 1).trim().replace(/^"|"$/g, ''); - // if (field === 'data') e[field] += value; - // else e[field] = value; - e.data += value; - }); - if (e.id) this.last_event_id = e.id; - const event = new CustomEvent(e.event || 'message'); - event.id = e.id; - event.data = e.data || ''; - event.last_event_id = this.last_event_id; - return event; - } - #checkStreamClosed() { - if (!this.xhr) return; - if (this.xhr.readyState === XMLHttpRequest.DONE) this.#setReadyState(this.CLOSED); - } - -} - -exports.SmartStreamer = SmartStreamer; diff --git a/smart-rank-model/build/esbuild.js b/smart-rank-model/build/esbuild.js index d3d8ffd3..b48c88ac 100644 --- a/smart-rank-model/build/esbuild.js +++ b/smart-rank-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('@huggingface/transformers', 'https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.1.1') + .replace('@huggingface/transformers', 'https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.1.2') // escape ${} // .replace(/\$\{([\w.]+)\}/g, '\\`+$1+\\`') ; @@ -44,7 +44,7 @@ async function build_transformers_worker_connector() { }); const connector = result.outputFiles[0].text - .replace('@huggingface/transformers', 'https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.1.1') + .replace('@huggingface/transformers', 'https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.1.2') ; writeFileSync(join(__dirname, '../connectors/transformers_worker.js'), connector); console.log('Build transformers_worker_connector completed successfully.'); diff --git a/smart-rank-model/connectors/transformers_iframe.js b/smart-rank-model/connectors/transformers_iframe.js index 55bd3f66..18aa179f 100644 --- a/smart-rank-model/connectors/transformers_iframe.js +++ b/smart-rank-model/connectors/transformers_iframe.js @@ -1 +1 @@ -export const transformers_connector = "var __defProp = Object.defineProperty;\nvar __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;\nvar __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== \"symbol\" ? key + \"\" : key, value);\n\n// ../smart-model/smart_model.js\nvar SmartModel = class {\n /**\n * Create a SmartModel instance.\n * @param {Object} opts - Configuration options\n * @param {Object} opts.adapters - Map of adapter names to adapter classes\n * @param {Object} opts.settings - Model settings configuration\n * @param {Object} opts.model_config - Model-specific configuration\n * @param {string} opts.model_config.adapter - Name of the adapter to use\n * @param {string} [opts.model_key] - Optional model identifier to override settings\n * @throws {Error} If required options are missing\n */\n constructor(opts = {}) {\n __publicField(this, \"scope_name\", \"smart_model\");\n this.opts = opts;\n this.validate_opts(opts);\n this.state = \"unloaded\";\n this._adapter = null;\n }\n /**\n * Initialize the model by loading the configured adapter.\n * @async\n * @returns {Promise}\n */\n async initialize() {\n this.load_adapter(this.adapter_name);\n await this.load();\n }\n /**\n * Validate required options.\n * @param {Object} opts - Configuration options\n */\n validate_opts(opts) {\n if (!opts.adapters) throw new Error(\"opts.adapters is required\");\n if (!opts.settings) throw new Error(\"opts.settings is required\");\n }\n /**\n * Get the current settings\n * @returns {Object} Current settings\n */\n get settings() {\n if (!this.opts.settings) this.opts.settings = {\n ...this.constructor.defaults\n };\n return this.opts.settings;\n }\n /**\n * Get the current adapter name\n * @returns {string} Current adapter name\n */\n get adapter_name() {\n const adapter_key = this.opts.model_config?.adapter || this.opts.adapter || this.settings.adapter || Object.keys(this.adapters)[0];\n if (!adapter_key || !this.adapters[adapter_key]) throw new Error(`Platform \"${adapter_key}\" not supported`);\n return adapter_key;\n }\n /**\n * Get adapter-specific settings.\n * @returns {Object} Settings for current adapter\n */\n get adapter_settings() {\n if (!this.settings[this.adapter_name]) this.settings[this.adapter_name] = {};\n return this.settings[this.adapter_name];\n }\n get adapter_config() {\n const base_config = this.adapters[this.adapter_name]?.defaults || {};\n return {\n ...base_config,\n ...this.adapter_settings,\n ...this.opts.adapter_config\n };\n }\n /**\n * Get available models.\n * @returns {Object} Map of model objects\n */\n get models() {\n return this.adapter.models;\n }\n /**\n * Get the default model key to use\n * @returns {string} Default model identifier\n */\n get default_model_key() {\n throw new Error(\"default_model_key must be overridden in sub-class\");\n }\n /**\n * Get the current model key\n * @returns {string} Current model key\n */\n get model_key() {\n return this.opts.model_key || this.adapter_config.model_key || this.settings.model_key || this.default_model_key;\n }\n /**\n * Get the current model configuration\n * @returns {Object} Combined base and custom model configuration\n */\n get model_config() {\n const model_key = this.model_key;\n const base_model_config = this.models[model_key] || {};\n return {\n ...this.adapter_config,\n ...base_model_config,\n ...this.opts.model_config\n };\n }\n get model_settings() {\n if (!this.settings[this.model_key]) this.settings[this.model_key] = {};\n return this.settings[this.model_key];\n }\n /**\n * Load the current adapter and transition to loaded state.\n * @async\n * @returns {Promise}\n */\n async load() {\n this.set_state(\"loading\");\n if (!this.adapter?.loaded) {\n await this.invoke_adapter_method(\"load\");\n }\n this.set_state(\"loaded\");\n }\n /**\n * Unload the current adapter and transition to unloaded state.\n * @async\n * @returns {Promise}\n */\n async unload() {\n if (this.adapter?.loaded) {\n this.set_state(\"unloading\");\n await this.invoke_adapter_method(\"unload\");\n this.set_state(\"unloaded\");\n }\n }\n /**\n * Set the model's state.\n * @param {('unloaded'|'loading'|'loaded'|'unloading')} new_state - The new state\n * @throws {Error} If the state is invalid\n */\n set_state(new_state) {\n const valid_states = [\"unloaded\", \"loading\", \"loaded\", \"unloading\"];\n if (!valid_states.includes(new_state)) {\n throw new Error(`Invalid state: ${new_state}`);\n }\n this.state = new_state;\n }\n get is_loading() {\n return this.state === \"loading\";\n }\n get is_loaded() {\n return this.state === \"loaded\";\n }\n get is_unloading() {\n return this.state === \"unloading\";\n }\n get is_unloaded() {\n return this.state === \"unloaded\";\n }\n // ADAPTERS\n /**\n * Get the map of available adapters\n * @returns {Object} Map of adapter names to adapter classes\n */\n get adapters() {\n return this.opts.adapters || {};\n }\n /**\n * Load a specific adapter by name.\n * @async\n * @param {string} adapter_name - Name of the adapter to load\n * @throws {Error} If adapter not found or loading fails\n * @returns {Promise}\n */\n async load_adapter(adapter_name) {\n this.set_adapter(adapter_name);\n if (!this._adapter.loaded) {\n this.set_state(\"loading\");\n try {\n await this.invoke_adapter_method(\"load\");\n this.set_state(\"loaded\");\n } catch (err) {\n this.set_state(\"unloaded\");\n throw new Error(`Failed to load adapter: ${err.message}`);\n }\n }\n }\n /**\n * Set an adapter instance by name without loading it.\n * @param {string} adapter_name - Name of the adapter to set\n * @throws {Error} If adapter not found\n */\n set_adapter(adapter_name) {\n const AdapterClass = this.adapters[adapter_name];\n if (!AdapterClass) {\n throw new Error(`Adapter \"${adapter_name}\" not found.`);\n }\n if (this._adapter?.constructor.name.toLowerCase() === adapter_name.toLowerCase()) {\n return;\n }\n this._adapter = new AdapterClass(this);\n }\n /**\n * Get the current active adapter instance\n * @returns {Object} The active adapter instance\n * @throws {Error} If adapter not found\n */\n get adapter() {\n const adapter_name = this.adapter_name;\n if (!adapter_name) {\n throw new Error(`Adapter not set for model.`);\n }\n if (!this._adapter) {\n this.load_adapter(adapter_name);\n }\n return this._adapter;\n }\n /**\n * Ensure the adapter is ready to execute a method.\n * @param {string} method - Name of the method to check\n * @throws {Error} If adapter not loaded or method not implemented\n */\n ensure_adapter_ready(method) {\n if (!this.adapter) {\n throw new Error(\"No adapter loaded.\");\n }\n if (typeof this.adapter[method] !== \"function\") {\n throw new Error(`Adapter does not implement method: ${method}`);\n }\n }\n /**\n * Invoke a method on the current adapter.\n * @async\n * @param {string} method - Name of the method to call\n * @param {...any} args - Arguments to pass to the method\n * @returns {Promise} Result from the adapter method\n * @throws {Error} If adapter not ready or method fails\n */\n async invoke_adapter_method(method, ...args) {\n this.ensure_adapter_ready(method);\n return await this.adapter[method](...args);\n }\n /**\n * Get platforms as dropdown options.\n * @returns {Array} Array of {value, name} option objects\n */\n get_platforms_as_options() {\n console.log(\"get_platforms_as_options\", this.adapters);\n return Object.entries(this.adapters).map(([key, AdapterClass]) => ({ value: key, name: AdapterClass.defaults.description || key }));\n }\n // SETTINGS\n /**\n * Get the settings configuration schema\n * @returns {Object} Settings configuration object\n */\n get settings_config() {\n return this.process_settings_config({\n adapter: {\n name: \"Model Platform\",\n type: \"dropdown\",\n description: \"Select a model platform to use with Smart Model.\",\n options_callback: \"get_platforms_as_options\",\n is_scope: true,\n // trigger re-render of settings when changed\n callback: \"adapter_changed\",\n default: \"default\"\n }\n });\n }\n /**\n * Process settings configuration with conditionals and prefixes.\n * @param {Object} _settings_config - Raw settings configuration\n * @param {string} [prefix] - Optional prefix for setting keys\n * @returns {Object} Processed settings configuration\n */\n process_settings_config(_settings_config, prefix = null) {\n return Object.entries(_settings_config).reduce((acc, [key, val]) => {\n if (val.conditional) {\n if (!val.conditional(this)) return acc;\n delete val.conditional;\n }\n const new_key = (prefix ? prefix + \".\" : \"\") + this.process_setting_key(key);\n acc[new_key] = val;\n return acc;\n }, {});\n }\n /**\n * Process an individual setting key.\n * Example: replace placeholders with actual adapter names.\n * @param {string} key - The setting key with placeholders.\n * @returns {string} Processed setting key.\n */\n process_setting_key(key) {\n return key.replace(/\\[ADAPTER\\]/g, this.adapter_name);\n }\n re_render_settings() {\n if (typeof this.opts.re_render_settings === \"function\") this.opts.re_render_settings();\n else console.warn(\"re_render_settings is not a function (must be passed in model opts)\");\n }\n /**\n * Reload model.\n */\n reload_model() {\n console.log(\"reload_model\", this.opts);\n if (typeof this.opts.reload_model === \"function\") this.opts.reload_model();\n else console.warn(\"reload_model is not a function (must be passed in model opts)\");\n }\n adapter_changed() {\n this.reload_model();\n this.re_render_settings();\n }\n model_changed() {\n this.reload_model();\n this.re_render_settings();\n }\n // /**\n // * Render settings.\n // * @param {HTMLElement} [container] - Container element\n // * @param {Object} [opts] - Render options\n // * @returns {Promise} Container element\n // */\n // async render_settings(container=this.settings_container, opts = {}) {\n // if(!this.settings_container || container !== this.settings_container) this.settings_container = container;\n // const model_type = this.constructor.name.toLowerCase().replace('smart', '').replace('model', '');\n // let model_settings_container;\n // if(this.settings_container) {\n // const container_id = `#${model_type}-model-settings-container`;\n // model_settings_container = this.settings_container.querySelector(container_id);\n // if(!model_settings_container) {\n // model_settings_container = document.createElement('div');\n // model_settings_container.id = container_id;\n // this.settings_container.appendChild(model_settings_container);\n // }\n // model_settings_container.innerHTML = '
Loading ' + this.adapter_name + ' settings...
';\n // }\n // const frag = await this.render_settings_component(this, opts);\n // if(model_settings_container) {\n // model_settings_container.innerHTML = '';\n // model_settings_container.appendChild(frag);\n // this.smart_view.on_open_overlay(model_settings_container);\n // }\n // return frag;\n // }\n};\n__publicField(SmartModel, \"defaults\", {\n // override in sub-class if needed\n});\n\n// models.json\nvar models_default = {\n \"cohere-rerank-english-v3.0\": {\n adapter: \"cohere\",\n model_name: \"rerank-english-v3.0\",\n model_description: \"Cohere Rerank English v3.0\",\n model_version: \"3.0\",\n endpoint: \"https://api.cohere.ai/v1/rerank\",\n headers: {\n \"Content-Type\": \"application/json\"\n },\n api_key_header: \"Authorization\"\n },\n \"jinaai/jina-reranker-v1-tiny-en\": {\n adapter: \"transformers\",\n model_key: \"jinaai/jina-reranker-v1-tiny-en\"\n },\n \"jinaai/jina-reranker-v1-turbo-en\": {\n adapter: \"transformers\",\n model_key: \"jinaai/jina-reranker-v1-turbo-en\"\n },\n \"mixedbread-ai/mxbai-rerank-xsmall-v1\": {\n adapter: \"transformers\",\n model_key: \"mixedbread-ai/mxbai-rerank-xsmall-v1\"\n },\n \"Xenova/bge-reranker-base\": {\n adapter: \"transformers\",\n model_key: \"Xenova/bge-reranker-base\"\n }\n};\n\n// smart_rank_model.js\nvar SmartRankModel = class extends SmartModel {\n /**\n * Load the SmartRankModel with the specified configuration.\n * @param {Object} env - Environment configurations.\n * @param {Object} opts - Configuration options.\n * @param {string} opts.model_key - Model key to select the adapter.\n * @param {Object} [opts.adapters] - Optional map of adapters to override defaults.\n * @param {Object} [opts.settings] - Optional user settings.\n * @returns {Promise} Loaded SmartRankModel instance.\n * \n * @example\n * ```javascript\n * const rankModel = await SmartRankModel.load(env, {\n * model_key: 'cohere',\n * adapter: 'cohere',\n * settings: {\n * cohere_api_key: 'your-cohere-api-key',\n * },\n * });\n * ```\n */\n /**\n * Rank documents based on a query.\n * @param {string} query - The query string.\n * @param {Array} documents - Array of document strings to rank.\n * @param {Object} [options={}] - Additional ranking options.\n * @param {number} [options.top_k] - Limit the number of returned documents.\n * @param {boolean} [options.return_documents=false] - Whether to include original documents in results.\n * @returns {Promise>} Ranked documents with properties like {index, score, text}.\n * \n * @example\n * ```javascript\n * const rankings = await rankModel.rank(\"What is the capital of the United States?\", [\n * \"Carson City is the capital city of the American state of Nevada.\",\n * \"The Commonwealth of the Northern Mariana Islands is a group of islands in the Pacific Ocean. Its capital is Saipan.\",\n * \"Washington, D.C. is the capital of the United States.\",\n * ]);\n * console.log(rankings);\n * ```\n */\n async rank(query, documents, options = {}) {\n return await this.invoke_adapter_method(\"rank\", query, documents, options);\n }\n /**\n * Get available ranking models.\n * @returns {Object} Map of ranking models.\n */\n get models() {\n return models_default;\n }\n /**\n * Get the default model key.\n * @returns {string} Default model key.\n */\n get default_model_key() {\n return \"jinaai/jina-reranker-v1-tiny-en\";\n }\n /**\n * Get settings configuration schema.\n * @returns {Object} Settings configuration object.\n */\n get settings_config() {\n const _settings_config = {\n adapter: {\n name: \"Ranking Model Platform\",\n type: \"dropdown\",\n description: \"Select a ranking model platform.\",\n options_callback: \"get_platforms_as_options\",\n callback: \"adapter_changed\",\n default: this.constructor.defaults.adapter\n },\n // Add adapter-specific settings here\n ...this.adapter.settings_config || {}\n };\n return this.process_settings_config(_settings_config);\n }\n /**\n * Reload ranking model.\n */\n reload_model() {\n if (this.adapter && typeof this.adapter.load === \"function\") {\n this.adapter.load();\n }\n }\n};\n/**\n * Default configurations for SmartRankModel.\n * @type {Object}\n */\n__publicField(SmartRankModel, \"defaults\", {\n adapter: \"transformers\",\n // Default to transformers adapter\n model_key: \"jinaai/jina-reranker-v1-tiny-en\"\n});\n\n// ../smart-model/adapters/_adapter.js\nvar SmartModelAdapter = class {\n /**\n * Create a SmartModelAdapter instance.\n * @param {SmartModel} model - The parent SmartModel instance\n */\n constructor(model2) {\n this.model = model2;\n this.state = \"unloaded\";\n }\n /**\n * Load the adapter.\n * @async\n * @returns {Promise}\n */\n async load() {\n this.set_state(\"loaded\");\n }\n /**\n * Unload the adapter.\n * @returns {void}\n */\n unload() {\n this.set_state(\"unloaded\");\n }\n /**\n * Get all settings.\n * @returns {Object} All settings\n */\n get settings() {\n return this.model.settings;\n }\n /**\n * Get the current model key.\n * @returns {string} Current model identifier\n */\n get model_key() {\n return this.model.model_key;\n }\n /**\n * Get the current model configuration.\n * @returns {Object} Model configuration\n */\n get model_config() {\n return this.model.model_config;\n }\n /**\n * Get model-specific settings.\n * @returns {Object} Settings for current model\n */\n get model_settings() {\n return this.model.model_settings;\n }\n /**\n * Get adapter-specific configuration.\n * @returns {Object} Adapter configuration\n */\n get adapter_config() {\n return this.model.adapter_config;\n }\n /**\n * Get adapter-specific settings.\n * @returns {Object} Adapter settings\n */\n get adapter_settings() {\n return this.model.adapter_settings;\n }\n /**\n * Get the models.\n * @returns {Object} Map of model objects\n */\n get models() {\n if (typeof this.adapter_config.models === \"object\" && Object.keys(this.adapter_config.models || {}).length > 0) return this.adapter_config.models;\n else {\n return {};\n }\n }\n /**\n * Get available models from the API.\n * @abstract\n * @param {boolean} [refresh=false] - Whether to refresh cached models\n * @returns {Promise} Map of model objects\n */\n async get_models(refresh = false) {\n throw new Error(\"get_models not implemented\");\n }\n /**\n * Validate the parameters for get_models.\n * @returns {boolean|Array} True if parameters are valid, otherwise an array of error objects\n */\n validate_get_models_params() {\n return true;\n }\n /**\n * Get available models as dropdown options synchronously.\n * @returns {Array} Array of model options.\n */\n get_models_as_options() {\n const models = this.models;\n const params_valid = this.validate_get_models_params();\n if (params_valid !== true) return params_valid;\n if (!Object.keys(models || {}).length) {\n this.get_models(true);\n return [{ value: \"\", name: \"No models currently available\" }];\n }\n return Object.values(models).map((model2) => ({ value: model2.id, name: model2.name || model2.id })).sort((a, b) => a.name.localeCompare(b.name));\n }\n /**\n * Set the adapter's state.\n * @param {('unloaded'|'loading'|'loaded'|'unloading')} new_state - The new state\n * @throws {Error} If the state is invalid\n */\n set_state(new_state) {\n const valid_states = [\"unloaded\", \"loading\", \"loaded\", \"unloading\"];\n if (!valid_states.includes(new_state)) {\n throw new Error(`Invalid state: ${new_state}`);\n }\n this.state = new_state;\n }\n // Replace individual state getters/setters with a unified state management\n get is_loading() {\n return this.state === \"loading\";\n }\n get is_loaded() {\n return this.state === \"loaded\";\n }\n get is_unloading() {\n return this.state === \"unloading\";\n }\n get is_unloaded() {\n return this.state === \"unloaded\";\n }\n};\n\n// adapters/_adapter.js\nvar SmartRankAdapter = class extends SmartModelAdapter {\n /**\n * Create a SmartRankAdapter instance.\n * @param {SmartRankModel} model - The parent SmartRankModel instance\n */\n constructor(model2) {\n super(model2);\n this.smart_rank = model2;\n }\n /**\n * Rank documents based on a query.\n * @abstract\n * @param {string} query - The query string\n * @param {Array} documents - The documents to rank\n * @returns {Promise>} Array of ranking results {index, score, ...}\n * @throws {Error} If the method is not implemented by subclass\n */\n async rank(query, documents) {\n throw new Error(\"rank method not implemented\");\n }\n get settings_config() {\n return {\n \"[ADAPTER].model_key\": {\n name: \"Ranking Model\",\n type: \"dropdown\",\n description: \"Select a ranking model to use.\",\n options_callback: \"adapter.get_models_as_options\",\n callback: \"reload_model\",\n default: this.constructor.defaults.default_model\n }\n };\n }\n};\n\n// adapters/transformers.js\nvar transformers_defaults = {\n adapter: \"transformers\",\n description: \"Transformers\",\n default_model: \"jinaai/jina-reranker-v1-tiny-en\"\n};\nvar transformers_models = {\n \"jinaai/jina-reranker-v1-tiny-en\": {\n id: \"jinaai/jina-reranker-v1-tiny-en\",\n adapter: \"transformers\",\n model_key: \"jinaai/jina-reranker-v1-tiny-en\"\n },\n \"jinaai/jina-reranker-v1-turbo-en\": {\n id: \"jinaai/jina-reranker-v1-turbo-en\",\n adapter: \"transformers\",\n model_key: \"jinaai/jina-reranker-v1-turbo-en\"\n },\n \"mixedbread-ai/mxbai-rerank-xsmall-v1\": {\n id: \"mixedbread-ai/mxbai-rerank-xsmall-v1\",\n adapter: \"transformers\",\n model_key: \"mixedbread-ai/mxbai-rerank-xsmall-v1\"\n },\n \"Xenova/bge-reranker-base\": {\n id: \"Xenova/bge-reranker-base\",\n adapter: \"transformers\",\n model_key: \"Xenova/bge-reranker-base\"\n }\n};\nvar SmartRankTransformersAdapter = class extends SmartRankAdapter {\n /**\n * Create transformers adapter instance\n * @param {SmartRankModel} model - Parent model instance\n */\n constructor(model2) {\n super(model2);\n this.model_instance = null;\n this.tokenizer = null;\n }\n /**\n * Load model and tokenizer\n * @async\n * @returns {Promise}\n */\n async load() {\n console.log(\"TransformersAdapter initializing\");\n console.log(this.model.model_key);\n const { AutoTokenizer, AutoModelForSequenceClassification, env } = await import(\"https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.1.1\");\n env.allowLocalModels = false;\n const pipeline_opts = {\n quantized: true\n };\n if (this.model.opts.use_gpu) {\n console.log(\"[Transformers] Using GPU\");\n pipeline_opts.device = \"webgpu\";\n } else {\n console.log(\"[Transformers] Using CPU\");\n }\n this.model_instance = await AutoModelForSequenceClassification.from_pretrained(this.model.model_key, pipeline_opts);\n this.tokenizer = await AutoTokenizer.from_pretrained(this.model.model_key);\n console.log(\"TransformersAdapter initialized\");\n }\n /**\n * Rank documents based on a query\n * @param {string} query - The query string\n * @param {Array} documents - Documents to rank\n * @param {Object} [options={}] - Additional ranking options\n * @param {number} [options.top_k] - Limit the number of returned documents\n * @param {boolean} [options.return_documents=false] - Whether to include original documents in results\n * @returns {Promise>} Ranked documents with properties like {index, score, text}\n */\n async rank(query, documents, options = {}) {\n console.log(\"TransformersAdapter ranking\");\n console.log(documents);\n const { top_k = void 0, return_documents = false } = options;\n if (!this.model_instance || !this.tokenizer) await this.load();\n console.log(\"tokenizing\");\n const inputs = this.tokenizer(\n new Array(documents.length).fill(query),\n { text_pair: documents, padding: true, truncation: true }\n );\n console.log(\"running model\");\n const { logits } = await this.model_instance(inputs);\n console.log(\"done\");\n return logits.sigmoid().tolist().map(([score], i) => ({\n index: i,\n score,\n ...return_documents ? { text: documents[i] } : {}\n })).sort((a, b) => b.score - a.score).slice(0, top_k);\n }\n get models() {\n return transformers_models;\n }\n};\n__publicField(SmartRankTransformersAdapter, \"defaults\", transformers_defaults);\n\n// build/transformers_iframe_script.js\nvar model = null;\nasync function process_message(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 = new SmartRankModel({\n ...params,\n adapters: { transformers: SmartRankTransformersAdapter },\n adapter: \"transformers\",\n settings: {}\n });\n await model.load();\n result = { model_loaded: true };\n break;\n case \"rank\":\n if (!model) throw new Error(\"Model not loaded\");\n result = await model.rank(params.query, params.documents);\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}\nprocess_message({ method: \"init\" });\n"; \ No newline at end of file +export const transformers_connector = "var __defProp = Object.defineProperty;\nvar __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;\nvar __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== \"symbol\" ? key + \"\" : key, value);\n\n// ../smart-model/smart_model.js\nvar SmartModel = class {\n /**\n * Create a SmartModel instance.\n * @param {Object} opts - Configuration options\n * @param {Object} opts.adapters - Map of adapter names to adapter classes\n * @param {Object} opts.settings - Model settings configuration\n * @param {Object} opts.model_config - Model-specific configuration\n * @param {string} opts.model_config.adapter - Name of the adapter to use\n * @param {string} [opts.model_key] - Optional model identifier to override settings\n * @throws {Error} If required options are missing\n */\n constructor(opts = {}) {\n __publicField(this, \"scope_name\", \"smart_model\");\n this.opts = opts;\n this.validate_opts(opts);\n this.state = \"unloaded\";\n this._adapter = null;\n }\n /**\n * Initialize the model by loading the configured adapter.\n * @async\n * @returns {Promise}\n */\n async initialize() {\n this.load_adapter(this.adapter_name);\n await this.load();\n }\n /**\n * Validate required options.\n * @param {Object} opts - Configuration options\n */\n validate_opts(opts) {\n if (!opts.adapters) throw new Error(\"opts.adapters is required\");\n if (!opts.settings) throw new Error(\"opts.settings is required\");\n }\n /**\n * Get the current settings\n * @returns {Object} Current settings\n */\n get settings() {\n if (!this.opts.settings) this.opts.settings = {\n ...this.constructor.defaults\n };\n return this.opts.settings;\n }\n /**\n * Get the current adapter name\n * @returns {string} Current adapter name\n */\n get adapter_name() {\n const adapter_key = this.opts.model_config?.adapter || this.opts.adapter || this.settings.adapter || Object.keys(this.adapters)[0];\n if (!adapter_key || !this.adapters[adapter_key]) throw new Error(`Platform \"${adapter_key}\" not supported`);\n return adapter_key;\n }\n /**\n * Get adapter-specific settings.\n * @returns {Object} Settings for current adapter\n */\n get adapter_settings() {\n if (!this.settings[this.adapter_name]) this.settings[this.adapter_name] = {};\n return this.settings[this.adapter_name];\n }\n get adapter_config() {\n const base_config = this.adapters[this.adapter_name]?.defaults || {};\n return {\n ...base_config,\n ...this.adapter_settings,\n ...this.opts.adapter_config\n };\n }\n /**\n * Get available models.\n * @returns {Object} Map of model objects\n */\n get models() {\n return this.adapter.models;\n }\n /**\n * Get the default model key to use\n * @returns {string} Default model identifier\n */\n get default_model_key() {\n throw new Error(\"default_model_key must be overridden in sub-class\");\n }\n /**\n * Get the current model key\n * @returns {string} Current model key\n */\n get model_key() {\n return this.opts.model_key || this.adapter_config.model_key || this.settings.model_key || this.default_model_key;\n }\n /**\n * Get the current model configuration\n * @returns {Object} Combined base and custom model configuration\n */\n get model_config() {\n const model_key = this.model_key;\n const base_model_config = this.models[model_key] || {};\n return {\n ...this.adapter_config,\n ...base_model_config,\n ...this.opts.model_config\n };\n }\n get model_settings() {\n if (!this.settings[this.model_key]) this.settings[this.model_key] = {};\n return this.settings[this.model_key];\n }\n /**\n * Load the current adapter and transition to loaded state.\n * @async\n * @returns {Promise}\n */\n async load() {\n this.set_state(\"loading\");\n if (!this.adapter?.loaded) {\n await this.invoke_adapter_method(\"load\");\n }\n this.set_state(\"loaded\");\n }\n /**\n * Unload the current adapter and transition to unloaded state.\n * @async\n * @returns {Promise}\n */\n async unload() {\n if (this.adapter?.loaded) {\n this.set_state(\"unloading\");\n await this.invoke_adapter_method(\"unload\");\n this.set_state(\"unloaded\");\n }\n }\n /**\n * Set the model's state.\n * @param {('unloaded'|'loading'|'loaded'|'unloading')} new_state - The new state\n * @throws {Error} If the state is invalid\n */\n set_state(new_state) {\n const valid_states = [\"unloaded\", \"loading\", \"loaded\", \"unloading\"];\n if (!valid_states.includes(new_state)) {\n throw new Error(`Invalid state: ${new_state}`);\n }\n this.state = new_state;\n }\n get is_loading() {\n return this.state === \"loading\";\n }\n get is_loaded() {\n return this.state === \"loaded\";\n }\n get is_unloading() {\n return this.state === \"unloading\";\n }\n get is_unloaded() {\n return this.state === \"unloaded\";\n }\n // ADAPTERS\n /**\n * Get the map of available adapters\n * @returns {Object} Map of adapter names to adapter classes\n */\n get adapters() {\n return this.opts.adapters || {};\n }\n /**\n * Load a specific adapter by name.\n * @async\n * @param {string} adapter_name - Name of the adapter to load\n * @throws {Error} If adapter not found or loading fails\n * @returns {Promise}\n */\n async load_adapter(adapter_name) {\n this.set_adapter(adapter_name);\n if (!this._adapter.loaded) {\n this.set_state(\"loading\");\n try {\n await this.invoke_adapter_method(\"load\");\n this.set_state(\"loaded\");\n } catch (err) {\n this.set_state(\"unloaded\");\n throw new Error(`Failed to load adapter: ${err.message}`);\n }\n }\n }\n /**\n * Set an adapter instance by name without loading it.\n * @param {string} adapter_name - Name of the adapter to set\n * @throws {Error} If adapter not found\n */\n set_adapter(adapter_name) {\n const AdapterClass = this.adapters[adapter_name];\n if (!AdapterClass) {\n throw new Error(`Adapter \"${adapter_name}\" not found.`);\n }\n if (this._adapter?.constructor.name.toLowerCase() === adapter_name.toLowerCase()) {\n return;\n }\n this._adapter = new AdapterClass(this);\n }\n /**\n * Get the current active adapter instance\n * @returns {Object} The active adapter instance\n * @throws {Error} If adapter not found\n */\n get adapter() {\n const adapter_name = this.adapter_name;\n if (!adapter_name) {\n throw new Error(`Adapter not set for model.`);\n }\n if (!this._adapter) {\n this.load_adapter(adapter_name);\n }\n return this._adapter;\n }\n /**\n * Ensure the adapter is ready to execute a method.\n * @param {string} method - Name of the method to check\n * @throws {Error} If adapter not loaded or method not implemented\n */\n ensure_adapter_ready(method) {\n if (!this.adapter) {\n throw new Error(\"No adapter loaded.\");\n }\n if (typeof this.adapter[method] !== \"function\") {\n throw new Error(`Adapter does not implement method: ${method}`);\n }\n }\n /**\n * Invoke a method on the current adapter.\n * @async\n * @param {string} method - Name of the method to call\n * @param {...any} args - Arguments to pass to the method\n * @returns {Promise} Result from the adapter method\n * @throws {Error} If adapter not ready or method fails\n */\n async invoke_adapter_method(method, ...args) {\n this.ensure_adapter_ready(method);\n return await this.adapter[method](...args);\n }\n /**\n * Get platforms as dropdown options.\n * @returns {Array} Array of {value, name} option objects\n */\n get_platforms_as_options() {\n console.log(\"get_platforms_as_options\", this.adapters);\n return Object.entries(this.adapters).map(([key, AdapterClass]) => ({ value: key, name: AdapterClass.defaults.description || key }));\n }\n // SETTINGS\n /**\n * Get the settings configuration schema\n * @returns {Object} Settings configuration object\n */\n get settings_config() {\n return this.process_settings_config({\n adapter: {\n name: \"Model Platform\",\n type: \"dropdown\",\n description: \"Select a model platform to use with Smart Model.\",\n options_callback: \"get_platforms_as_options\",\n is_scope: true,\n // trigger re-render of settings when changed\n callback: \"adapter_changed\",\n default: \"default\"\n }\n });\n }\n /**\n * Process settings configuration with conditionals and prefixes.\n * @param {Object} _settings_config - Raw settings configuration\n * @param {string} [prefix] - Optional prefix for setting keys\n * @returns {Object} Processed settings configuration\n */\n process_settings_config(_settings_config, prefix = null) {\n return Object.entries(_settings_config).reduce((acc, [key, val]) => {\n if (val.conditional) {\n if (!val.conditional(this)) return acc;\n delete val.conditional;\n }\n const new_key = (prefix ? prefix + \".\" : \"\") + this.process_setting_key(key);\n acc[new_key] = val;\n return acc;\n }, {});\n }\n /**\n * Process an individual setting key.\n * Example: replace placeholders with actual adapter names.\n * @param {string} key - The setting key with placeholders.\n * @returns {string} Processed setting key.\n */\n process_setting_key(key) {\n return key.replace(/\\[ADAPTER\\]/g, this.adapter_name);\n }\n re_render_settings() {\n if (typeof this.opts.re_render_settings === \"function\") this.opts.re_render_settings();\n else console.warn(\"re_render_settings is not a function (must be passed in model opts)\");\n }\n /**\n * Reload model.\n */\n reload_model() {\n console.log(\"reload_model\", this.opts);\n if (typeof this.opts.reload_model === \"function\") this.opts.reload_model();\n else console.warn(\"reload_model is not a function (must be passed in model opts)\");\n }\n adapter_changed() {\n this.reload_model();\n this.re_render_settings();\n }\n model_changed() {\n this.reload_model();\n this.re_render_settings();\n }\n // /**\n // * Render settings.\n // * @param {HTMLElement} [container] - Container element\n // * @param {Object} [opts] - Render options\n // * @returns {Promise} Container element\n // */\n // async render_settings(container=this.settings_container, opts = {}) {\n // if(!this.settings_container || container !== this.settings_container) this.settings_container = container;\n // const model_type = this.constructor.name.toLowerCase().replace('smart', '').replace('model', '');\n // let model_settings_container;\n // if(this.settings_container) {\n // const container_id = `#${model_type}-model-settings-container`;\n // model_settings_container = this.settings_container.querySelector(container_id);\n // if(!model_settings_container) {\n // model_settings_container = document.createElement('div');\n // model_settings_container.id = container_id;\n // this.settings_container.appendChild(model_settings_container);\n // }\n // model_settings_container.innerHTML = '
Loading ' + this.adapter_name + ' settings...
';\n // }\n // const frag = await this.render_settings_component(this, opts);\n // if(model_settings_container) {\n // model_settings_container.innerHTML = '';\n // model_settings_container.appendChild(frag);\n // this.smart_view.on_open_overlay(model_settings_container);\n // }\n // return frag;\n // }\n};\n__publicField(SmartModel, \"defaults\", {\n // override in sub-class if needed\n});\n\n// models.json\nvar models_default = {\n \"cohere-rerank-english-v3.0\": {\n adapter: \"cohere\",\n model_name: \"rerank-english-v3.0\",\n model_description: \"Cohere Rerank English v3.0\",\n model_version: \"3.0\",\n endpoint: \"https://api.cohere.ai/v1/rerank\",\n headers: {\n \"Content-Type\": \"application/json\"\n },\n api_key_header: \"Authorization\"\n },\n \"jinaai/jina-reranker-v1-tiny-en\": {\n adapter: \"transformers\",\n model_key: \"jinaai/jina-reranker-v1-tiny-en\"\n },\n \"jinaai/jina-reranker-v1-turbo-en\": {\n adapter: \"transformers\",\n model_key: \"jinaai/jina-reranker-v1-turbo-en\"\n },\n \"mixedbread-ai/mxbai-rerank-xsmall-v1\": {\n adapter: \"transformers\",\n model_key: \"mixedbread-ai/mxbai-rerank-xsmall-v1\"\n },\n \"Xenova/bge-reranker-base\": {\n adapter: \"transformers\",\n model_key: \"Xenova/bge-reranker-base\"\n }\n};\n\n// smart_rank_model.js\nvar SmartRankModel = class extends SmartModel {\n /**\n * Load the SmartRankModel with the specified configuration.\n * @param {Object} env - Environment configurations.\n * @param {Object} opts - Configuration options.\n * @param {string} opts.model_key - Model key to select the adapter.\n * @param {Object} [opts.adapters] - Optional map of adapters to override defaults.\n * @param {Object} [opts.settings] - Optional user settings.\n * @returns {Promise} Loaded SmartRankModel instance.\n * \n * @example\n * ```javascript\n * const rankModel = await SmartRankModel.load(env, {\n * model_key: 'cohere',\n * adapter: 'cohere',\n * settings: {\n * cohere_api_key: 'your-cohere-api-key',\n * },\n * });\n * ```\n */\n /**\n * Rank documents based on a query.\n * @param {string} query - The query string.\n * @param {Array} documents - Array of document strings to rank.\n * @param {Object} [options={}] - Additional ranking options.\n * @param {number} [options.top_k] - Limit the number of returned documents.\n * @param {boolean} [options.return_documents=false] - Whether to include original documents in results.\n * @returns {Promise>} Ranked documents with properties like {index, score, text}.\n * \n * @example\n * ```javascript\n * const rankings = await rankModel.rank(\"What is the capital of the United States?\", [\n * \"Carson City is the capital city of the American state of Nevada.\",\n * \"The Commonwealth of the Northern Mariana Islands is a group of islands in the Pacific Ocean. Its capital is Saipan.\",\n * \"Washington, D.C. is the capital of the United States.\",\n * ]);\n * console.log(rankings);\n * ```\n */\n async rank(query, documents, options = {}) {\n return await this.invoke_adapter_method(\"rank\", query, documents, options);\n }\n /**\n * Get available ranking models.\n * @returns {Object} Map of ranking models.\n */\n get models() {\n return models_default;\n }\n /**\n * Get the default model key.\n * @returns {string} Default model key.\n */\n get default_model_key() {\n return \"jinaai/jina-reranker-v1-tiny-en\";\n }\n /**\n * Get settings configuration schema.\n * @returns {Object} Settings configuration object.\n */\n get settings_config() {\n const _settings_config = {\n adapter: {\n name: \"Ranking Model Platform\",\n type: \"dropdown\",\n description: \"Select a ranking model platform.\",\n options_callback: \"get_platforms_as_options\",\n callback: \"adapter_changed\",\n default: this.constructor.defaults.adapter\n },\n // Add adapter-specific settings here\n ...this.adapter.settings_config || {}\n };\n return this.process_settings_config(_settings_config);\n }\n /**\n * Reload ranking model.\n */\n reload_model() {\n if (this.adapter && typeof this.adapter.load === \"function\") {\n this.adapter.load();\n }\n }\n};\n/**\n * Default configurations for SmartRankModel.\n * @type {Object}\n */\n__publicField(SmartRankModel, \"defaults\", {\n adapter: \"transformers\",\n // Default to transformers adapter\n model_key: \"jinaai/jina-reranker-v1-tiny-en\"\n});\n\n// ../smart-model/adapters/_adapter.js\nvar SmartModelAdapter = class {\n /**\n * Create a SmartModelAdapter instance.\n * @param {SmartModel} model - The parent SmartModel instance\n */\n constructor(model2) {\n this.model = model2;\n this.state = \"unloaded\";\n }\n /**\n * Load the adapter.\n * @async\n * @returns {Promise}\n */\n async load() {\n this.set_state(\"loaded\");\n }\n /**\n * Unload the adapter.\n * @returns {void}\n */\n unload() {\n this.set_state(\"unloaded\");\n }\n /**\n * Get all settings.\n * @returns {Object} All settings\n */\n get settings() {\n return this.model.settings;\n }\n /**\n * Get the current model key.\n * @returns {string} Current model identifier\n */\n get model_key() {\n return this.model.model_key;\n }\n /**\n * Get the current model configuration.\n * @returns {Object} Model configuration\n */\n get model_config() {\n return this.model.model_config;\n }\n /**\n * Get model-specific settings.\n * @returns {Object} Settings for current model\n */\n get model_settings() {\n return this.model.model_settings;\n }\n /**\n * Get adapter-specific configuration.\n * @returns {Object} Adapter configuration\n */\n get adapter_config() {\n return this.model.adapter_config;\n }\n /**\n * Get adapter-specific settings.\n * @returns {Object} Adapter settings\n */\n get adapter_settings() {\n return this.model.adapter_settings;\n }\n /**\n * Get the models.\n * @returns {Object} Map of model objects\n */\n get models() {\n if (typeof this.adapter_config.models === \"object\" && Object.keys(this.adapter_config.models || {}).length > 0) return this.adapter_config.models;\n else {\n return {};\n }\n }\n /**\n * Get available models from the API.\n * @abstract\n * @param {boolean} [refresh=false] - Whether to refresh cached models\n * @returns {Promise} Map of model objects\n */\n async get_models(refresh = false) {\n throw new Error(\"get_models not implemented\");\n }\n /**\n * Validate the parameters for get_models.\n * @returns {boolean|Array} True if parameters are valid, otherwise an array of error objects\n */\n validate_get_models_params() {\n return true;\n }\n /**\n * Get available models as dropdown options synchronously.\n * @returns {Array} Array of model options.\n */\n get_models_as_options() {\n const models = this.models;\n const params_valid = this.validate_get_models_params();\n if (params_valid !== true) return params_valid;\n if (!Object.keys(models || {}).length) {\n this.get_models(true);\n return [{ value: \"\", name: \"No models currently available\" }];\n }\n return Object.values(models).map((model2) => ({ value: model2.id, name: model2.name || model2.id })).sort((a, b) => a.name.localeCompare(b.name));\n }\n /**\n * Set the adapter's state.\n * @param {('unloaded'|'loading'|'loaded'|'unloading')} new_state - The new state\n * @throws {Error} If the state is invalid\n */\n set_state(new_state) {\n const valid_states = [\"unloaded\", \"loading\", \"loaded\", \"unloading\"];\n if (!valid_states.includes(new_state)) {\n throw new Error(`Invalid state: ${new_state}`);\n }\n this.state = new_state;\n }\n // Replace individual state getters/setters with a unified state management\n get is_loading() {\n return this.state === \"loading\";\n }\n get is_loaded() {\n return this.state === \"loaded\";\n }\n get is_unloading() {\n return this.state === \"unloading\";\n }\n get is_unloaded() {\n return this.state === \"unloaded\";\n }\n};\n\n// adapters/_adapter.js\nvar SmartRankAdapter = class extends SmartModelAdapter {\n /**\n * Create a SmartRankAdapter instance.\n * @param {SmartRankModel} model - The parent SmartRankModel instance\n */\n constructor(model2) {\n super(model2);\n this.smart_rank = model2;\n }\n /**\n * Rank documents based on a query.\n * @abstract\n * @param {string} query - The query string\n * @param {Array} documents - The documents to rank\n * @returns {Promise>} Array of ranking results {index, score, ...}\n * @throws {Error} If the method is not implemented by subclass\n */\n async rank(query, documents) {\n throw new Error(\"rank method not implemented\");\n }\n get settings_config() {\n return {\n \"[ADAPTER].model_key\": {\n name: \"Ranking Model\",\n type: \"dropdown\",\n description: \"Select a ranking model to use.\",\n options_callback: \"adapter.get_models_as_options\",\n callback: \"reload_model\",\n default: this.constructor.defaults.default_model\n }\n };\n }\n};\n\n// adapters/transformers.js\nvar transformers_defaults = {\n adapter: \"transformers\",\n description: \"Transformers\",\n default_model: \"jinaai/jina-reranker-v1-tiny-en\"\n};\nvar transformers_models = {\n \"jinaai/jina-reranker-v1-tiny-en\": {\n id: \"jinaai/jina-reranker-v1-tiny-en\",\n adapter: \"transformers\",\n model_key: \"jinaai/jina-reranker-v1-tiny-en\"\n },\n \"jinaai/jina-reranker-v1-turbo-en\": {\n id: \"jinaai/jina-reranker-v1-turbo-en\",\n adapter: \"transformers\",\n model_key: \"jinaai/jina-reranker-v1-turbo-en\"\n },\n \"mixedbread-ai/mxbai-rerank-xsmall-v1\": {\n id: \"mixedbread-ai/mxbai-rerank-xsmall-v1\",\n adapter: \"transformers\",\n model_key: \"mixedbread-ai/mxbai-rerank-xsmall-v1\"\n },\n \"Xenova/bge-reranker-base\": {\n id: \"Xenova/bge-reranker-base\",\n adapter: \"transformers\",\n model_key: \"Xenova/bge-reranker-base\"\n }\n};\nvar SmartRankTransformersAdapter = class extends SmartRankAdapter {\n /**\n * Create transformers adapter instance\n * @param {SmartRankModel} model - Parent model instance\n */\n constructor(model2) {\n super(model2);\n this.model_instance = null;\n this.tokenizer = null;\n }\n /**\n * Load model and tokenizer\n * @async\n * @returns {Promise}\n */\n async load() {\n console.log(\"TransformersAdapter initializing\");\n console.log(this.model.model_key);\n const { AutoTokenizer, AutoModelForSequenceClassification, env } = await import(\"https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.1.2\");\n env.allowLocalModels = false;\n const pipeline_opts = {\n quantized: true\n };\n if (this.model.opts.use_gpu) {\n console.log(\"[Transformers] Using GPU\");\n pipeline_opts.device = \"webgpu\";\n } else {\n console.log(\"[Transformers] Using CPU\");\n }\n this.model_instance = await AutoModelForSequenceClassification.from_pretrained(this.model.model_key, pipeline_opts);\n this.tokenizer = await AutoTokenizer.from_pretrained(this.model.model_key);\n console.log(\"TransformersAdapter initialized\");\n }\n /**\n * Rank documents based on a query\n * @param {string} query - The query string\n * @param {Array} documents - Documents to rank\n * @param {Object} [options={}] - Additional ranking options\n * @param {number} [options.top_k] - Limit the number of returned documents\n * @param {boolean} [options.return_documents=false] - Whether to include original documents in results\n * @returns {Promise>} Ranked documents with properties like {index, score, text}\n */\n async rank(query, documents, options = {}) {\n console.log(\"TransformersAdapter ranking\");\n console.log(documents);\n const { top_k = void 0, return_documents = false } = options;\n if (!this.model_instance || !this.tokenizer) await this.load();\n console.log(\"tokenizing\");\n const inputs = this.tokenizer(\n new Array(documents.length).fill(query),\n { text_pair: documents, padding: true, truncation: true }\n );\n console.log(\"running model\");\n const { logits } = await this.model_instance(inputs);\n console.log(\"done\");\n return logits.sigmoid().tolist().map(([score], i) => ({\n index: i,\n score,\n ...return_documents ? { text: documents[i] } : {}\n })).sort((a, b) => b.score - a.score).slice(0, top_k);\n }\n get models() {\n return transformers_models;\n }\n};\n__publicField(SmartRankTransformersAdapter, \"defaults\", transformers_defaults);\n\n// build/transformers_iframe_script.js\nvar model = null;\nasync function process_message(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 = new SmartRankModel({\n ...params,\n adapters: { transformers: SmartRankTransformersAdapter },\n adapter: \"transformers\",\n settings: {}\n });\n await model.load();\n result = { model_loaded: true };\n break;\n case \"rank\":\n if (!model) throw new Error(\"Model not loaded\");\n result = await model.rank(params.query, params.documents);\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}\nprocess_message({ method: \"init\" });\n"; \ No newline at end of file diff --git a/smart-rank-model/connectors/transformers_worker.js b/smart-rank-model/connectors/transformers_worker.js index 85598ff4..fcb9f972 100644 --- a/smart-rank-model/connectors/transformers_worker.js +++ b/smart-rank-model/connectors/transformers_worker.js @@ -690,7 +690,7 @@ var SmartRankTransformersAdapter = class extends SmartRankAdapter { async load() { console.log("TransformersAdapter initializing"); console.log(this.model.model_key); - const { AutoTokenizer, AutoModelForSequenceClassification, env } = await import("https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.1.1"); + const { AutoTokenizer, AutoModelForSequenceClassification, env } = await import("https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.1.2"); env.allowLocalModels = false; const pipeline_opts = { quantized: true diff --git a/smart-rank-model/smart_rank_model.js b/smart-rank-model/smart_rank_model.js index 3c4baadf..5ef473b6 100644 --- a/smart-rank-model/smart_rank_model.js +++ b/smart-rank-model/smart_rank_model.js @@ -50,8 +50,11 @@ export class SmartRankModel extends SmartModel { * @type {Object} */ static defaults = { - adapter: 'transformers', // Default to transformers adapter - model_key: 'jinaai/jina-reranker-v1-tiny-en', + adapter: 'cohere', + model_key: 'rerank-v3.5', + // LOCAL RERANKER CURRENTLY TOO SLOW FOR DEFAULT + // adapter: 'transformers', // Default to transformers adapter + // model_key: 'jinaai/jina-reranker-v1-tiny-en', };