From eb119cb1c4f729f5d8e75a22bd930848a955acde Mon Sep 17 00:00:00 2001 From: chelouche9 Date: Sat, 18 Mar 2023 22:15:32 +0200 Subject: [PATCH] fix: add jsdoc to utils.js --- dist/types/samplers.d.ts | 10 +- dist/types/utils.d.ts | 234 ++++++++++-- src/utils.js | 770 ++++++++++++++++++++++++--------------- 3 files changed, 679 insertions(+), 335 deletions(-) diff --git a/dist/types/samplers.d.ts b/dist/types/samplers.d.ts index e29231a40..e18587444 100644 --- a/dist/types/samplers.d.ts +++ b/dist/types/samplers.d.ts @@ -16,10 +16,10 @@ export class TopKSampler extends Sampler { sample(logits: any, index?: number): any[][]; } export class BeamSearchSampler extends Sampler { - constructor(temperature: any, num_beams: any, do_sample: any, top_k: any); - num_beams: any; - do_sample: any; - top_k: any; - sample(logits: any, index?: number): any; + constructor(temperature: any, num_beams: any, do_sample: any, top_k: any); + num_beams: any; + do_sample: any; + top_k: any; + sample(logits: any, index?: number): any[]; } import { Callable } from "./utils.js"; diff --git a/dist/types/utils.d.ts b/dist/types/utils.d.ts index 8bb52067c..289b9a7fe 100644 --- a/dist/types/utils.d.ts +++ b/dist/types/utils.d.ts @@ -1,39 +1,209 @@ +/** + * A base class for creating callable objects. + * + * @class Callable + * @extends Function + */ export class Callable extends Function { - constructor(); - _call(...args: any[]): void; + /** + * Creates a new instance of the Callable class. + * + * @constructor + */ + constructor(); + /** + * This method should be implemented in subclasses to provide the + * functionality of the callable object. + * + * @method _call + * @throws {Error} Must implement _call method in subclass + */ + _call(...args: any[]): void; } -export function getModelFile(modelPath: any, fileName: any, progressCallback?: any): Promise; -export function dispatchCallback(progressCallback: any, data: any): void; -export function fetchJSON(modelPath: any, fileName: any, progressCallback?: any): Promise; -export function pathJoin(...parts: any[]): string; -export function reverseDictionary(data: any): any; -export function indexOfMax(arr: any): number; -export function softmax(arr: any): any; -export function log_softmax(arr: any): any; -export function escapeRegExp(string: any): any; -export function getTopItems(items: any, top_k?: number): any; -export function dot(arr1: any, arr2: any): any; -export function cos_sim(arr1: any, arr2: any): number; -export function magnitude(arr: any): number; -export function getFile(url: any): Promise; +/** + * Retrieves a file from either a remote URL using the Fetch API or from the local file system using the FileSystem API. + * + * @async + * @function getModelFile + * @param {string} modelPath - The path of the model file. + * @param {string} fileName - The name of the model file. + * @param {function} [progressCallback=null] - A function to call when the download progress is updated. + * @returns {Promise} A Promise that resolves with the file content as a buffer. + * @throws Will throw an error if the file is not found. + */ +export function getModelFile( + modelPath: string, + fileName: string, + progressCallback?: Function +): Promise; +/** + * Helper function to dispatch progress callbacks. + * + * @function dispatchCallback + * @param {function} progressCallback - The progress callback function to dispatch. + * @param {any} data - The data to pass to the progress callback function. + * @returns {void} + */ +export function dispatchCallback(progressCallback: Function, data: any): void; +/** + * Fetches a JSON file from a given path and file name. + * + * @param {string} modelPath - The path to the directory containing the file. + * @param {string} fileName - The name of the file to fetch. + * @param {function} progressCallback - A callback function to receive progress updates. Optional. + * @returns {Promise} - The JSON data parsed into a JavaScript object. + */ +export function fetchJSON( + modelPath: string, + fileName: string, + progressCallback?: Function +): Promise; +/** + * Joins multiple parts of a path into a single path, while handling leading and trailing slashes. + * + * @param {...string} parts - Multiple parts of a path. + * @returns {string} A string representing the joined path. + */ +export function pathJoin(...parts: string[]): string; +/** + * Reverses the keys and values of an object. + * + * @param {object} data - The object to reverse. + * @returns {object} The reversed object. + * @see https://ultimatecourses.com/blog/reverse-object-keys-and-values-in-javascript + */ +export function reverseDictionary(data: object): object; +/** + * Returns the index of the maximum value in an array. + * @param {Array} arr - The input array. + * @see https://stackoverflow.com/a/11301464 + * @returns {number} - The index of the maximum value in the array. + */ +export function indexOfMax(arr: any[]): number; +/** + * Compute the softmax of an array of numbers. + * + * @param {number[]} arr - The array of numbers to compute the softmax of. + * @returns {number[]} The softmax array. + */ +export function softmax(arr: number[]): number[]; +/** + * Calculates the logarithm of the softmax function for the input array. + * @param {number[]} arr - The input array to calculate the log_softmax function for. + * @returns {number[]} - The resulting log_softmax array. + */ +export function log_softmax(arr: number[]): number[]; +/** + * Escapes regular expression special characters from a string by replacing them with their escaped counterparts. + * + * @param {string} string - The string to escape. + * @returns {string} - The escaped string. + */ +export function escapeRegExp(string: string): string; +/** + * Get the top k items from an iterable, sorted by descending order + * + * @param {Array} items - The items to be sorted + * @param {number} [top_k=0] - The number of top items to return (default: 0 = return all) + * @returns {Array} - The top k items, sorted by descending order + */ +export function getTopItems(items: any[], top_k?: number): any[]; +/** + * Calculates the dot product of two arrays. + * @param {Array} arr1 - The first array. + * @param {Array} arr2 - The second array. + * @returns {number} - The dot product of arr1 and arr2. + */ +export function dot(arr1: Array, arr2: Array): number; +/** + * Computes the cosine similarity between two arrays. + * + * @param {Array} arr1 - The first array. + * @param {Array} arr2 - The second array. + * @returns {number} The cosine similarity between the two arrays. + */ +export function cos_sim(arr1: Array, arr2: Array): number; +/** + * Calculates the magnitude of a given array. + * @param {number[]} arr - The array to calculate the magnitude of. + * @returns {number} The magnitude of the array. + */ +export function magnitude(arr: number[]): number; +/** + * Helper function to get a file, using either the Fetch API or FileSystem API. + * + * @async + * @function getFile + * @param {string} url - The URL of the file to get. + * @returns {Promise} A promise that resolves to a FileResponse object (if the file is retrieved using the FileSystem API), or a Response object (if the file is retrieved using the Fetch API). + */ +export function getFile(url: string): Promise; +/** + * Check if a value is an integer. + * @param {*} x - The value to check. + * @returns {boolean} - True if the value is a string, false otherwise. + */ export function isIntegralNumber(x: any): boolean; +/** + * Check if a value is a string. + * @param {*} text - The value to check. + * @returns {boolean} - True if the value is a string, false otherwise. + */ export function isString(text: any): boolean; declare class FileResponse { - /** - * @param {string} filePath - */ - constructor(filePath: string); - filePath: string; - headers: {}; - exists: boolean; - status: number; - statusText: string; - body: ReadableStream; - updateContentType(): void; - clone(): FileResponse; - arrayBuffer(): Promise; - blob(): Promise; - text(): Promise; - json(): Promise; + /** + * @param {string} filePath + */ + constructor(filePath: string); + filePath: string; + headers: {}; + exists: boolean; + status: number; + statusText: string; + body: ReadableStream; + /** + * Updates the 'content-type' header property of the HTTP response based on the file extension of + * the file specified by the filePath property of the current object. + * @function + * @returns {void} + */ + updateContentType(): void; + clone(): FileResponse; + /** + * Reads the contents of the file specified by the filePath property and returns a Promise that + * resolves with an ArrayBuffer containing the file's contents. + * @async + * @function + * @returns {Promise} - A Promise that resolves with an ArrayBuffer containing the file's contents. + * @throws {Error} - If the file cannot be read. + */ + arrayBuffer(): Promise; + /** + * Reads the contents of the file specified by the filePath property and returns a Promise that + * resolves with a Blob containing the file's contents. + * @async + * @function + * @returns {Promise} - A Promise that resolves with a Blob containing the file's contents. + * @throws {Error} - If the file cannot be read. + */ + blob(): Promise; + /** + * Reads the contents of the file specified by the filePath property and returns a Promise that + * resolves with a string containing the file's contents. + * @async + * @function + * @returns {Promise} - A Promise that resolves with a string containing the file's contents. + * @throws {Error} - If the file cannot be read. + */ + text(): Promise; + /** + * Reads the contents of the file specified by the filePath property and returns a Promise that + * resolves with a parsed JavaScript object containing the file's contents. + * @async + * @function + * @returns {Promise} - A Promise that resolves with a parsed JavaScript object containing the file's contents. + * @throws {Error} - If the file cannot be read. + */ + json(): Promise; } export {}; diff --git a/src/utils.js b/src/utils.js index 6c126cae1..d9553a923 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,402 +1,576 @@ +const fs = require("fs"); -const fs = require('fs'); - -const { env } = require('./env.js'); +const { env } = require("./env.js"); class FileResponse { - /** - * @param {string} filePath - */ - constructor(filePath) { - this.filePath = filePath; - this.headers = {}; - this.headers.get = (x) => this.headers[x] - - this.exists = fs.existsSync(filePath); - if (this.exists) { - this.status = 200; - this.statusText = 'OK'; - - - let stats = fs.statSync(filePath); - this.headers['content-length'] = stats.size; - - this.updateContentType(); - - let self = this; - this.body = new ReadableStream({ - start(controller) { - self.arrayBuffer().then(buffer => { - controller.enqueue(new Uint8Array(buffer)); - controller.close(); - }) - } - }); - } else { - this.status = 404; - this.statusText = 'Not Found'; - this.body = null; - } - } - - updateContentType() { - // Set content-type header based on file extension - const extension = this.filePath.split('.').pop().toLowerCase(); - switch (extension) { - case 'txt': - this.headers['content-type'] = 'text/plain'; - break; - case 'html': - this.headers['content-type'] = 'text/html'; - break; - case 'css': - this.headers['content-type'] = 'text/css'; - break; - case 'js': - this.headers['content-type'] = 'text/javascript'; - break; - case 'json': - this.headers['content-type'] = 'application/json'; - break; - case 'png': - this.headers['content-type'] = 'image/png'; - break; - case 'jpg': - case 'jpeg': - this.headers['content-type'] = 'image/jpeg'; - break; - case 'gif': - this.headers['content-type'] = 'image/gif'; - break; - default: - this.headers['content-type'] = 'application/octet-stream'; - break; - } - } - - clone() { - return new FileResponse(this.filePath, { - status: this.status, - statusText: this.statusText, - headers: this.headers, - }); - } - - async arrayBuffer() { - const data = await fs.promises.readFile(this.filePath); - return data.buffer; - } - - async blob() { - const data = await fs.promises.readFile(this.filePath); - return new Blob([data], { type: this.headers['content-type'] }); + /** + * @param {string} filePath + */ + constructor(filePath) { + this.filePath = filePath; + this.headers = {}; + this.headers.get = (x) => this.headers[x]; + + this.exists = fs.existsSync(filePath); + if (this.exists) { + this.status = 200; + this.statusText = "OK"; + + let stats = fs.statSync(filePath); + this.headers["content-length"] = stats.size; + + this.updateContentType(); + + let self = this; + this.body = new ReadableStream({ + start(controller) { + self.arrayBuffer().then((buffer) => { + controller.enqueue(new Uint8Array(buffer)); + controller.close(); + }); + }, + }); + } else { + this.status = 404; + this.statusText = "Not Found"; + this.body = null; } - - async text() { - const data = await fs.promises.readFile(this.filePath, 'utf8'); - return data; + } + + /** + * Updates the 'content-type' header property of the HTTP response based on the file extension of + * the file specified by the filePath property of the current object. + * @function + * @returns {void} + */ + updateContentType() { + // Set content-type header based on file extension + const extension = this.filePath.split(".").pop().toLowerCase(); + switch (extension) { + case "txt": + this.headers["content-type"] = "text/plain"; + break; + case "html": + this.headers["content-type"] = "text/html"; + break; + case "css": + this.headers["content-type"] = "text/css"; + break; + case "js": + this.headers["content-type"] = "text/javascript"; + break; + case "json": + this.headers["content-type"] = "application/json"; + break; + case "png": + this.headers["content-type"] = "image/png"; + break; + case "jpg": + case "jpeg": + this.headers["content-type"] = "image/jpeg"; + break; + case "gif": + this.headers["content-type"] = "image/gif"; + break; + default: + this.headers["content-type"] = "application/octet-stream"; + break; } + } - async json() { - return JSON.parse(await this.text()); - } + clone() { + return new FileResponse(this.filePath, { + status: this.status, + statusText: this.statusText, + headers: this.headers, + }); + } + + /** + * Reads the contents of the file specified by the filePath property and returns a Promise that + * resolves with an ArrayBuffer containing the file's contents. + * @async + * @function + * @returns {Promise} - A Promise that resolves with an ArrayBuffer containing the file's contents. + * @throws {Error} - If the file cannot be read. + */ + async arrayBuffer() { + const data = await fs.promises.readFile(this.filePath); + return data.buffer; + } + + /** + * Reads the contents of the file specified by the filePath property and returns a Promise that + * resolves with a Blob containing the file's contents. + * @async + * @function + * @returns {Promise} - A Promise that resolves with a Blob containing the file's contents. + * @throws {Error} - If the file cannot be read. + */ + async blob() { + const data = await fs.promises.readFile(this.filePath); + return new Blob([data], { type: this.headers["content-type"] }); + } + + /** + * Reads the contents of the file specified by the filePath property and returns a Promise that + * resolves with a string containing the file's contents. + * @async + * @function + * @returns {Promise} - A Promise that resolves with a string containing the file's contents. + * @throws {Error} - If the file cannot be read. + */ + async text() { + const data = await fs.promises.readFile(this.filePath, "utf8"); + return data; + } + + /** + * Reads the contents of the file specified by the filePath property and returns a Promise that + * resolves with a parsed JavaScript object containing the file's contents. + * @async + * @function + * @returns {Promise} - A Promise that resolves with a parsed JavaScript object containing the file's contents. + * @throws {Error} - If the file cannot be read. + */ + async json() { + return JSON.parse(await this.text()); + } } +/** + * Determines whether the given string is a valid HTTP or HTTPS URL. + * @function + * @param {string} string - The string to test for validity as an HTTP or HTTPS URL. + * @returns {boolean} - True if the string is a valid HTTP or HTTPS URL, false otherwise. + */ function isValidHttpUrl(string) { - // https://stackoverflow.com/a/43467144 - let url; - try { - url = new URL(string); - } catch (_) { - return false; - } - return url.protocol === "http:" || url.protocol === "https:"; + // https://stackoverflow.com/a/43467144 + let url; + try { + url = new URL(string); + } catch (_) { + return false; + } + return url.protocol === "http:" || url.protocol === "https:"; } +/** + * Helper function to get a file, using either the Fetch API or FileSystem API. + * + * @async + * @function getFile + * @param {string} url - The URL of the file to get. + * @returns {Promise} A promise that resolves to a FileResponse object (if the file is retrieved using the FileSystem API), or a Response object (if the file is retrieved using the Fetch API). + */ async function getFile(url) { - // Helper function to get a file, using either the Fetch API or FileSystem API - - if (env.useFS && !isValidHttpUrl(url)) { - return new FileResponse(url) + // Helper function to get a file, using either the Fetch API or FileSystem API - } else { - return fetch(url) - } + if (env.useFS && !isValidHttpUrl(url)) { + return new FileResponse(url); + } else { + return fetch(url); + } } +/** + * Helper function to dispatch progress callbacks. + * + * @function dispatchCallback + * @param {function} progressCallback - The progress callback function to dispatch. + * @param {any} data - The data to pass to the progress callback function. + * @returns {void} + */ function dispatchCallback(progressCallback, data) { - if (progressCallback !== null) progressCallback(data); + if (progressCallback !== null) progressCallback(data); } +/** + * Retrieves a file from either a remote URL using the Fetch API or from the local file system using the FileSystem API. + * + * @async + * @function getModelFile + * @param {string} modelPath - The path of the model file. + * @param {string} fileName - The name of the model file. + * @param {function} [progressCallback=null] - A function to call when the download progress is updated. + * @returns {Promise} A Promise that resolves with the file content as a buffer. + * @throws Will throw an error if the file is not found. + */ async function getModelFile(modelPath, fileName, progressCallback = null) { + // Initiate session + dispatchCallback(progressCallback, { + status: "initiate", + name: modelPath, + file: fileName, + }); - // Initiate session - dispatchCallback(progressCallback, { - status: 'initiate', - name: modelPath, - file: fileName - }) - - let cache; - if (env.useCache) { - cache = await caches.open('transformers-cache'); - } - - const request = pathJoin(modelPath, fileName); + let cache; + if (env.useCache) { + cache = await caches.open("transformers-cache"); + } - let response; - let responseToCache; + const request = pathJoin(modelPath, fileName); - if (!env.useCache || (response = await cache.match(request)) === undefined) { - // Caching not available, or model is not cached, so we perform the request - response = await getFile(request); + let response; + let responseToCache; - if (response.status === 404) { - throw Error(`File not found. Could not locate "${request}".`) - } + if (!env.useCache || (response = await cache.match(request)) === undefined) { + // Caching not available, or model is not cached, so we perform the request + response = await getFile(request); - if (env.useCache) { - // only clone if cache available - responseToCache = response.clone(); - } + if (response.status === 404) { + throw Error(`File not found. Could not locate "${request}".`); } - // Start downloading - dispatchCallback(progressCallback, { - status: 'download', - name: modelPath, - file: fileName - }) - - const buffer = await readResponse(response, data => { - dispatchCallback(progressCallback, { - status: 'progress', - ...data, - name: modelPath, - file: fileName - }) - }) - - // Check again whether request is in cache. If not, we add the response to the cache - if (responseToCache !== undefined && await cache.match(request) === undefined) { - cache.put(request, responseToCache); + if (env.useCache) { + // only clone if cache available + responseToCache = response.clone(); } + } + // Start downloading + dispatchCallback(progressCallback, { + status: "download", + name: modelPath, + file: fileName, + }); + + const buffer = await readResponse(response, (data) => { dispatchCallback(progressCallback, { - status: 'done', - name: modelPath, - file: fileName + status: "progress", + ...data, + name: modelPath, + file: fileName, }); - - return buffer; + }); + + // Check again whether request is in cache. If not, we add the response to the cache + if ( + responseToCache !== undefined && + (await cache.match(request)) === undefined + ) { + // @ts-ignore + // TODO: fix type error for responseToCache + cache.put(request, responseToCache); + } + + dispatchCallback(progressCallback, { + status: "done", + name: modelPath, + file: fileName, + }); + + return buffer; } +/** + * Fetches a JSON file from a given path and file name. + * + * @param {string} modelPath - The path to the directory containing the file. + * @param {string} fileName - The name of the file to fetch. + * @param {function} progressCallback - A callback function to receive progress updates. Optional. + * @returns {Promise} - The JSON data parsed into a JavaScript object. + */ async function fetchJSON(modelPath, fileName, progressCallback = null) { - let buffer = await getModelFile(modelPath, fileName, progressCallback); + let buffer = await getModelFile(modelPath, fileName, progressCallback); - let decoder = new TextDecoder('utf-8'); - let jsonData = decoder.decode(buffer); + let decoder = new TextDecoder("utf-8"); + let jsonData = decoder.decode(buffer); - return JSON.parse(jsonData); + return JSON.parse(jsonData); } - +/** + * Read and track progress when reading a Response object + * + * @param {Response} response - The Response object to read + * @param {function} progressCallback - The function to call with progress updates + * @returns {Promise} A Promise that resolves with the Uint8Array buffer + */ async function readResponse(response, progressCallback) { - // Read and track progress when reading a Response object - - const contentLength = response.headers.get('Content-Length'); - if (contentLength === null) { - console.warn('Unable to determine content-length from response headers. Will expand buffer when needed.') + // Read and track progress when reading a Response object + + const contentLength = response.headers.get("Content-Length"); + if (contentLength === null) { + console.warn( + "Unable to determine content-length from response headers. Will expand buffer when needed." + ); + } + let total = parseInt(contentLength ?? "0"); + let buffer = new Uint8Array(total); + let loaded = 0; + + const reader = response.body.getReader(); + async function read() { + const { done, value } = await reader.read(); + if (done) return; + + let newLoaded = loaded + value.length; + if (newLoaded > total) { + total = newLoaded; + + // Adding the new data will overflow buffer. + // In this case, we extend the buffer + let newBuffer = new Uint8Array(total); + + // copy contents + newBuffer.set(buffer); + + buffer = newBuffer; } - let total = parseInt(contentLength ?? '0'); - let buffer = new Uint8Array(total); - let loaded = 0; - - const reader = response.body.getReader(); - async function read() { - const { done, value } = await reader.read(); - if (done) return; - - let newLoaded = loaded + value.length; - if (newLoaded > total) { - total = newLoaded; + buffer.set(value, loaded); + loaded = newLoaded; - // Adding the new data will overflow buffer. - // In this case, we extend the buffer - let newBuffer = new Uint8Array(total); + const progress = (loaded / total) * 100; - // copy contents - newBuffer.set(buffer); - - buffer = newBuffer; - } - buffer.set(value, loaded) - loaded = newLoaded; - - const progress = (loaded / total) * 100; - - // Call your function here - progressCallback({ - progress: progress, - loaded: loaded, - total: total, - }) + // Call your function here + progressCallback({ + progress: progress, + loaded: loaded, + total: total, + }); - return read(); - } + return read(); + } - // Actually read - await read(); + // Actually read + await read(); - return buffer; + return buffer; } +/** + * Joins multiple parts of a path into a single path, while handling leading and trailing slashes. + * + * @param {...string} parts - Multiple parts of a path. + * @returns {string} A string representing the joined path. + */ function pathJoin(...parts) { - // https://stackoverflow.com/a/55142565 - parts = parts.map((part, index) => { - if (index) { - part = part.replace(new RegExp('^/'), ''); - } - if (index !== parts.length - 1) { - part = part.replace(new RegExp('/$'), ''); - } - return part; - }) - return parts.join('/'); + // https://stackoverflow.com/a/55142565 + parts = parts.map((part, index) => { + if (index) { + part = part.replace(new RegExp("^/"), ""); + } + if (index !== parts.length - 1) { + part = part.replace(new RegExp("/$"), ""); + } + return part; + }); + return parts.join("/"); } +/** + * Reverses the keys and values of an object. + * + * @param {object} data - The object to reverse. + * @returns {object} The reversed object. + * @see https://ultimatecourses.com/blog/reverse-object-keys-and-values-in-javascript + */ function reverseDictionary(data) { - // https://ultimatecourses.com/blog/reverse-object-keys-and-values-in-javascript - return Object.fromEntries(Object.entries(data).map(([key, value]) => [value, key])); + return Object.fromEntries( + Object.entries(data).map(([key, value]) => [value, key]) + ); } +/** + * Returns the index of the maximum value in an array. + * @param {Array} arr - The input array. + * @see https://stackoverflow.com/a/11301464 + * @returns {number} - The index of the maximum value in the array. + */ function indexOfMax(arr) { - // https://stackoverflow.com/a/11301464 - - if (arr.length === 0) { - return -1; - } + if (arr.length === 0) { + return -1; + } - var max = arr[0]; - var maxIndex = 0; + var max = arr[0]; + var maxIndex = 0; - for (var i = 1; i < arr.length; ++i) { - if (arr[i] > max) { - maxIndex = i; - max = arr[i]; - } + for (var i = 1; i < arr.length; ++i) { + if (arr[i] > max) { + maxIndex = i; + max = arr[i]; } + } - return maxIndex; + return maxIndex; } - +/** + * Compute the softmax of an array of numbers. + * + * @param {number[]} arr - The array of numbers to compute the softmax of. + * @returns {number[]} The softmax array. + */ function softmax(arr) { - // Compute the maximum value in the array - const max = Math.max(...arr); + // Compute the maximum value in the array + const max = Math.max(...arr); - // Compute the exponentials of the array values - const exps = arr.map(x => Math.exp(x - max)); + // Compute the exponentials of the array values + const exps = arr.map((x) => Math.exp(x - max)); - // Compute the sum of the exponentials - const sumExps = exps.reduce((acc, val) => acc + val, 0); + // Compute the sum of the exponentials + const sumExps = exps.reduce((acc, val) => acc + val, 0); - // Compute the softmax values - const softmaxArr = exps.map(x => x / sumExps); + // Compute the softmax values + const softmaxArr = exps.map((x) => x / sumExps); - return softmaxArr; + return softmaxArr; } +/** + * Calculates the logarithm of the softmax function for the input array. + * @param {number[]} arr - The input array to calculate the log_softmax function for. + * @returns {number[]} - The resulting log_softmax array. + */ function log_softmax(arr) { - // Compute the softmax values - const softmaxArr = softmax(arr); + // Compute the softmax values + const softmaxArr = softmax(arr); - // Apply log formula to each element - const logSoftmaxArr = softmaxArr.map(x => Math.log(x)); + // Apply log formula to each element + const logSoftmaxArr = softmaxArr.map((x) => Math.log(x)); - return logSoftmaxArr; + return logSoftmaxArr; } +/** + * Escapes regular expression special characters from a string by replacing them with their escaped counterparts. + * + * @param {string} string - The string to escape. + * @returns {string} - The escaped string. + */ function escapeRegExp(string) { - return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string + return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string } +/** + * Get the top k items from an iterable, sorted by descending order + * + * @param {Array} items - The items to be sorted + * @param {number} [top_k=0] - The number of top items to return (default: 0 = return all) + * @returns {Array} - The top k items, sorted by descending order + */ function getTopItems(items, top_k = 0) { - // if top == 0, return all + // if top == 0, return all - items = Array.from(items) - .map((x, i) => [i, x]) // Get indices ([index, score]) - .sort((a, b) => b[1] - a[1]) // Sort by log probabilities + items = Array.from(items) + .map((x, i) => [i, x]) // Get indices ([index, score]) + .sort((a, b) => b[1] - a[1]); // Sort by log probabilities - if (top_k > 0) { - items = items.slice(0, top_k); // Get top k items - } + if (top_k > 0) { + items = items.slice(0, top_k); // Get top k items + } - return items + return items; } +/** + * Calculates the dot product of two arrays. + * @param {Array} arr1 - The first array. + * @param {Array} arr2 - The second array. + * @returns {number} - The dot product of arr1 and arr2. + */ function dot(arr1, arr2) { - return arr1.reduce((acc, val, i) => acc + val * arr2[i], 0); + return arr1.reduce((acc, val, i) => acc + val * arr2[i], 0); } +/** + * Computes the cosine similarity between two arrays. + * + * @param {Array} arr1 - The first array. + * @param {Array} arr2 - The second array. + * @returns {number} The cosine similarity between the two arrays. + */ function cos_sim(arr1, arr2) { - // Calculate dot product of the two arrays - const dotProduct = dot(arr1, arr2); + // Calculate dot product of the two arrays + const dotProduct = dot(arr1, arr2); - // Calculate the magnitude of the first array - const magnitudeA = magnitude(arr1); + // Calculate the magnitude of the first array + const magnitudeA = magnitude(arr1); - // Calculate the magnitude of the second array - const magnitudeB = magnitude(arr2); + // Calculate the magnitude of the second array + const magnitudeB = magnitude(arr2); - // Calculate the cosine similarity - const cosineSimilarity = dotProduct / (magnitudeA * magnitudeB); + // Calculate the cosine similarity + const cosineSimilarity = dotProduct / (magnitudeA * magnitudeB); - return cosineSimilarity; + return cosineSimilarity; } +/** + * Calculates the magnitude of a given array. + * @param {number[]} arr - The array to calculate the magnitude of. + * @returns {number} The magnitude of the array. + */ function magnitude(arr) { - return Math.sqrt(arr.reduce((acc, val) => acc + val * val, 0)); + return Math.sqrt(arr.reduce((acc, val) => acc + val * val, 0)); } - +/** + * A base class for creating callable objects. + * + * @class Callable + * @extends Function + */ class Callable extends Function { - constructor() { - let closure = function (...args) { return closure._call(...args) } - return Object.setPrototypeOf(closure, new.target.prototype) - } - - _call(...args) { - throw Error('Must implement _call method in subclass') - } + /** + * Creates a new instance of the Callable class. + * + * @constructor + */ + constructor() { + let closure = function (...args) { + return closure._call(...args); + }; + return Object.setPrototypeOf(closure, new.target.prototype); + } + + /** + * This method should be implemented in subclasses to provide the + * functionality of the callable object. + * + * @method _call + * @throws {Error} Must implement _call method in subclass + */ + _call(...args) { + throw Error("Must implement _call method in subclass"); + } } - +/** + * Check if a value is a string. + * @param {*} text - The value to check. + * @returns {boolean} - True if the value is a string, false otherwise. + */ function isString(text) { - return typeof text === 'string' || text instanceof String + return typeof text === "string" || text instanceof String; } - +/** + * Check if a value is an integer. + * @param {*} x - The value to check. + * @returns {boolean} - True if the value is a string, false otherwise. + */ function isIntegralNumber(x) { - return Number.isInteger(x) || typeof x === 'bigint' + return Number.isInteger(x) || typeof x === "bigint"; } module.exports = { - Callable, - getModelFile, - dispatchCallback, - fetchJSON, - pathJoin, - reverseDictionary, - indexOfMax, - softmax, - log_softmax, - escapeRegExp, - getTopItems, - dot, - cos_sim, - magnitude, - getFile, - isIntegralNumber, - isString + Callable, + getModelFile, + dispatchCallback, + fetchJSON, + pathJoin, + reverseDictionary, + indexOfMax, + softmax, + log_softmax, + escapeRegExp, + getTopItems, + dot, + cos_sim, + magnitude, + getFile, + isIntegralNumber, + isString, };