diff --git a/plugins/data-plugin/package.json b/plugins/data-plugin/package.json index 89c281f00..cd7014840 100644 --- a/plugins/data-plugin/package.json +++ b/plugins/data-plugin/package.json @@ -5,7 +5,7 @@ "icon": "https://raw.githubusercontent.com/tailwindlabs/heroicons/88e98b0c2b458553fbadccddc2d2f878edc0387b/src/20/solid/circle-stack.svg", "main": "dist/esm/index.js", "module": "dist/cjs/module.js", - "author": "Jan", + "author": "Jan ", "license": "MIT", "activationPoints": [ "init" diff --git a/plugins/inference-plugin/package.json b/plugins/inference-plugin/package.json index fd8e41e06..778c610ae 100644 --- a/plugins/inference-plugin/package.json +++ b/plugins/inference-plugin/package.json @@ -5,7 +5,7 @@ "icon": "https://raw.githubusercontent.com/tailwindlabs/heroicons/88e98b0c2b458553fbadccddc2d2f878edc0387b/src/20/solid/command-line.svg", "main": "dist/index.js", "module": "dist/module.js", - "author": "Jan", + "author": "Jan ", "license": "MIT", "activationPoints": [ "init" diff --git a/plugins/model-management-plugin/@types/global.d.ts b/plugins/model-management-plugin/@types/global.d.ts index 87105f099..87056c342 100644 --- a/plugins/model-management-plugin/@types/global.d.ts +++ b/plugins/model-management-plugin/@types/global.d.ts @@ -1,2 +1,3 @@ declare const PLUGIN_NAME: string; declare const MODULE_PATH: string; +declare const MODEL_CATALOG_URL: string; diff --git a/plugins/model-management-plugin/helper.ts b/plugins/model-management-plugin/helper.ts new file mode 100644 index 000000000..d8b8a81f5 --- /dev/null +++ b/plugins/model-management-plugin/helper.ts @@ -0,0 +1,37 @@ +export const parseToModel = (model) => { + const modelVersions = []; + model.versions.forEach((v) => { + const version = { + _id: `${model.author}-${v.name}`, + name: v.name, + quantMethod: v.quantMethod, + bits: v.bits, + size: v.size, + maxRamRequired: v.maxRamRequired, + usecase: v.usecase, + downloadLink: v.downloadLink, + productId: model.id, + }; + modelVersions.push(version); + }); + + const product = { + _id: model.id, + name: model.name, + shortDescription: model.shortDescription, + avatarUrl: model.avatarUrl, + author: model.author, + version: model.version, + modelUrl: model.modelUrl, + nsfw: model.nsfw, + tags: model.tags, + greeting: model.defaultGreeting, + type: model.type, + createdAt: model.createdAt, + longDescription: model.longDescription, + status: "Downloadable", + releaseDate: 0, + availableVersions: modelVersions, + }; + return product; +}; diff --git a/plugins/model-management-plugin/index.ts b/plugins/model-management-plugin/index.ts index 04d64be53..64ae0548e 100644 --- a/plugins/model-management-plugin/index.ts +++ b/plugins/model-management-plugin/index.ts @@ -1,4 +1,5 @@ import { ModelManagementService, PluginService, RegisterExtensionPoint, core, store } from "@janhq/core"; +import { parseToModel } from "./helper"; const getDownloadedModels = () => core.invokePluginFunc(MODULE_PATH, "getDownloadedModels"); @@ -10,7 +11,16 @@ const deleteModel = (path) => core.deleteFile(path); const searchModels = (params) => core.invokePluginFunc(MODULE_PATH, "searchModels", params); -const getConfiguredModels = () => core.invokePluginFunc(MODULE_PATH, "getConfiguredModels"); +async function getConfiguredModels() { + // Clear cache to get the latest model catalog + delete require.cache[MODEL_CATALOG_URL]; + + // Import the remote model catalog + const module = require(MODEL_CATALOG_URL); + return module.default.map((e) => { + return parseToModel(e); + }); +} /** * Store a model in the database when user start downloading it diff --git a/plugins/model-management-plugin/module.ts b/plugins/model-management-plugin/module.ts index 8aacfc60f..f053ebf79 100644 --- a/plugins/model-management-plugin/module.ts +++ b/plugins/model-management-plugin/module.ts @@ -1,212 +1 @@ -const { listModels, listFiles, fileDownloadInfo } = require("@huggingface/hub"); -const https = require("https"); - -let modelsIterator = undefined; -let currentSearchOwner = undefined; - -// Github API -const githubHostName = "api.github.com"; -const githubHeaders = { - "User-Agent": "node.js", - Accept: "application/vnd.github.v3+json", -}; -const githubPath = "/repos/janhq/models/contents"; - -const getNextModels = async (count) => { - const models = []; - let hasMore = true; - - while (models.length < count) { - const next = await modelsIterator.next(); - - // end if we reached the end - if (next.done) { - hasMore = false; - break; - } - - const model = next.value; - const files = await listFilesByName(model.name); - - models.push({ - ...model, - files, - }); - } - - const result = { - data: models, - hasMore, - }; - return result; -}; - -const searchModels = async (params) => { - if (currentSearchOwner === params.search.owner && modelsIterator != null) { - // paginated search - console.debug(`Paginated search owner: ${params.search.owner}`); - const models = await getNextModels(params.limit); - return models; - } else { - // new search - console.debug(`Init new search owner: ${params.search.owner}`); - currentSearchOwner = params.search.owner; - modelsIterator = listModels({ - search: params.search, - credentials: params.credentials, - }); - - const models = await getNextModels(params.limit); - return models; - } -}; - -const listFilesByName = async (modelName) => { - const repo = { type: "model", name: modelName }; - const fileDownloadInfoMap = {}; - for await (const file of listFiles({ - repo: repo, - })) { - if (file.type === "file" && file.path.endsWith(".bin")) { - const downloadInfo = await fileDownloadInfo({ - repo: repo, - path: file.path, - }); - fileDownloadInfoMap[file.path] = { - ...file, - ...downloadInfo, - }; - } - } - - return fileDownloadInfoMap; -}; - -async function getConfiguredModels() { - const files: any = await getModelFiles(); - - const promises = files.map((file) => getContent(file)); - const response = await Promise.all(promises); - - const models = []; - response.forEach((model) => { - models.push(parseToModel(model)); - }); - - return models; -} - -const parseToModel = (model) => { - const modelVersions = []; - model.versions.forEach((v) => { - const version = { - _id: `${model.author}-${v.name}`, - name: v.name, - quantMethod: v.quantMethod, - bits: v.bits, - size: v.size, - maxRamRequired: v.maxRamRequired, - usecase: v.usecase, - downloadLink: v.downloadLink, - productId: model.id, - }; - modelVersions.push(version); - }); - - const product = { - _id: model.id, - name: model.name, - shortDescription: model.shortDescription, - avatarUrl: model.avatarUrl, - author: model.author, - version: model.version, - modelUrl: model.modelUrl, - nsfw: model.nsfw, - tags: model.tags, - greeting: model.defaultGreeting, - type: model.type, - createdAt: model.createdAt, - longDescription: model.longDescription, - status: "Downloadable", - releaseDate: 0, - availableVersions: modelVersions, - }; - return product; -}; - -async function getModelFiles() { - const options = { - hostname: githubHostName, - path: githubPath, - headers: githubHeaders, - }; - - const data = await new Promise((resolve, reject) => { - const req = https.request(options, (res) => { - let data = ""; - - res.on("data", (chunk) => { - data += chunk; - }); - - res.on("end", () => { - const files = JSON.parse(data); - - if (files.filter == null) { - console.error(files.message); - reject(files.message ?? "No files found"); - } - if (!files || files.length === 0) { - resolve([]); - } - const jsonFiles = files.filter((file) => file.name.endsWith(".json")); - resolve(jsonFiles); - }); - }); - - req.on("error", (error) => { - console.error(error); - }); - - req.end(); - }); - - return data; -} - -async function getContent(file) { - const options = { - hostname: githubHostName, - path: `${githubPath}/${file.path}`, - headers: githubHeaders, - }; - - const data = await new Promise((resolve) => { - const req = https.request(options, (res) => { - let data = ""; - - res.on("data", (chunk) => { - data += chunk; - }); - - res.on("end", () => { - const fileData = JSON.parse(data); - const fileContent = Buffer.from(fileData.content, "base64").toString(); - resolve(JSON.parse(fileContent)); - }); - }); - - req.on("error", (error) => { - console.error(error); - }); - - req.end(); - }); - - return data; -} - -module.exports = { - searchModels, - getConfiguredModels, -}; +module.exports = {}; diff --git a/plugins/model-management-plugin/package.json b/plugins/model-management-plugin/package.json index 35e70b788..7a9a05e54 100644 --- a/plugins/model-management-plugin/package.json +++ b/plugins/model-management-plugin/package.json @@ -5,7 +5,7 @@ "icon": "https://raw.githubusercontent.com/tailwindlabs/heroicons/88e98b0c2b458553fbadccddc2d2f878edc0387b/src/20/solid/queue-list.svg", "main": "dist/index.js", "module": "dist/module.js", - "author": "James", + "author": "Jan ", "license": "MIT", "activationPoints": [ "init" @@ -27,11 +27,7 @@ "README.md" ], "dependencies": { - "@huggingface/hub": "^0.8.5", "@janhq/core": "^0.1.1", "ts-loader": "^9.5.0" - }, - "bundledDependencies": [ - "@huggingface/hub" - ] + } } diff --git a/plugins/model-management-plugin/tsconfig.json b/plugins/model-management-plugin/tsconfig.json index 3b321034a..3a82721e6 100644 --- a/plugins/model-management-plugin/tsconfig.json +++ b/plugins/model-management-plugin/tsconfig.json @@ -1,7 +1,7 @@ { "compilerOptions": { "target": "es2016", - "module": "ES6", + "module": "esnext", "moduleResolution": "node", "outDir": "./dist", "esModuleInterop": true, diff --git a/plugins/model-management-plugin/webpack.config.js b/plugins/model-management-plugin/webpack.config.js index 48e80e2ec..1cef734ba 100644 --- a/plugins/model-management-plugin/webpack.config.js +++ b/plugins/model-management-plugin/webpack.config.js @@ -19,6 +19,9 @@ module.exports = { new webpack.DefinePlugin({ PLUGIN_NAME: JSON.stringify(packageJson.name), MODULE_PATH: JSON.stringify(`${packageJson.name}/${packageJson.module}`), + MODEL_CATALOG_URL: JSON.stringify( + "https://cdn.jsdelivr.net/npm/@janhq/models@latest/dist/index.js" + ), }), ], output: { @@ -30,7 +33,7 @@ module.exports = { extensions: [".ts", ".js"], }, optimization: { - minimize: false + minimize: false, }, // Add loaders and other configuration as needed for your project }; diff --git a/plugins/monitoring-plugin/package.json b/plugins/monitoring-plugin/package.json index a79f4a5c3..35e9f54d7 100644 --- a/plugins/monitoring-plugin/package.json +++ b/plugins/monitoring-plugin/package.json @@ -5,7 +5,7 @@ "icon": "https://raw.githubusercontent.com/tailwindlabs/heroicons/88e98b0c2b458553fbadccddc2d2f878edc0387b/src/20/solid/cpu-chip.svg", "main": "dist/index.js", "module": "dist/module.js", - "author": "Jan", + "author": "Jan ", "license": "MIT", "activationPoints": [ "init" diff --git a/plugins/openai-plugin/package.json b/plugins/openai-plugin/package.json index 636d0b513..8e23e678c 100644 --- a/plugins/openai-plugin/package.json +++ b/plugins/openai-plugin/package.json @@ -5,7 +5,7 @@ "icon": "https://static-assets.jan.ai/openai-icon.jpg", "main": "dist/index.js", "module": "dist/module.js", - "author": "Jan", + "author": "Jan ", "license": "MIT", "activationPoints": [ "init"