From 7c0bd05df3f751cf110d2e07e0564b1da4e4124a Mon Sep 17 00:00:00 2001 From: vuonghoainam Date: Wed, 4 Oct 2023 09:35:09 +0700 Subject: [PATCH 01/42] feat(ard): Add adr 002 initial draft --- adr/adr-002-jan-replicants.md | 48 ++++++++++++++++++++++++++++++++++ adr/images/adr-002-01.png | Bin 0 -> 88927 bytes adr/images/adr-002-02.png | Bin 0 -> 183397 bytes 3 files changed, 48 insertions(+) create mode 100644 adr/adr-002-jan-replicants.md create mode 100644 adr/images/adr-002-01.png create mode 100644 adr/images/adr-002-02.png diff --git a/adr/adr-002-jan-replicants.md b/adr/adr-002-jan-replicants.md new file mode 100644 index 0000000000..f7c0f9168e --- /dev/null +++ b/adr/adr-002-jan-replicants.md @@ -0,0 +1,48 @@ +# ADR #002: {Jan replicant - Composable plugin} + +## Changelog +- Oct 4th 2023: Initial draft + +## Authors +- @vuonghoainam - Hiro +- @louis-jan + +## Status +Proposed + +## Context + +### Business context +Jan can be a platform and let builders build their own `replicants` using existing tools +- Use-case 1: Medical AI startup uploads "case notes" to Jan, wants to ask it questions (i.e. medical audit) +- Use-case 2: Legal e-discovery: very large amount of documents (~10-15k pages) are uploaded, data is very private and cannot be leaked +- Use-case 3: Jan wants to use Jan to have a QnA chatbot to answer questions on docs +- Use-case 4: Jan wants to use Jan to have a codellama RAG on its own codebase, to generate new PRs + +### Extra context +- There are many use cases that the community can develop and sell to the users through Jan as plugin. Jan needs to streamline higher value chain. +- This brings more value and more option to all kind of user +- This can help building ecosystem and streamline value end to end (Jan, plugins/ model creators, Jan users - enterprise/ individual) +- We at Jan cannot build plugins more on our own, but this one should serve as featured example like [OpenAI Retrieval plugin](https://github.com/openai/chatgpt-retrieval-plugin) does. +- [#232](https://github.com/janhq/jan/issues/232) + +## Decision + +- User can browse and install plugins (with recommended model - llama2, claude, openai …) - This requires plugin dependencies. +- Jan provide consistent interface for plugin developer to use: + - Use LLM (this can be switched in runtime) - i.e Dev in llama2-7b but user can use with llama2-70b. Can choose another model as well + - Plugin can have API for CRUD indices in vectorDB/ DB, and Jan only exposes corresponding data to the app + - A place for a plugin to store the files for persistence +- This works seamlessly on desktop/ Jan hosted version with Jan API abstraction. + +### Simple UX +![UX](images/adr-002-01.png "UX") + +### Component design +![Component design](images/adr-002-02.png "Component design") + +## Consequences +- Jan user can build their own replicants (and buy from others too) in an easy way +- Clear design for plugin and Jan platform development + +## Reference diff --git a/adr/images/adr-002-01.png b/adr/images/adr-002-01.png new file mode 100644 index 0000000000000000000000000000000000000000..18b1df775e987bd1b29c92313e2df2635b9ead06 GIT binary patch literal 88927 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�r$tdm)h@#}ov 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%0AU8Vv4@*87q8|*< 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 literal 0 HcmV?d00001 diff --git a/adr/images/adr-002-02.png b/adr/images/adr-002-02.png new file mode 100644 index 0000000000000000000000000000000000000000..2c2cb1b5207bf056b6303e4886decc2f6a36a168 GIT binary patch literal 183397 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

P@% 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࣮g87_(+j~O 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�u`tUph%&yT$sq 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 z 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

YbogA&zlUh$@4gA+!{(oUKTxQNj1MbJ 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

GefLrKl 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

_o~k_BBM7(Woe6UnARO%MxSBtr;bw6rqK( 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 U)<=A%fOaMWJ(K-+_F}{T2UVFU_5c6? literal 0 HcmV?d00001 From 711bc5479988b05e4436cc6c2a3eb15a435d4bd6 Mon Sep 17 00:00:00 2001 From: vuonghoainam Date: Wed, 4 Oct 2023 10:10:59 +0700 Subject: [PATCH 02/42] fix(adr-002): Update terminology replicant to composable AI --- ...-jan-replicants.md => adr-002-jan-composable-plugins.md} | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename adr/{adr-002-jan-replicants.md => adr-002-jan-composable-plugins.md} (89%) diff --git a/adr/adr-002-jan-replicants.md b/adr/adr-002-jan-composable-plugins.md similarity index 89% rename from adr/adr-002-jan-replicants.md rename to adr/adr-002-jan-composable-plugins.md index f7c0f9168e..ec1014443c 100644 --- a/adr/adr-002-jan-replicants.md +++ b/adr/adr-002-jan-composable-plugins.md @@ -1,4 +1,4 @@ -# ADR #002: {Jan replicant - Composable plugin} +# ADR #002: Jan replicant - Composable plugin ## Changelog - Oct 4th 2023: Initial draft @@ -13,7 +13,7 @@ Proposed ## Context ### Business context -Jan can be a platform and let builders build their own `replicants` using existing tools +Jan can be a platform and let builders build their own `composable AIs` using existing tools - Use-case 1: Medical AI startup uploads "case notes" to Jan, wants to ask it questions (i.e. medical audit) - Use-case 2: Legal e-discovery: very large amount of documents (~10-15k pages) are uploaded, data is very private and cannot be leaked - Use-case 3: Jan wants to use Jan to have a QnA chatbot to answer questions on docs @@ -42,7 +42,7 @@ Jan can be a platform and let builders build their own `replicants` using existi ![Component design](images/adr-002-02.png "Component design") ## Consequences -- Jan user can build their own replicants (and buy from others too) in an easy way +- Jan user can build their own composable AIs (and buy from others too) in an easy way - Clear design for plugin and Jan platform development ## Reference From fa831e1dcb48b103d89f02612ed09dde958faf16 Mon Sep 17 00:00:00 2001 From: vuonghoainam Date: Wed, 4 Oct 2023 10:19:53 +0700 Subject: [PATCH 03/42] fix(adr-002): Change ADR title --- adr/adr-002-jan-composable-plugins.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adr/adr-002-jan-composable-plugins.md b/adr/adr-002-jan-composable-plugins.md index ec1014443c..79ae228032 100644 --- a/adr/adr-002-jan-composable-plugins.md +++ b/adr/adr-002-jan-composable-plugins.md @@ -1,4 +1,4 @@ -# ADR #002: Jan replicant - Composable plugin +# ADR #002: Jan composable AI ## Changelog - Oct 4th 2023: Initial draft From b2eef21ed13a9bf788d626a53cc8a91d352b40c2 Mon Sep 17 00:00:00 2001 From: vuonghoainam Date: Wed, 4 Oct 2023 10:25:41 +0700 Subject: [PATCH 04/42] fix(adr-002): Change md file name --- ...002-jan-composable-plugins.md => adr-002-jan-composable-ai.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename adr/{adr-002-jan-composable-plugins.md => adr-002-jan-composable-ai.md} (100%) diff --git a/adr/adr-002-jan-composable-plugins.md b/adr/adr-002-jan-composable-ai.md similarity index 100% rename from adr/adr-002-jan-composable-plugins.md rename to adr/adr-002-jan-composable-ai.md From 949df5283824cc5ef2c713f6d83498411ceb88ec Mon Sep 17 00:00:00 2001 From: vuonghoainam Date: Fri, 6 Oct 2023 17:10:56 +0700 Subject: [PATCH 05/42] fix(adr-002): Update final name for the ADR and api definition --- ...-jan-composable-ai.md => adr-002-jan-ai-apps.md} | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) rename adr/{adr-002-jan-composable-ai.md => adr-002-jan-ai-apps.md} (82%) diff --git a/adr/adr-002-jan-composable-ai.md b/adr/adr-002-jan-ai-apps.md similarity index 82% rename from adr/adr-002-jan-composable-ai.md rename to adr/adr-002-jan-ai-apps.md index 79ae228032..61dfde8479 100644 --- a/adr/adr-002-jan-composable-ai.md +++ b/adr/adr-002-jan-ai-apps.md @@ -1,7 +1,8 @@ -# ADR #002: Jan composable AI +# ADR #002: Jan AI apps ## Changelog - Oct 4th 2023: Initial draft +- Oct 6th 2023: Update sample API ## Authors - @vuonghoainam - Hiro @@ -13,7 +14,7 @@ Proposed ## Context ### Business context -Jan can be a platform and let builders build their own `composable AIs` using existing tools +Jan can be a platform and let builders build their own `AI app` using existing tools - Use-case 1: Medical AI startup uploads "case notes" to Jan, wants to ask it questions (i.e. medical audit) - Use-case 2: Legal e-discovery: very large amount of documents (~10-15k pages) are uploaded, data is very private and cannot be leaked - Use-case 3: Jan wants to use Jan to have a QnA chatbot to answer questions on docs @@ -41,8 +42,14 @@ Jan can be a platform and let builders build their own `composable AIs` using ex ### Component design ![Component design](images/adr-002-02.png "Component design") +## API +- `jan.plugin..(**args)` + +- `jan.core.db.sql.command()` -> CRUD/ query +- `jan.plugin.vectra.(**args)` -> CRUD/ query for ## Consequences -- Jan user can build their own composable AIs (and buy from others too) in an easy way +- Jan user can build their own AI apps (and buy from others too) in an easy way - Clear design for plugin and Jan platform development ## Reference +- [ADR-003](adr-003-jan-plugins.md) \ No newline at end of file From 63d8b895f32f439709b017a4f67e8ac859b99643 Mon Sep 17 00:00:00 2001 From: hiento09 <136591877+hiento09@users.noreply.github.com> Date: Tue, 10 Oct 2023 17:30:59 +0700 Subject: [PATCH 06/42] Fix icon error for linux app (#316) * Create icon folder for linux building app * CI Test: add clean workspace --------- Co-authored-by: Hien To --- .github/workflows/linter-and-test.yml | 15 +++++++++++++++ electron/{ => icons}/icon.png | Bin electron/package.json | 11 ++++++++++- 3 files changed, 25 insertions(+), 1 deletion(-) rename electron/{ => icons}/icon.png (100%) diff --git a/.github/workflows/linter-and-test.yml b/.github/workflows/linter-and-test.yml index e6a69df270..f8bbcd3411 100644 --- a/.github/workflows/linter-and-test.yml +++ b/.github/workflows/linter-and-test.yml @@ -26,6 +26,12 @@ jobs: test-on-macos: runs-on: [self-hosted, macOS, macos-desktop] steps: + - name: 'Cleanup build folder' + run: | + ls -la ./ + rm -rf ./* || true + rm -rf ./.??* || true + ls -la ./ - name: Getting the repo uses: actions/checkout@v3 @@ -48,6 +54,9 @@ jobs: test-on-windows: runs-on: [self-hosted, Windows, windows-desktop] steps: + - name: Clean workspace + run: | + Remove-Item -Path .\* -Force -Recurse - name: Getting the repo uses: actions/checkout@v3 @@ -68,6 +77,12 @@ jobs: test-on-ubuntu: runs-on: [self-hosted, Linux, ubuntu-desktop] steps: + - name: 'Cleanup build folder' + run: | + ls -la ./ + rm -rf ./* || true + rm -rf ./.??* || true + ls -la ./ - name: Getting the repo uses: actions/checkout@v3 diff --git a/electron/icon.png b/electron/icons/icon.png similarity index 100% rename from electron/icon.png rename to electron/icons/icon.png diff --git a/electron/package.json b/electron/package.json index 5df518e7a1..615659dd68 100644 --- a/electron/package.json +++ b/electron/package.json @@ -32,7 +32,16 @@ "entitlementsInherit": "./entitlements.mac.plist", "notarize": { "teamId": "YT49P7GXG4" - } + }, + "icon": "icons/icon.png" + }, + "linux": { + "target": ["deb"], + "category": "Utility", + "icon": "icons/" + }, + "win": { + "icon": "icons/icon.png" }, "artifactName": "jan-${os}-${arch}-${version}.${ext}" }, From a57dfe743b11201bf296078c302a8da813395eca Mon Sep 17 00:00:00 2001 From: Louis <133622055+louis-jan@users.noreply.github.com> Date: Tue, 10 Oct 2023 18:24:33 +0700 Subject: [PATCH 07/42] fixes: #247 - inference plugin should check nitro service available (#313) * fix: #247 - inference plugin should check nitro service available * fix: #247 check service status and emit error if any * chore: error handling * chore: typo * fix: open conversation does not work when model is deleted * chore: reload plugins in development mode without exiting the process * chore: move model file check to inference plugin * update package-lock.json --------- Co-authored-by: Hien To <> --- electron/core/plugins/data-plugin/module.ts | 12 +- .../inference-plugin/{index.js => index.ts} | 9 - .../core/plugins/inference-plugin/module.js | 102 --- .../core/plugins/inference-plugin/module.ts | 119 ++++ .../inference-plugin/package-lock.json | 595 ++++++++++++++---- .../plugins/inference-plugin/package.json | 20 +- .../plugins/inference-plugin/tsconfig.json | 22 + .../plugins/inference-plugin/types/index.d.ts | 7 + .../inference-plugin/webpack.config.js | 4 +- electron/main.ts | 19 +- web/app/_components/HistoryItem/index.tsx | 23 +- web/app/_components/InputToolbar/index.tsx | 20 +- web/app/_helpers/JotaiWrapper.tsx | 2 - web/app/_helpers/atoms/Conversation.atom.ts | 12 + web/app/_hooks/useCreateConversation.ts | 15 +- web/app/_hooks/useInitModel.ts | 14 +- web/app/_hooks/useSendChatMessage.ts | 19 +- web/app/_hooks/useStartStopModel.ts | 4 +- web/app/_models/Conversation.ts | 1 + web/app/_services/pluginService.ts | 6 +- web/shared/coreService.ts | 4 +- 21 files changed, 747 insertions(+), 282 deletions(-) rename electron/core/plugins/inference-plugin/{index.js => index.ts} (74%) delete mode 100644 electron/core/plugins/inference-plugin/module.js create mode 100644 electron/core/plugins/inference-plugin/module.ts create mode 100644 electron/core/plugins/inference-plugin/tsconfig.json create mode 100644 electron/core/plugins/inference-plugin/types/index.d.ts diff --git a/electron/core/plugins/data-plugin/module.ts b/electron/core/plugins/data-plugin/module.ts index 7d50a87081..3e01fe502b 100644 --- a/electron/core/plugins/data-plugin/module.ts +++ b/electron/core/plugins/data-plugin/module.ts @@ -129,6 +129,7 @@ function updateFinishedDownloadAt(fileName: string, time: number) { db.run(stmt, [time, fileName], (err: any) => { if (err) { console.log(err); + res(undefined); } else { console.log("Updated 1 row"); res("Updated"); @@ -150,7 +151,11 @@ function getUnfinishedDownloadModels() { const query = `SELECT * FROM models WHERE finish_download_at = -1 ORDER BY start_download_at DESC`; db.all(query, (err: Error, row: any) => { - res(row); + if (row) { + res(row); + } else { + res([]); + } }); db.close(); }); @@ -193,13 +198,10 @@ function getModelById(modelId: string) { path.join(app.getPath("userData"), "jan.db") ); - console.debug("Get model by id", modelId); db.get( `SELECT * FROM models WHERE id = ?`, [modelId], (err: any, row: any) => { - console.debug("Get model by id result", row); - if (row) { const product = { id: row.id, @@ -223,6 +225,8 @@ function getModelById(modelId: string) { downloadUrl: row.download_url, }; res(product); + } else { + res(undefined); } } ); diff --git a/electron/core/plugins/inference-plugin/index.js b/electron/core/plugins/inference-plugin/index.ts similarity index 74% rename from electron/core/plugins/inference-plugin/index.js rename to electron/core/plugins/inference-plugin/index.ts index 80281737c8..9f758f12f8 100644 --- a/electron/core/plugins/inference-plugin/index.js +++ b/electron/core/plugins/inference-plugin/index.ts @@ -9,14 +9,6 @@ const initModel = async (product) => } }); -const dispose = async () => - new Promise(async (resolve) => { - if (window.electronAPI) { - window.electronAPI - .invokePluginFunc(MODULE_PATH, "dispose") - .then((res) => resolve(res)); - } - }); const inferenceUrl = () => "http://localhost:3928/llama/chat_completion"; const stopModel = () => { @@ -27,6 +19,5 @@ const stopModel = () => { export function init({ register }) { register("initModel", "initModel", initModel); register("inferenceUrl", "inferenceUrl", inferenceUrl); - register("dispose", "dispose", dispose); register("stopModel", "stopModel", stopModel); } diff --git a/electron/core/plugins/inference-plugin/module.js b/electron/core/plugins/inference-plugin/module.js deleted file mode 100644 index 0e458bf2c5..0000000000 --- a/electron/core/plugins/inference-plugin/module.js +++ /dev/null @@ -1,102 +0,0 @@ -const path = require("path"); -const { app, dialog } = require("electron"); -const { spawn } = require("child_process"); -const fs = require("fs"); - -let subprocess = null; - -async function initModel(product) { - // fileName fallback - if (!product.fileName) { - product.fileName = product.file_name; - } - - if (!product.fileName) { - await dialog.showMessageBox({ - message: "Selected model does not have file name..", - }); - - return; - } - - if (subprocess) { - console.error( - "A subprocess is already running. Attempt to kill then reinit." - ); - dispose(); - } - - let binaryFolder = path.join(__dirname, "nitro"); // Current directory by default - - // Read the existing config - const configFilePath = path.join(binaryFolder, "config", "config.json"); - let config = {}; - if (fs.existsSync(configFilePath)) { - const rawData = fs.readFileSync(configFilePath, "utf-8"); - config = JSON.parse(rawData); - } - - // Update the llama_model_path - if (!config.custom_config) { - config.custom_config = {}; - } - - const modelPath = path.join(app.getPath("userData"), product.fileName); - - config.custom_config.llama_model_path = modelPath; - - // Write the updated config back to the file - fs.writeFileSync(configFilePath, JSON.stringify(config, null, 4)); - - let binaryName; - - if (process.platform === "win32") { - binaryName = "nitro_windows_amd64.exe"; - } else if (process.platform === "darwin") { // Mac OS platform - binaryName = process.arch === "arm64" ? "nitro_mac_arm64" : "nitro_mac_amd64"; - } else { - // Linux - binaryName = "nitro_linux_amd64_cuda"; // For other platforms - } - - const binaryPath = path.join(binaryFolder, binaryName); - - // Execute the binary - - subprocess = spawn(binaryPath, [configFilePath], { cwd: binaryFolder }); - - // Handle subprocess output - subprocess.stdout.on("data", (data) => { - console.log(`stdout: ${data}`); - }); - - subprocess.stderr.on("data", (data) => { - console.error(`stderr: ${data}`); - }); - - subprocess.on("close", (code) => { - console.log(`child process exited with code ${code}`); - subprocess = null; - }); -} - -function dispose() { - killSubprocess(); - // clean other registered resources here -} - -function killSubprocess() { - if (subprocess) { - subprocess.kill(); - subprocess = null; - console.log("Subprocess terminated."); - } else { - console.error("No subprocess is currently running."); - } -} - -module.exports = { - initModel, - killSubprocess, - dispose, -}; diff --git a/electron/core/plugins/inference-plugin/module.ts b/electron/core/plugins/inference-plugin/module.ts new file mode 100644 index 0000000000..ac70b8c685 --- /dev/null +++ b/electron/core/plugins/inference-plugin/module.ts @@ -0,0 +1,119 @@ +const path = require("path"); +const { app } = require("electron"); +const { spawn } = require("child_process"); +const fs = require("fs"); +const tcpPortUsed = require("tcp-port-used"); +const { killPortProcess } = require("kill-port-process"); + +let subprocess = null; +const PORT = 3928; + +const initModel = (product) => { + return ( + new Promise(async (resolve, reject) => { + if (!product?.fileName) { + reject("Model not found, please download again."); + } + if (subprocess) { + console.error( + "A subprocess is already running. Attempt to kill then reinit." + ); + killSubprocess(); + } + resolve(product?.fileName); + }) + // Kill port process if it is already in use + .then((fileName) => + tcpPortUsed + .waitUntilFree(PORT, 200, 3000) + .catch(() => killPortProcess(PORT)) + .then(() => fileName) + ) + // Spawn Nitro subprocess to load model + .then(() => { + let binaryFolder = path.join(__dirname, "nitro"); // Current directory by default + + // Read the existing config + const configFilePath = path.join(binaryFolder, "config", "config.json"); + let config: any = {}; + if (fs.existsSync(configFilePath)) { + const rawData = fs.readFileSync(configFilePath, "utf-8"); + config = JSON.parse(rawData); + } + + // Update the llama_model_path + if (!config.custom_config) { + config.custom_config = {}; + } + + const modelPath = path.join(app.getPath("userData"), product.fileName); + + config.custom_config.llama_model_path = modelPath; + + // Write the updated config back to the file + fs.writeFileSync(configFilePath, JSON.stringify(config, null, 4)); + + let binaryName; + + if (process.platform === "win32") { + binaryName = "nitro_windows_amd64.exe"; + } else if (process.platform === "darwin") { + // Mac OS platform + binaryName = + process.arch === "arm64" ? "nitro_mac_arm64" : "nitro_mac_amd64"; + } else { + // Linux + binaryName = "nitro_linux_amd64_cuda"; // For other platforms + } + + const binaryPath = path.join(binaryFolder, binaryName); + + // Execute the binary + + subprocess = spawn(binaryPath, [configFilePath], { cwd: binaryFolder }); + + // Handle subprocess output + subprocess.stdout.on("data", (data) => { + console.log(`stdout: ${data}`); + }); + + subprocess.stderr.on("data", (data) => { + console.error(`stderr: ${data}`); + }); + + subprocess.on("close", (code) => { + console.log(`child process exited with code ${code}`); + subprocess = null; + }); + }) + .then(() => tcpPortUsed.waitUntilUsed(PORT, 300, 30000)) + .then(() => { + return {}; + }) + .catch((err) => { + return { error: err }; + }) + ); +}; + +function dispose() { + killSubprocess(); + // clean other registered resources here +} + +function killSubprocess() { + if (subprocess) { + subprocess.kill(); + subprocess = null; + console.log("Subprocess terminated."); + } else { + killPortProcess(PORT); + console.error("No subprocess is currently running."); + } +} + +module.exports = { + initModel, + killSubprocess, + dispose, +}; diff --git a/electron/core/plugins/inference-plugin/package-lock.json b/electron/core/plugins/inference-plugin/package-lock.json index dc20857a50..9bb9c09e7b 100644 --- a/electron/core/plugins/inference-plugin/package-lock.json +++ b/electron/core/plugins/inference-plugin/package-lock.json @@ -8,13 +8,15 @@ "name": "inference-plugin", "version": "1.0.0", "bundleDependencies": [ - "electron-is-dev", - "node-llama-cpp" + "tcp-port-used", + "kill-port-process" ], "hasInstallScript": true, "license": "MIT", "dependencies": { - "electron-is-dev": "^2.0.0" + "kill-port-process": "^3.2.0", + "tcp-port-used": "^1.0.2", + "ts-loader": "^9.5.0" }, "devDependencies": { "cpx": "^1.5.0", @@ -39,7 +41,6 @@ "version": "0.3.3", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", - "dev": true, "dependencies": { "@jridgewell/set-array": "^1.0.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -53,7 +54,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", - "dev": true, "engines": { "node": ">=6.0.0" } @@ -62,7 +62,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true, "engines": { "node": ">=6.0.0" } @@ -71,7 +70,6 @@ "version": "0.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", - "dev": true, "dependencies": { "@jridgewell/gen-mapping": "^0.3.0", "@jridgewell/trace-mapping": "^0.3.9" @@ -80,14 +78,12 @@ "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.15", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.19", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", - "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -97,7 +93,6 @@ "version": "8.44.3", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.3.tgz", "integrity": "sha512-iM/WfkwAhwmPff3wZuPLYiHX18HI24jU8k1ZSH7P8FHwxTjZ2P6CoX2wnF43oprR+YXJM6UUxATkNvyv/JHd+g==", - "dev": true, "dependencies": { "@types/estree": "*", "@types/json-schema": "*" @@ -107,7 +102,6 @@ "version": "3.7.5", "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.5.tgz", "integrity": "sha512-JNvhIEyxVW6EoMIFIvj93ZOywYFatlpu9deeH6eSx6PE3WHYvHaQtmHmQeNw7aA81bYGBPPQqdtBm6b1SsQMmA==", - "dev": true, "dependencies": { "@types/eslint": "*", "@types/estree": "*" @@ -116,26 +110,22 @@ "node_modules/@types/estree": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.2.tgz", - "integrity": "sha512-VeiPZ9MMwXjO32/Xu7+OwflfmeoRwkE/qzndw42gGtgJwZopBnzy2gD//NN1+go1mADzkDcqf/KnFRSjTJ8xJA==", - "dev": true + "integrity": "sha512-VeiPZ9MMwXjO32/Xu7+OwflfmeoRwkE/qzndw42gGtgJwZopBnzy2gD//NN1+go1mADzkDcqf/KnFRSjTJ8xJA==" }, "node_modules/@types/json-schema": { "version": "7.0.13", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.13.tgz", - "integrity": "sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ==", - "dev": true + "integrity": "sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ==" }, "node_modules/@types/node": { "version": "20.8.2", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.2.tgz", - "integrity": "sha512-Vvycsc9FQdwhxE3y3DzeIxuEJbWGDsnrxvMADzTDF/lcdR9/K+AQIeAghTQsHtotg/q0j3WEOYS/jQgSdWue3w==", - "dev": true + "integrity": "sha512-Vvycsc9FQdwhxE3y3DzeIxuEJbWGDsnrxvMADzTDF/lcdR9/K+AQIeAghTQsHtotg/q0j3WEOYS/jQgSdWue3w==" }, "node_modules/@webassemblyjs/ast": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==", - "dev": true, "dependencies": { "@webassemblyjs/helper-numbers": "1.11.6", "@webassemblyjs/helper-wasm-bytecode": "1.11.6" @@ -144,26 +134,22 @@ "node_modules/@webassemblyjs/floating-point-hex-parser": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", - "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", - "dev": true + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==" }, "node_modules/@webassemblyjs/helper-api-error": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", - "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", - "dev": true + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==" }, "node_modules/@webassemblyjs/helper-buffer": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz", - "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==", - "dev": true + "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==" }, "node_modules/@webassemblyjs/helper-numbers": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", - "dev": true, "dependencies": { "@webassemblyjs/floating-point-hex-parser": "1.11.6", "@webassemblyjs/helper-api-error": "1.11.6", @@ -173,14 +159,12 @@ "node_modules/@webassemblyjs/helper-wasm-bytecode": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", - "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", - "dev": true + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==" }, "node_modules/@webassemblyjs/helper-wasm-section": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz", "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==", - "dev": true, "dependencies": { "@webassemblyjs/ast": "1.11.6", "@webassemblyjs/helper-buffer": "1.11.6", @@ -192,7 +176,6 @@ "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", - "dev": true, "dependencies": { "@xtuc/ieee754": "^1.2.0" } @@ -201,7 +184,6 @@ "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", - "dev": true, "dependencies": { "@xtuc/long": "4.2.2" } @@ -209,14 +191,12 @@ "node_modules/@webassemblyjs/utf8": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", - "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", - "dev": true + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==" }, "node_modules/@webassemblyjs/wasm-edit": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz", "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==", - "dev": true, "dependencies": { "@webassemblyjs/ast": "1.11.6", "@webassemblyjs/helper-buffer": "1.11.6", @@ -232,7 +212,6 @@ "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz", "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==", - "dev": true, "dependencies": { "@webassemblyjs/ast": "1.11.6", "@webassemblyjs/helper-wasm-bytecode": "1.11.6", @@ -245,7 +224,6 @@ "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz", "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==", - "dev": true, "dependencies": { "@webassemblyjs/ast": "1.11.6", "@webassemblyjs/helper-buffer": "1.11.6", @@ -257,7 +235,6 @@ "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz", "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==", - "dev": true, "dependencies": { "@webassemblyjs/ast": "1.11.6", "@webassemblyjs/helper-api-error": "1.11.6", @@ -271,7 +248,6 @@ "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz", "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==", - "dev": true, "dependencies": { "@webassemblyjs/ast": "1.11.6", "@xtuc/long": "4.2.2" @@ -324,20 +300,17 @@ "node_modules/@xtuc/ieee754": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" }, "node_modules/@xtuc/long": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" }, "node_modules/acorn": { "version": "8.10.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", - "dev": true, "bin": { "acorn": "bin/acorn" }, @@ -349,7 +322,6 @@ "version": "1.9.0", "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", - "dev": true, "peerDependencies": { "acorn": "^8" } @@ -358,7 +330,6 @@ "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -374,11 +345,24 @@ "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, "peerDependencies": { "ajv": "^6.9.1" } }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/anymatch": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", @@ -563,7 +547,6 @@ "version": "4.22.1", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", - "dev": true, "funding": [ { "type": "opencollective", @@ -594,8 +577,7 @@ "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, "node_modules/cache-base": { "version": "1.0.1", @@ -630,7 +612,6 @@ "version": "1.0.30001543", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001543.tgz", "integrity": "sha512-qxdO8KPWPQ+Zk6bvNpPeQIOH47qZSYdFZd6dXQzb2KzhnSXju4Kd7H1PkSJx6NICSMgo/IhRZRhhfPTHYpJUCA==", - "dev": true, "funding": [ { "type": "opencollective", @@ -646,6 +627,32 @@ } ] }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/chokidar": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", @@ -670,7 +677,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", - "dev": true, "engines": { "node": ">=6.0" } @@ -815,6 +821,22 @@ "node": ">=0.10.0" } }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, "node_modules/colorette": { "version": "2.0.20", "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", @@ -824,8 +846,7 @@ "node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" }, "node_modules/component-emitter": { "version": "1.3.0", @@ -898,12 +919,6 @@ "node": ">= 8" } }, - "node_modules/cross-spawn/node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, "node_modules/cross-spawn/node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -919,6 +934,23 @@ "node": ">= 8" } }, + "node_modules/debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "inBundle": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, "node_modules/decode-uri-component": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", @@ -928,6 +960,12 @@ "node": ">=0.10" } }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "inBundle": true + }, "node_modules/define-property": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", @@ -956,26 +994,15 @@ "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", "dev": true }, - "node_modules/electron-is-dev": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/electron-is-dev/-/electron-is-dev-2.0.0.tgz", - "integrity": "sha512-3X99K852Yoqu9AcW50qz3ibYBWY79/pBhlMCab8ToEWS48R0T9tyxRiQhwylE7zQdXrMnx2JKqUJyMPmt5FBqA==", - "inBundle": true, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/electron-to-chromium": { "version": "1.4.542", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.542.tgz", - "integrity": "sha512-6+cpa00G09N3sfh2joln4VUXHquWrOFx3FLZqiVQvl45+zS9DskDBTPvob+BhvFRmTBkyDSk0vvLMMRo/qc6mQ==", - "dev": true + "integrity": "sha512-6+cpa00G09N3sfh2joln4VUXHquWrOFx3FLZqiVQvl45+zS9DskDBTPvob+BhvFRmTBkyDSk0vvLMMRo/qc6mQ==" }, "node_modules/enhanced-resolve": { "version": "5.15.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", - "dev": true, "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -999,14 +1026,12 @@ "node_modules/es-module-lexer": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.1.tgz", - "integrity": "sha512-JUFAyicQV9mXc3YRxPnDlrfBKpqt6hUYzz9/boprUJHs4e4KVr3XwOF70doO6gwXUor6EWZJAyWAfKki84t20Q==", - "dev": true + "integrity": "sha512-JUFAyicQV9mXc3YRxPnDlrfBKpqt6hUYzz9/boprUJHs4e4KVr3XwOF70doO6gwXUor6EWZJAyWAfKki84t20Q==" }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, "engines": { "node": ">=6" } @@ -1015,7 +1040,6 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" @@ -1028,7 +1052,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, "dependencies": { "estraverse": "^5.2.0" }, @@ -1040,7 +1063,6 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, "engines": { "node": ">=4.0" } @@ -1049,7 +1071,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, "engines": { "node": ">=4.0" } @@ -1058,11 +1079,76 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true, "engines": { "node": ">=0.8.x" } }, + "node_modules/execa": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.9.0.tgz", + "integrity": "sha512-BbUMBiX4hqiHZUA5+JujIjNb6TyAlp2D5KLheMjMluwOuzcnylDL4AxZYLLn1n2AGB49eSWwyKvvEQoRpnAtmA==", + "inBundle": true, + "dependencies": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/execa/node_modules/cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==", + "inBundle": true, + "dependencies": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "node_modules/execa/node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "inBundle": true, + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/execa/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "inBundle": true, + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/execa/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "inBundle": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/execa/node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", + "inBundle": true + }, "node_modules/expand-brackets": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", @@ -1148,14 +1234,12 @@ "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" }, "node_modules/fastest-levenshtein": { "version": "1.0.16", @@ -1275,6 +1359,21 @@ "node": ">= 4.0" } }, + "node_modules/get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==", + "inBundle": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/get-them-args": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/get-them-args/-/get-them-args-1.3.2.tgz", + "integrity": "sha512-LRn8Jlk+DwZE4GTlDbT3Hikd1wSHgLMme/+7ddlqKd7ldwR6LjJgTVWzBnR01wnYGe4KgrXjg287RaI22UHmAw==", + "inBundle": true + }, "node_modules/get-value": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", @@ -1329,8 +1428,7 @@ "node_modules/glob-to-regexp": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" }, "node_modules/glob2base": { "version": "0.0.12", @@ -1347,8 +1445,7 @@ "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, "node_modules/has": { "version": "1.0.4", @@ -1363,7 +1460,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, "engines": { "node": ">=8" } @@ -1484,6 +1580,15 @@ "node": ">=10.13.0" } }, + "node_modules/ip-regex": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-4.3.0.tgz", + "integrity": "sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==", + "inBundle": true, + "engines": { + "node": ">=8" + } + }, "node_modules/is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", @@ -1660,6 +1765,21 @@ "node": ">=0.10.0" } }, + "node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "inBundle": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-url": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", + "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==", + "inBundle": true + }, "node_modules/is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", @@ -1669,12 +1789,32 @@ "node": ">=0.10.0" } }, + "node_modules/is2": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/is2/-/is2-2.0.9.tgz", + "integrity": "sha512-rZkHeBn9Zzq52sd9IUIV3a5mfwBY+o2HePMh0wkGBM4z4qjvy2GwVxQ6nNXSfw6MmVP6gf1QIlWjiOavhM3x5g==", + "inBundle": true, + "dependencies": { + "deep-is": "^0.1.3", + "ip-regex": "^4.1.0", + "is-url": "^1.2.4" + }, + "engines": { + "node": ">=v0.10.0" + } + }, "node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "dev": true }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "inBundle": true + }, "node_modules/isobject": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", @@ -1691,7 +1831,6 @@ "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "dev": true, "dependencies": { "@types/node": "*", "merge-stream": "^2.0.0", @@ -1704,14 +1843,28 @@ "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/kill-port-process": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/kill-port-process/-/kill-port-process-3.2.0.tgz", + "integrity": "sha512-EQd6g3yrfdb3tV3cJ2FC6qbMjKWdAV7yen7r/IkJ4LLsPSMA+AJXIpvNkzai2RcxFYXENcYGOOAanO4s2vcxMw==", + "inBundle": true, + "dependencies": { + "get-them-args": "1.3.2", + "pid-from-port": "1.1.3" + }, + "bin": { + "kill-port": "dist/bin/kill-port-process.js" + }, + "engines": { + "node": ">=14" + } }, "node_modules/kind-of": { "version": "3.2.2", @@ -1729,7 +1882,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", - "dev": true, "engines": { "node": ">=6.11.5" } @@ -1746,6 +1898,17 @@ "node": ">=8" } }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/map-cache": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", @@ -1776,8 +1939,7 @@ "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" }, "node_modules/micromatch": { "version": "2.3.11", @@ -1807,7 +1969,6 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, "engines": { "node": ">= 0.6" } @@ -1816,7 +1977,6 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, "dependencies": { "mime-db": "1.52.0" }, @@ -1903,6 +2063,12 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "inBundle": true + }, "node_modules/nan": { "version": "2.18.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.18.0.tgz", @@ -1962,14 +2128,12 @@ "node_modules/neo-async": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" }, "node_modules/node-releases": { "version": "2.0.13", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", - "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", - "dev": true + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==" }, "node_modules/normalize-path": { "version": "2.1.1", @@ -1983,6 +2147,27 @@ "node": ">=0.10.0" } }, + "node_modules/npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", + "inBundle": true, + "dependencies": { + "path-key": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "inBundle": true, + "engines": { + "node": ">=4" + } + }, "node_modules/object-copy": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", @@ -2120,6 +2305,15 @@ "wrappy": "1" } }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "inBundle": true, + "engines": { + "node": ">=4" + } + }, "node_modules/p-limit": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", @@ -2216,8 +2410,30 @@ "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pid-from-port": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/pid-from-port/-/pid-from-port-1.1.3.tgz", + "integrity": "sha512-OlE82n3yMOE5dY9RMOwxhoWefeMlxwk5IVxoj0sSzSFIlmvhN4obzTvO3s/d/b5JhcgXikjaspsy/HuUDTqbBg==", + "inBundle": true, + "dependencies": { + "execa": "^0.9.0" + }, + "engines": { + "node": ">=4" + } }, "node_modules/pkg-dir": { "version": "4.2.0", @@ -2255,11 +2471,16 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, + "node_modules/pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", + "inBundle": true + }, "node_modules/punycode": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", - "dev": true, "engines": { "node": ">=6" } @@ -2300,7 +2521,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, "dependencies": { "safe-buffer": "^5.1.0" } @@ -2804,7 +3024,6 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, "funding": [ { "type": "github", @@ -2833,7 +3052,6 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", - "dev": true, "dependencies": { "@types/json-schema": "^7.0.8", "ajv": "^6.12.5", @@ -2847,11 +3065,24 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/serialize-javascript": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", - "dev": true, "dependencies": { "randombytes": "^2.1.0" } @@ -2955,6 +3186,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "inBundle": true + }, "node_modules/snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", @@ -3120,7 +3357,6 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -3143,7 +3379,6 @@ "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -3240,6 +3475,15 @@ "node": ">=0.10.0" } }, + "node_modules/strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==", + "inBundle": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/subarg": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz", @@ -3253,7 +3497,6 @@ "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -3280,16 +3523,24 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true, "engines": { "node": ">=6" } }, + "node_modules/tcp-port-used": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tcp-port-used/-/tcp-port-used-1.0.2.tgz", + "integrity": "sha512-l7ar8lLUD3XS1V2lfoJlCBaeoaWo/2xfYt81hM7VlvR4RrMVFqfmzfhLVk40hAb368uitje5gPtBRL1m/DGvLA==", + "inBundle": true, + "dependencies": { + "debug": "4.3.1", + "is2": "^2.0.6" + } + }, "node_modules/terser": { "version": "5.21.0", "resolved": "https://registry.npmjs.org/terser/-/terser-5.21.0.tgz", "integrity": "sha512-WtnFKrxu9kaoXuiZFSGrcAvvBqAdmKx0SFNmVNYdJamMu9yyN3I/QF0FbH4QcqJQ+y1CJnzxGIKH0cSj+FGYRw==", - "dev": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", @@ -3307,7 +3558,6 @@ "version": "5.3.9", "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz", "integrity": "sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==", - "dev": true, "dependencies": { "@jridgewell/trace-mapping": "^0.3.17", "jest-worker": "^27.4.5", @@ -3389,6 +3639,99 @@ "node": ">=0.10.0" } }, + "node_modules/ts-loader": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.0.tgz", + "integrity": "sha512-LLlB/pkB4q9mW2yLdFMnK3dEHbrBjeZTYguaaIfusyojBgAGf5kF+O6KcWqiGzWqHk0LBsoolrp4VftEURhybg==", + "dependencies": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4", + "source-map": "^0.7.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "typescript": "*", + "webpack": "^5.0.0" + } + }, + "node_modules/ts-loader/node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ts-loader/node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ts-loader/node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/ts-loader/node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/ts-loader/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/ts-loader/node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/typescript": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/union-value": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", @@ -3465,7 +3808,6 @@ "version": "1.0.13", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", - "dev": true, "funding": [ { "type": "opencollective", @@ -3495,7 +3837,6 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, "dependencies": { "punycode": "^2.1.0" } @@ -3526,7 +3867,6 @@ "version": "2.4.0", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", - "dev": true, "dependencies": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" @@ -3539,7 +3879,6 @@ "version": "5.88.2", "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.2.tgz", "integrity": "sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ==", - "dev": true, "dependencies": { "@types/eslint-scope": "^3.7.3", "@types/estree": "^1.0.0", @@ -3653,11 +3992,22 @@ "version": "3.2.3", "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", - "dev": true, "engines": { "node": ">=10.13.0" } }, + "node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "inBundle": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, "node_modules/wildcard": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", @@ -3669,6 +4019,11 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" } } } diff --git a/electron/core/plugins/inference-plugin/package.json b/electron/core/plugins/inference-plugin/package.json index a6a899dbb7..3983432f64 100644 --- a/electron/core/plugins/inference-plugin/package.json +++ b/electron/core/plugins/inference-plugin/package.json @@ -10,23 +10,29 @@ "init" ], "scripts": { - "build": "webpack --config webpack.config.js", - "postinstall": "rimraf ./*.tgz && npm run build && cpx \"module.js\" \"dist\" && rimraf dist/nitro/* && cpx \"nitro/**\" \"dist/nitro\"", + "build": "tsc -b . && webpack --config webpack.config.js", + "postinstall": "rimraf ./*.tgz && npm run build && rimraf dist/nitro/* && cpx \"nitro/**\" \"dist/nitro\"", "build:publish": "npm pack && cpx *.tgz ../../pre-install" }, + "exports": { + ".": "./dist/index.js", + "./main": "./dist/module.js" + }, "devDependencies": { "cpx": "^1.5.0", "rimraf": "^3.0.2", "webpack": "^5.88.2", "webpack-cli": "^5.1.4" }, - "bundledDependencies": [ - "electron-is-dev", - "node-llama-cpp" - ], "dependencies": { - "electron-is-dev": "^2.0.0" + "kill-port-process": "^3.2.0", + "tcp-port-used": "^1.0.2", + "ts-loader": "^9.5.0" }, + "bundledDependencies": [ + "tcp-port-used", + "kill-port-process" + ], "engines": { "node": ">=18.0.0" }, diff --git a/electron/core/plugins/inference-plugin/tsconfig.json b/electron/core/plugins/inference-plugin/tsconfig.json new file mode 100644 index 0000000000..72d6f3732a --- /dev/null +++ b/electron/core/plugins/inference-plugin/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + /* Language and Environment */ + "target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, + /* Modules */ + "module": "ES6" /* Specify what module code is generated. */, + // "rootDir": "./", /* Specify the root folder within your source files. */ + // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "baseUrl": "." /* Specify the base directory to resolve non-relative module names. */, + // "paths": {} /* Specify a set of entries that re-map imports to additional lookup locations. */, + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "resolveJsonModule": true, /* Enable importing .json files. */ + + "outDir": "./dist" /* Specify an output folder for all emitted files. */, + "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, + "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, + /* Type Checking */ + "strict": false /* Enable all strict type-checking options. */, + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +} diff --git a/electron/core/plugins/inference-plugin/types/index.d.ts b/electron/core/plugins/inference-plugin/types/index.d.ts new file mode 100644 index 0000000000..a7ac3c8ac3 --- /dev/null +++ b/electron/core/plugins/inference-plugin/types/index.d.ts @@ -0,0 +1,7 @@ +export {}; + +declare global { + interface Window { + electronAPI?: any | undefined; + } +} diff --git a/electron/core/plugins/inference-plugin/webpack.config.js b/electron/core/plugins/inference-plugin/webpack.config.js index 2821852d4a..18696aa340 100644 --- a/electron/core/plugins/inference-plugin/webpack.config.js +++ b/electron/core/plugins/inference-plugin/webpack.config.js @@ -2,7 +2,7 @@ const path = require("path"); module.exports = { experiments: { outputModule: true }, - entry: "./index.js", // Adjust the entry point to match your project's main file + entry: "./index.ts", // Adjust the entry point to match your project's main file mode: "production", module: { rules: [ @@ -19,7 +19,7 @@ module.exports = { library: { type: "module" }, // Specify ESM output format }, resolve: { - extensions: [".js"], + extensions: [".ts", ".js"], }, // Add loaders and other configuration as needed for your project }; diff --git a/electron/main.ts b/electron/main.ts index ca5d9f187a..2321167650 100644 --- a/electron/main.ts +++ b/electron/main.ts @@ -156,8 +156,23 @@ function handleIPCs() { rmdir(fullPath, { recursive: true }, function (err) { if (err) console.log(err); - app.relaunch(); - app.exit(); + dispose(requiredModules); + + // just relaunch if packaged, should launch manually in development mode + if (app.isPackaged) { + app.relaunch(); + app.exit(); + } else { + for (const modulePath in requiredModules) { + delete require.cache[ + require.resolve( + join(app.getPath("userData"), "plugins", modulePath) + ) + ]; + } + setupPlugins(); + mainWindow?.reload(); + } }); }); diff --git a/web/app/_components/HistoryItem/index.tsx b/web/app/_components/HistoryItem/index.tsx index 6aaadaac27..e88fc1d48f 100644 --- a/web/app/_components/HistoryItem/index.tsx +++ b/web/app/_components/HistoryItem/index.tsx @@ -9,6 +9,8 @@ import { conversationStatesAtom, getActiveConvoIdAtom, setActiveConvoIdAtom, + updateConversationErrorAtom, + updateConversationWaitingForResponseAtom, } from "@/_helpers/atoms/Conversation.atom"; import { setMainViewStateAtom, @@ -33,6 +35,10 @@ const HistoryItem: React.FC = ({ const conversationStates = useAtomValue(conversationStatesAtom); const activeConvoId = useAtomValue(getActiveConvoIdAtom); const setActiveConvoId = useSetAtom(setActiveConvoIdAtom); + const updateConvWaiting = useSetAtom( + updateConversationWaitingForResponseAtom + ); + const updateConvError = useSetAtom(updateConversationErrorAtom); const isSelected = activeConvoId === conversation.id; const { initModel } = useInitModel(); @@ -42,13 +48,16 @@ const HistoryItem: React.FC = ({ DataService.GET_MODEL_BY_ID, conversation.model_id ); - if (!model) { - alert( - `Model ${conversation.model_id} not found! Please re-download the model first.` - ); - } else { - initModel(model); - } + + if (conversation.id) updateConvWaiting(conversation.id, true); + initModel(model).then((res: any) => { + if (conversation.id) updateConvWaiting(conversation.id, false); + + if (res?.error && conversation.id) { + updateConvError(conversation.id, res.error); + } + }); + if (activeConvoId !== conversation.id) { setMainViewState(MainViewState.Conversation); setActiveConvoId(conversation.id); diff --git a/web/app/_components/InputToolbar/index.tsx b/web/app/_components/InputToolbar/index.tsx index 99d362b19f..9dbd02f926 100644 --- a/web/app/_components/InputToolbar/index.tsx +++ b/web/app/_components/InputToolbar/index.tsx @@ -9,14 +9,14 @@ import { Fragment } from "react"; import { PlusIcon } from "@heroicons/react/24/outline"; import useCreateConversation from "@/_hooks/useCreateConversation"; import { currentProductAtom } from "@/_helpers/atoms/Model.atom"; -import { showingTyping } from "@/_helpers/JotaiWrapper"; import LoadingIndicator from "../LoadingIndicator"; +import { currentConvoStateAtom } from "@/_helpers/atoms/Conversation.atom"; const InputToolbar: React.FC = () => { const showingAdvancedPrompt = useAtomValue(showingAdvancedPromptAtom); const currentProduct = useAtomValue(currentProductAtom); const { requestCreateConvo } = useCreateConversation(); - const isTyping = useAtomValue(showingTyping); + const currentConvoState = useAtomValue(currentConvoStateAtom); if (showingAdvancedPrompt) { return

; @@ -34,12 +34,20 @@ const InputToolbar: React.FC = () => { return (
-
- {isTyping && ( -
+
+ {currentConvoState?.waitingForResponse === true && ( +
- )}{" "} + )} + {!currentConvoState?.waitingForResponse && + currentConvoState?.error && ( +
+ + {currentConvoState?.error?.toString()} + +
+ )}
{/* */} diff --git a/web/app/_helpers/JotaiWrapper.tsx b/web/app/_helpers/JotaiWrapper.tsx index 0c0f97fd58..9862f75956 100644 --- a/web/app/_helpers/JotaiWrapper.tsx +++ b/web/app/_helpers/JotaiWrapper.tsx @@ -13,8 +13,6 @@ export default function JotaiWrapper({ children }: Props) { export const currentPromptAtom = atom(""); -export const showingTyping = atom(false); - export const appDownloadProgress = atom(-1); export const searchingModelText = atom(""); diff --git a/web/app/_helpers/atoms/Conversation.atom.ts b/web/app/_helpers/atoms/Conversation.atom.ts index 7f1b312c9e..77a193c2d0 100644 --- a/web/app/_helpers/atoms/Conversation.atom.ts +++ b/web/app/_helpers/atoms/Conversation.atom.ts @@ -55,6 +55,18 @@ export const updateConversationWaitingForResponseAtom = atom( currentState[conversationId] = { ...currentState[conversationId], waitingForResponse, + error: undefined, + }; + set(conversationStatesAtom, currentState); + } +); +export const updateConversationErrorAtom = atom( + null, + (get, set, conversationId: string, error?: Error) => { + const currentState = { ...get(conversationStatesAtom) }; + currentState[conversationId] = { + ...currentState[conversationId], + error, }; set(conversationStatesAtom, currentState); } diff --git a/web/app/_hooks/useCreateConversation.ts b/web/app/_hooks/useCreateConversation.ts index 89c80144a5..100ffa9451 100644 --- a/web/app/_hooks/useCreateConversation.ts +++ b/web/app/_hooks/useCreateConversation.ts @@ -7,6 +7,8 @@ import { userConversationsAtom, setActiveConvoIdAtom, addNewConversationStateAtom, + updateConversationWaitingForResponseAtom, + updateConversationErrorAtom, } from "@/_helpers/atoms/Conversation.atom"; import useInitModel from "./useInitModel"; @@ -17,6 +19,10 @@ const useCreateConversation = () => { ); const setActiveConvoId = useSetAtom(setActiveConvoIdAtom); const addNewConvoState = useSetAtom(addNewConversationStateAtom); + const updateConvWaiting = useSetAtom( + updateConversationWaitingForResponseAtom + ); + const updateConvError = useSetAtom(updateConversationErrorAtom); const requestCreateConvo = async (model: Product) => { const conversationName = model.name; @@ -27,7 +33,14 @@ const useCreateConversation = () => { name: conversationName, }; const id = await executeSerial(DataService.CREATE_CONVERSATION, conv); - await initModel(model); + + if (id) updateConvWaiting(id, true); + initModel(model).then((res: any) => { + if (id) updateConvWaiting(id, false); + if (res?.error) { + updateConvError(id, res.error); + } + }); const mappedConvo: Conversation = { id, diff --git a/web/app/_hooks/useInitModel.ts b/web/app/_hooks/useInitModel.ts index 18f8d7b871..15ed78929a 100644 --- a/web/app/_hooks/useInitModel.ts +++ b/web/app/_hooks/useInitModel.ts @@ -1,6 +1,6 @@ import { Product } from "@/_models/Product"; import { executeSerial } from "@/_services/pluginService"; -import { InfereceService } from "../../shared/coreService"; +import { InferenceService } from "../../shared/coreService"; import { useAtom } from "jotai"; import { currentProductAtom } from "@/_helpers/atoms/Model.atom"; @@ -12,12 +12,14 @@ export default function useInitModel() { console.debug(`Model ${model.id} is already init. Ignore..`); return; } - try { - await executeSerial(InfereceService.INIT_MODEL, model); - console.debug(`Init model ${model.name} successfully!`); + const res = await executeSerial(InferenceService.INIT_MODEL, model); + if (res?.error) { + console.log("error occured: ", res); + return res; + } else { + console.log(`Init model successfully!`); setActiveModel(model); - } catch (err) { - console.error(`Init model ${model.name} failed: ${err}`); + return {}; } }; diff --git a/web/app/_hooks/useSendChatMessage.ts b/web/app/_hooks/useSendChatMessage.ts index ccc037d2f6..9746795f2f 100644 --- a/web/app/_hooks/useSendChatMessage.ts +++ b/web/app/_hooks/useSendChatMessage.ts @@ -1,7 +1,7 @@ -import { currentPromptAtom, showingTyping } from "@/_helpers/JotaiWrapper"; +import { currentPromptAtom } from "@/_helpers/JotaiWrapper"; import { useAtom, useAtomValue, useSetAtom } from "jotai"; import { selectAtom } from "jotai/utils"; -import { DataService, InfereceService } from "../../shared/coreService"; +import { DataService, InferenceService } from "../../shared/coreService"; import { MessageSenderType, RawMessage, @@ -18,6 +18,7 @@ import { import { currentConversationAtom, getActiveConvoIdAtom, + updateConversationWaitingForResponseAtom, } from "@/_helpers/atoms/Conversation.atom"; export default function useSendChatMessage() { @@ -26,6 +27,9 @@ export default function useSendChatMessage() { const addNewMessage = useSetAtom(addNewMessageAtom); const updateMessage = useSetAtom(updateMessageAtom); const activeConversationId = useAtomValue(getActiveConvoIdAtom) ?? ""; + const updateConvWaiting = useSetAtom( + updateConversationWaitingForResponseAtom + ); const chatMessagesHistory = useAtomValue( selectAtom( @@ -34,10 +38,11 @@ export default function useSendChatMessage() { ) ); const [currentPrompt, setCurrentPrompt] = useAtom(currentPromptAtom); - const [, setIsTyping] = useAtom(showingTyping); + const sendChatMessage = async () => { - setIsTyping(true); setCurrentPrompt(""); + const conversationId = activeConversationId; + updateConvWaiting(conversationId, true); const prompt = currentPrompt.trim(); const newMessage: RawMessage = { conversation_id: parseInt(currentConvo?.id ?? "0") ?? 0, @@ -65,7 +70,7 @@ export default function useSendChatMessage() { : "assistant", }; }); - const url = await executeSerial(InfereceService.INFERENCE_URL); + const url = await executeSerial(InferenceService.INFERENCE_URL); const response = await fetch(url, { method: "POST", headers: { @@ -108,7 +113,7 @@ export default function useSendChatMessage() { const lines = text.trim().split("\n"); for (const line of lines) { if (line.startsWith("data: ") && !line.includes("data: [DONE]")) { - setIsTyping(false); + updateConvWaiting(conversationId, false); const data = JSON.parse(line.replace("data: ", "")); answer += data.choices[0]?.delta?.content ?? ""; if (answer.startsWith("assistant: ")) { @@ -139,7 +144,7 @@ export default function useSendChatMessage() { .replace("T", " ") .replace(/\.\d+Z$/, ""), }); - setIsTyping(false); + updateConvWaiting(conversationId, false); }; return { sendChatMessage, diff --git a/web/app/_hooks/useStartStopModel.ts b/web/app/_hooks/useStartStopModel.ts index b04166a1b0..8d9e0c7bbe 100644 --- a/web/app/_hooks/useStartStopModel.ts +++ b/web/app/_hooks/useStartStopModel.ts @@ -1,5 +1,5 @@ import { executeSerial } from "@/_services/pluginService"; -import { DataService, InfereceService } from "../../shared/coreService"; +import { DataService, InferenceService } from "../../shared/coreService"; import useInitModel from "./useInitModel"; import { useSetAtom } from "jotai"; import { currentProductAtom } from "@/_helpers/atoms/Model.atom"; @@ -18,7 +18,7 @@ export default function useStartStopModel() { }; const stopModel = async (modelId: string) => { - await executeSerial(InfereceService.STOP_MODEL, modelId); + await executeSerial(InferenceService.STOP_MODEL, modelId); setActiveModel(undefined); }; diff --git a/web/app/_models/Conversation.ts b/web/app/_models/Conversation.ts index 1d435fd891..3010bba0d0 100644 --- a/web/app/_models/Conversation.ts +++ b/web/app/_models/Conversation.ts @@ -14,4 +14,5 @@ export interface Conversation { export type ConversationState = { hasMore: boolean; waitingForResponse: boolean; + error?: Error; }; diff --git a/web/app/_services/pluginService.ts b/web/app/_services/pluginService.ts index 2b86149cc7..deb2159389 100644 --- a/web/app/_services/pluginService.ts +++ b/web/app/_services/pluginService.ts @@ -6,7 +6,7 @@ import { import { CoreService, DataService, - InfereceService, + InferenceService, ModelManagementService, } from "../../shared/coreService"; @@ -14,7 +14,7 @@ export const isCorePluginInstalled = () => { if (!extensionPoints.get(DataService.GET_CONVERSATIONS)) { return false; } - if (!extensionPoints.get(InfereceService.INIT_MODEL)) { + if (!extensionPoints.get(InferenceService.INIT_MODEL)) { return false; } if (!extensionPoints.get(ModelManagementService.GET_DOWNLOADED_MODELS)) { @@ -33,7 +33,7 @@ export const setupBasePlugins = async () => { if ( !extensionPoints.get(DataService.GET_CONVERSATIONS) || - !extensionPoints.get(InfereceService.INIT_MODEL) || + !extensionPoints.get(InferenceService.INIT_MODEL) || !extensionPoints.get(ModelManagementService.GET_DOWNLOADED_MODELS) ) { const installed = await plugins.install(basePlugins); diff --git a/web/shared/coreService.ts b/web/shared/coreService.ts index 068ca02d25..8a2c5372fd 100644 --- a/web/shared/coreService.ts +++ b/web/shared/coreService.ts @@ -1,7 +1,7 @@ export type CoreService = | DataService | ModelService - | InfereceService + | InferenceService | ModelManagementService | SystemMonitoringService | PreferenceService; @@ -27,7 +27,7 @@ export enum ModelService { GET_MODELS = "getModels", } -export enum InfereceService { +export enum InferenceService { INFERENCE_URL = "inferenceUrl", INIT_MODEL = "initModel", STOP_MODEL = "stopModel", From bcab163c8ea6e3bc7999617806b8f5df96aeae31 Mon Sep 17 00:00:00 2001 From: hiento09 <136591877+hiento09@users.noreply.github.com> Date: Wed, 11 Oct 2023 18:20:29 +0700 Subject: [PATCH 08/42] Add release note template (#322) Co-authored-by: Hien To --- .github/release-drafter.yml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .github/release-drafter.yml diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml new file mode 100644 index 0000000000..91e3cc07bc --- /dev/null +++ b/.github/release-drafter.yml @@ -0,0 +1,25 @@ +name-template: 'v$RESOLVED_VERSION 🌈' +tag-template: 'v$RESOLVED_VERSION' +categories: + - title: '🚀 Features' + labels: + - 'type: enhancement' + - 'type: epic' + - 'type: feature request' + - title: '🐛 Bug Fixes' + labels: + - 'type: bug' + - title: '🧰 Maintenance' + labels: + - 'type: chore' + - 'type: ci' +change-template: '- $TITLE @$AUTHOR (#$NUMBER)' +change-title-escapes: '\<*_&' # You can add # and @ to disable mentions, and add ` to disable code blocks. +template: | + ## Changes + + $CHANGES + + ## Contributor + + $CONTRIBUTORS \ No newline at end of file From f290ca22a12c22bb769603ae0dbc8cf275752844 Mon Sep 17 00:00:00 2001 From: hiento09 <136591877+hiento09@users.noreply.github.com> Date: Wed, 11 Oct 2023 18:51:08 +0700 Subject: [PATCH 09/42] Chore/release note template (#323) * Add release note template * Switch Release Drafter from github app to github action workflow --------- Co-authored-by: Hien To --- .github/workflows/build-app.yml | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-app.yml b/.github/workflows/build-app.yml index 1174410e15..38093eba8d 100644 --- a/.github/workflows/build-app.yml +++ b/.github/workflows/build-app.yml @@ -155,4 +155,28 @@ jobs: run: | yarn build:publish-linux env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + update_release_draft: + needs: [build-macos, build-windows-x64, build-linux-x64] + permissions: + # write permission is required to create a github release + contents: write + # write permission is required for autolabeler + # otherwise, read permission is required at least + pull-requests: write + runs-on: ubuntu-latest + steps: + # (Optional) GitHub Enterprise requires GHE_HOST variable set + #- name: Set GHE_HOST + # run: | + # echo "GHE_HOST=${GITHUB_SERVER_URL##https:\/\/}" >> $GITHUB_ENV + + # Drafts your next Release notes as Pull Requests are merged into "master" + - uses: release-drafter/release-drafter@v5 + # (Optional) specify config name to use, relative to .github/. Default: release-drafter.yml + # with: + # config-name: my-config.yml + # disable-autolabeler: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file From a1e9da6ac392f0faab6ec9bc853544e8f78108ed Mon Sep 17 00:00:00 2001 From: hiento09 <136591877+hiento09@users.noreply.github.com> Date: Wed, 11 Oct 2023 19:11:07 +0700 Subject: [PATCH 10/42] Correct release name correspond to electron-build publish --- .github/release-drafter.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml index 91e3cc07bc..bafd5cb2af 100644 --- a/.github/release-drafter.yml +++ b/.github/release-drafter.yml @@ -1,4 +1,4 @@ -name-template: 'v$RESOLVED_VERSION 🌈' +name-template: '$RESOLVED_VERSION 🌈' tag-template: 'v$RESOLVED_VERSION' categories: - title: '🚀 Features' @@ -22,4 +22,4 @@ template: | ## Contributor - $CONTRIBUTORS \ No newline at end of file + $CONTRIBUTORS From f1f1f06f2312673e63f4f0fa4c44c10214b12a85 Mon Sep 17 00:00:00 2001 From: 0xSage <69952136+0xSage@users.noreply.github.com> Date: Thu, 12 Oct 2023 05:15:27 +0000 Subject: [PATCH 11/42] Update issue templates --- .github/ISSUE_TEMPLATE/bug_report.md | 6 ------ .github/ISSUE_TEMPLATE/discussion-thread.md | 4 +++- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 837bdb720c..116d665432 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -28,11 +28,5 @@ If applicable, add screenshots to help explain your problem. - Browser [e.g. chrome, safari] - Version [e.g. 22] -**Smartphone (please complete the following information):** - - Device: [e.g. iPhone6] - - OS: [e.g. iOS8.1] - - Browser [e.g. stock browser, safari] - - Version [e.g. 22] - **Additional context** Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/discussion-thread.md b/.github/ISSUE_TEMPLATE/discussion-thread.md index 09e52ae688..d15921191d 100644 --- a/.github/ISSUE_TEMPLATE/discussion-thread.md +++ b/.github/ISSUE_TEMPLATE/discussion-thread.md @@ -2,7 +2,7 @@ name: Discussion thread about: Start an open ended discussion title: 'Discussion: [TOPIC HERE]' -labels: '' +labels: 'type: discussion' assignees: '' --- @@ -11,4 +11,6 @@ assignees: '' **Discussion** +**Alternatives** + **Resources** From e5347b727362e6edda43500dc97e86afacf31391 Mon Sep 17 00:00:00 2001 From: hiento09 <136591877+hiento09@users.noreply.github.com> Date: Thu, 12 Oct 2023 13:49:41 +0700 Subject: [PATCH 12/42] Add Documentation category to release note template (#332) --- .github/release-drafter.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml index bafd5cb2af..4e87f452d8 100644 --- a/.github/release-drafter.yml +++ b/.github/release-drafter.yml @@ -13,6 +13,9 @@ categories: labels: - 'type: chore' - 'type: ci' + - title: '📖 Documentaion' + labels: + - 'type: documentation' change-template: '- $TITLE @$AUTHOR (#$NUMBER)' change-title-escapes: '\<*_&' # You can add # and @ to disable mentions, and add ` to disable code blocks. template: | From cb25a69909f96689aaef80cd96225d62fb468704 Mon Sep 17 00:00:00 2001 From: hiento09 <136591877+hiento09@users.noreply.github.com> Date: Thu, 12 Oct 2023 16:38:21 +0700 Subject: [PATCH 13/42] Fix #290: Add description in package.json and rename to jan (#333) Co-authored-by: Hien To --- README.md | 2 +- electron/package.json | 5 +++-- electron/tests/main.e2e.spec.ts | 4 ++-- package-lock.json | 4 ++-- package.json | 22 +++++++++++----------- 5 files changed, 19 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 5103c9f902..be2cf47772 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ To reset your installation: 1. Delete Jan Application from /Applications 1. Clear cache: -`rm -rf /Users/$(whoami)/Library/Application\ Support/jan-electron` +`rm -rf /Users/$(whoami)/Library/Application\ Support/jan` OR `rm -rf /Users/$(whoami)/Library/Application\ Support/jan` diff --git a/electron/package.json b/electron/package.json index 615659dd68..a4c3cd3cd1 100644 --- a/electron/package.json +++ b/electron/package.json @@ -1,10 +1,11 @@ { - "name": "jan-electron", + "name": "jan", "version": "0.1.3", "main": "./build/main.js", "author": "Jan ", "license": "MIT", - "homepage": "./", + "homepage": "https://github.com/janhq/jan/tree/main/electron", + "description": "Use offline LLMs with your own data. Run open source models like Llama2 or Falcon on your internal computers/servers.", "build": { "appId": "jan.ai.app", "productName": "Jan", diff --git a/electron/tests/main.e2e.spec.ts b/electron/tests/main.e2e.spec.ts index 2a4fc5931e..85c3d5c7a4 100644 --- a/electron/tests/main.e2e.spec.ts +++ b/electron/tests/main.e2e.spec.ts @@ -22,9 +22,9 @@ test.beforeAll(async () => { expect(appInfo.asar).toBe(true); expect(appInfo.executable).toBeTruthy(); expect(appInfo.main).toBeTruthy(); - expect(appInfo.name).toBe("jan-electron"); + expect(appInfo.name).toBe("jan"); expect(appInfo.packageJson).toBeTruthy(); - expect(appInfo.packageJson.name).toBe("jan-electron"); + expect(appInfo.packageJson.name).toBe("jan"); expect(appInfo.platform).toBeTruthy(); expect(appInfo.platform).toBe(process.platform); expect(appInfo.resourcesDir).toBeTruthy(); diff --git a/package-lock.json b/package-lock.json index 7b1d8bf6a3..ccedb15ba6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,7 +27,7 @@ } }, "electron": { - "name": "jan-electron", + "name": "jan", "version": "0.1.3", "license": "MIT", "dependencies": { @@ -7168,7 +7168,7 @@ "node": ">=10" } }, - "node_modules/jan-electron": { + "node_modules/jan": { "resolved": "electron", "link": true }, diff --git a/package.json b/package.json index e848f8cc94..3d476e6774 100644 --- a/package.json +++ b/package.json @@ -14,23 +14,23 @@ ] }, "scripts": { - "lint": "yarn workspace jan-electron lint && yarn workspace jan-web lint", - "test": "yarn workspace jan-electron test:e2e", - "dev:electron": "yarn workspace jan-electron dev", + "lint": "yarn workspace jan lint && yarn workspace jan-web lint", + "test": "yarn workspace jan test:e2e", + "dev:electron": "yarn workspace jan dev", "dev:web": "yarn workspace jan-web dev", "dev": "concurrently --kill-others \"yarn dev:web\" \"wait-on http://localhost:3000 && yarn dev:electron\"", "build:web": "yarn workspace jan-web build && cpx \"web/out/**\" \"electron/renderer/\"", - "build:electron": "yarn workspace jan-electron build", + "build:electron": "yarn workspace jan build", "build:plugins": "rimraf ./electron/core/pre-install/*.tgz && concurrently \"cd ./electron/core/plugins/data-plugin && npm ci\" \"cd ./electron/core/plugins/inference-plugin && npm ci\" \"cd ./electron/core/plugins/model-management-plugin && npm ci\" \"cd ./electron/core/plugins/monitoring-plugin && npm ci\" && concurrently \"cd ./electron/core/plugins/data-plugin && npm run build:publish\" \"cd ./electron/core/plugins/inference-plugin && npm run build:publish\" \"cd ./electron/core/plugins/model-management-plugin && npm run build:publish\" \"cd ./electron/core/plugins/monitoring-plugin && npm run build:publish\"", "build:plugins-darwin": "rimraf ./electron/core/pre-install/*.tgz && concurrently \"cd ./electron/core/plugins/data-plugin && npm ci\" \"cd ./electron/core/plugins/inference-plugin && npm ci\" \"cd ./electron/core/plugins/model-management-plugin && npm ci\" \"cd ./electron/core/plugins/monitoring-plugin && npm ci\" && chmod +x ./electron/auto-sign.sh && ./electron/auto-sign.sh && concurrently \"cd ./electron/core/plugins/data-plugin && npm run build:publish\" \"cd ./electron/core/plugins/inference-plugin && npm run build:publish\" \"cd ./electron/core/plugins/model-management-plugin && npm run build:publish\" \"cd ./electron/core/plugins/monitoring-plugin && npm run build:publish\"", "build": "yarn build:web && yarn build:electron", - "build:darwin": "yarn build:web && yarn workspace jan-electron build:darwin", - "build:win32": "yarn build:web && yarn workspace jan-electron build:win32", - "build:linux": "yarn build:web && yarn workspace jan-electron build:linux", - "build:publish": "yarn build:web && yarn workspace jan-electron build:publish", - "build:publish-darwin": "yarn build:web && yarn workspace jan-electron build:publish-darwin", - "build:publish-win32": "yarn build:web && yarn workspace jan-electron build:publish-win32", - "build:publish-linux": "yarn build:web && yarn workspace jan-electron build:publish-linux" + "build:darwin": "yarn build:web && yarn workspace jan build:darwin", + "build:win32": "yarn build:web && yarn workspace jan build:win32", + "build:linux": "yarn build:web && yarn workspace jan build:linux", + "build:publish": "yarn build:web && yarn workspace jan build:publish", + "build:publish-darwin": "yarn build:web && yarn workspace jan build:publish-darwin", + "build:publish-win32": "yarn build:web && yarn workspace jan build:publish-win32", + "build:publish-linux": "yarn build:web && yarn workspace jan build:publish-linux" }, "devDependencies": { "concurrently": "^8.2.1", From d982dce090231f012aa2e4c4e16c5e85b0b3c08b Mon Sep 17 00:00:00 2001 From: James Date: Tue, 10 Oct 2023 07:18:40 -0700 Subject: [PATCH 14/42] feat: allowing user to fetch models from github Signed-off-by: James --- electron/core/plugins/data-plugin/index.ts | 1 + electron/core/plugins/data-plugin/module.ts | 389 +++++++---- .../core/plugins/inference-plugin/module.ts | 8 +- .../plugins/model-management-plugin/index.js | 10 + .../plugins/model-management-plugin/module.js | 225 ++++--- package-lock.json | 618 +++++------------- .../_components/ActiveModelTable/index.tsx | 6 +- .../_components/AvailableModelCard/index.tsx | 28 +- .../_components/ConversationalCard/index.tsx | 12 +- .../_components/ConversationalList/index.tsx | 10 +- .../_components/DownloadedModelCard/index.tsx | 18 +- .../_components/ExploreModelItem/index.tsx | 2 +- .../ExploreModelItemHeader/index.tsx | 2 +- .../_components/ExploreModelList/index.tsx | 44 +- web/app/_components/InputToolbar/index.tsx | 9 +- web/app/_components/ModelRow/index.tsx | 31 +- web/app/_components/ModelSelector/index.tsx | 4 +- web/app/_components/ModelTable/index.tsx | 4 +- .../_components/ModelVersionItem/index.tsx | 13 +- .../_components/ModelVersionList/index.tsx | 5 +- web/app/_components/MonitorBar/index.tsx | 4 +- web/app/_components/NewChatButton/index.tsx | 8 +- .../_components/SidebarEmptyHistory/index.tsx | 8 +- .../_helpers/atoms/DownloadedModel.atom.ts | 7 +- web/app/_helpers/atoms/Model.atom.ts | 8 +- web/app/_hooks/useCreateConversation.ts | 4 +- web/app/_hooks/useDeleteModel.ts | 6 +- web/app/_hooks/useDownloadModel.ts | 32 +- web/app/_hooks/useGetAvailableModels.ts | 54 -- web/app/_hooks/useGetConfiguredModels.ts | 20 + web/app/_hooks/useGetDownloadedModels.ts | 75 +-- web/app/_hooks/useInitModel.ts | 11 +- web/app/_hooks/useStartStopModel.ts | 4 +- web/app/_models/AssistantModel.ts | 65 ++ web/app/_models/ModelVersion.ts | 23 + web/app/_models/Product.ts | 35 +- web/app/_services/pluginService.ts | 4 +- web/shared/coreService.ts | 3 +- 38 files changed, 797 insertions(+), 1013 deletions(-) delete mode 100644 web/app/_hooks/useGetAvailableModels.ts create mode 100644 web/app/_hooks/useGetConfiguredModels.ts create mode 100644 web/app/_models/AssistantModel.ts create mode 100644 web/app/_models/ModelVersion.ts diff --git a/electron/core/plugins/data-plugin/index.ts b/electron/core/plugins/data-plugin/index.ts index 3609c629b1..cec71c820e 100644 --- a/electron/core/plugins/data-plugin/index.ts +++ b/electron/core/plugins/data-plugin/index.ts @@ -95,6 +95,7 @@ const createConversation = (conversation: any) => resolve(undefined); } }); + const createMessage = (message: any) => new Promise((resolve) => { if (window && window.electronAPI) { diff --git a/electron/core/plugins/data-plugin/module.ts b/electron/core/plugins/data-plugin/module.ts index 3e01fe502b..a9bc20040d 100644 --- a/electron/core/plugins/data-plugin/module.ts +++ b/electron/core/plugins/data-plugin/module.ts @@ -5,54 +5,78 @@ const { app } = require("electron"); const MODEL_TABLE_CREATION = ` CREATE TABLE IF NOT EXISTS models ( id TEXT PRIMARY KEY, - slug TEXT NOT NULL, name TEXT NOT NULL, - description TEXT NOT NULL, + short_description TEXT NOT NULL, avatar_url TEXT, long_description TEXT NOT NULL, - technical_description TEXT NOT NULL, author TEXT NOT NULL, version TEXT NOT NULL, model_url TEXT NOT NULL, nsfw INTEGER NOT NULL, - greeting TEXT NOT NULL, + tags TEXT NOT NULL, + default_greeting TEXT NOT NULL, type TEXT NOT NULL, - file_name TEXT NOT NULL, - download_url TEXT NOT NULL, - start_download_at INTEGER DEFAULT -1, - finish_download_at INTEGER DEFAULT -1, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP );`; +const MODEL_VERSION_TABLE_CREATION = ` +CREATE TABLE IF NOT EXISTS model_versions ( + id TEXT PRIMARY KEY, + name TEXT NOT NULL, + quant_method TEXT NOT NULL, + bits INTEGER NOT NULL, + size INTEGER NOT NULL, + max_ram_required INTEGER NOT NULL, + usecase TEXT NOT NULL, + download_link TEXT NOT NULL, + model_id TEXT NOT NULL, + start_download_at INTEGER DEFAULT -1, + finish_download_at INTEGER DEFAULT -1, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP +);`; + const MODEL_TABLE_INSERTION = ` -INSERT INTO models ( +INSERT OR IGNORE INTO models ( id, - slug, name, - description, + short_description, avatar_url, long_description, - technical_description, author, version, model_url, nsfw, - greeting, - type, - file_name, - download_url, + tags, + default_greeting, + type +) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)`; + +const MODEL_VERSION_TABLE_INSERTION = ` +INSERT INTO model_versions ( + id, + name, + quant_method, + bits, + size, + max_ram_required, + usecase, + download_link, + model_id, start_download_at -) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`; +) VALUES (?,?,?,?,?,?,?,?,?,?)`; + +const getDbPath = () => { + return path.join(app.getPath("userData"), "jan.db"); +}; function init() { - const db = new sqlite3.Database(path.join(app.getPath("userData"), "jan.db")); - console.log( - `Database located at ${path.join(app.getPath("userData"), "jan.db")}` - ); + const db = new sqlite3.Database(getDbPath()); + console.debug(`Database located at ${getDbPath()}`); db.serialize(() => { db.run(MODEL_TABLE_CREATION); + db.run(MODEL_VERSION_TABLE_CREATION); db.run( "CREATE TABLE IF NOT EXISTS conversations ( id INTEGER PRIMARY KEY, name TEXT, model_id TEXT, image TEXT, message TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP);" ); @@ -67,33 +91,59 @@ function init() { /** * Store a model in the database when user start downloading it * - * @param model Product + * @param params: { model, modelVersion } */ -function storeModel(model: any) { +function storeModel(params: any) { return new Promise((res) => { - const db = new sqlite3.Database( - path.join(app.getPath("userData"), "jan.db") - ); - console.debug("Inserting", JSON.stringify(model)); + const db = new sqlite3.Database(getDbPath()); + console.debug("Inserting", JSON.stringify(params)); + + const model = params.model; + const modelTags = model.tags.join(","); + const modelVersion = params.modelVersion; + db.serialize(() => { const stmt = db.prepare(MODEL_TABLE_INSERTION); stmt.run( model.id, - model.slug, model.name, - model.description, + model.shortDescription, model.avatarUrl, model.longDescription, - model.technicalDescription, model.author, model.version, model.modelUrl, model.nsfw, + modelTags, model.greeting, model.type, - model.fileName, - model.downloadUrl, - Date.now(), + function (err: any) { + if (err) { + // Handle the insertion error here + console.error(err.message); + res(undefined); + return; + } + // @ts-ignoreF + const id = this.lastID; + res(id); + return; + } + ); + + // insert modelVersion to MODEL_VERSION_TABLE_INSERTION + const stmt2 = db.prepare(MODEL_VERSION_TABLE_INSERTION); + stmt2.run( + modelVersion.id, + modelVersion.name, + modelVersion.quantMethod, + modelVersion.bits, + modelVersion.size, + modelVersion.maxRamRequired, + modelVersion.usecase, + modelVersion.downloadLink, + model.id, + modelVersion.startDownloadAt, function (err: any) { if (err) { // Handle the insertion error here @@ -108,6 +158,7 @@ function storeModel(model: any) { } ); stmt.finalize(); + stmt2.finalize(); }); db.close(); @@ -119,14 +170,15 @@ function storeModel(model: any) { * * @param model Product */ -function updateFinishedDownloadAt(fileName: string, time: number) { +function updateFinishedDownloadAt(modelVersionId: string) { return new Promise((res) => { - const db = new sqlite3.Database( - path.join(app.getPath("userData"), "jan.db") + const db = new sqlite3.Database(getDbPath()); + const time = Date.now(); + console.debug( + `Updating finished downloaded model version ${modelVersionId}` ); - console.debug(`Updating fileName ${fileName} to ${time}`); - const stmt = `UPDATE models SET finish_download_at = ? WHERE file_name = ?`; - db.run(stmt, [time, fileName], (err: any) => { + const stmt = `UPDATE model_versions SET finish_download_at = ? WHERE id = ?`; + db.run(stmt, [time, modelVersionId], (err: any) => { if (err) { console.log(err); res(undefined); @@ -145,11 +197,9 @@ function updateFinishedDownloadAt(fileName: string, time: number) { */ function getUnfinishedDownloadModels() { return new Promise((res) => { - const db = new sqlite3.Database( - path.join(app.getPath("userData"), "jan.db") - ); + const db = new sqlite3.Database(getDbPath()); - const query = `SELECT * FROM models WHERE finish_download_at = -1 ORDER BY start_download_at DESC`; + const query = `SELECT * FROM model_versions WHERE finish_download_at = -1 ORDER BY start_download_at DESC`; db.all(query, (err: Error, row: any) => { if (row) { res(row); @@ -161,28 +211,85 @@ function getUnfinishedDownloadModels() { }); } -function getFinishedDownloadModels() { - return new Promise((res) => { - const db = new sqlite3.Database( - path.join(app.getPath("userData"), "jan.db") - ); +async function getFinishedDownloadModels() { + const db = new sqlite3.Database(getDbPath()); - const query = `SELECT * FROM models WHERE finish_download_at != -1 ORDER BY finish_download_at DESC`; - db.all(query, (err: Error, row: any) => { - res(row?.map((item: any) => parseToProduct(item)) ?? []); + const query = `SELECT * FROM model_versions WHERE finish_download_at != -1 ORDER BY finish_download_at DESC`; + const modelVersions: any = await new Promise((resolve, reject) => { + db.all(query, (err: Error, rows: any[]) => { + if (err) { + reject(err); + } else { + resolve(rows); + } }); - db.close(); }); + + const models = await Promise.all( + modelVersions.map(async (modelVersion) => { + const modelQuery = `SELECT * FROM models WHERE id = ?`; + return new Promise((resolve, reject) => { + db.get(modelQuery, [modelVersion.model_id], (err: Error, row: any) => { + if (err) { + reject(err); + } else { + resolve(row); + } + }); + }); + }) + ); + + const downloadedModels = []; + modelVersions.forEach((modelVersion: any) => { + const model = models.find((m: any) => m.id === modelVersion.model_id); + + if (!model) { + return; + } + + const assistantModel = { + id: modelVersion.id, + name: modelVersion.name, + quantMethod: modelVersion.quant_method, + bits: modelVersion.bits, + size: modelVersion.size, + maxRamRequired: modelVersion.max_ram_required, + usecase: modelVersion.usecase, + downloadLink: modelVersion.download_link, + startDownloadAt: modelVersion.start_download_at, + finishDownloadAt: modelVersion.finish_download_at, + productId: model.id, + productName: model.name, + shortDescription: model.short_description, + longDescription: model.long_description, + avatarUrl: model.avatar_url, + author: model.author, + version: model.version, + modelUrl: model.model_url, + nsfw: model.nsfw === 0 ? false : true, + greeting: model.default_greeting, + type: model.type, + createdAt: new Date(model.created_at).getTime(), + updatedAt: new Date(model.updated_at ?? "").getTime(), + status: "", + releaseDate: -1, + tags: model.tags.split(","), + }; + downloadedModels.push(assistantModel); + }); + + db.close(); + + return downloadedModels; } function deleteDownloadModel(modelId: string) { return new Promise((res) => { - const db = new sqlite3.Database( - path.join(app.getPath("userData"), "jan.db") - ); - console.log(`Deleting ${modelId}`); + const db = new sqlite3.Database(getDbPath()); + console.debug(`Deleting ${modelId}`); db.serialize(() => { - const stmt = db.prepare("DELETE FROM models WHERE id = ?"); + const stmt = db.prepare("DELETE FROM model_versions WHERE id = ?"); stmt.run(modelId); stmt.finalize(); res(modelId); @@ -192,54 +299,101 @@ function deleteDownloadModel(modelId: string) { }); } -function getModelById(modelId: string) { - return new Promise((res) => { - const db = new sqlite3.Database( - path.join(app.getPath("userData"), "jan.db") - ); - +async function fetchModelVersion(db: any, versionId: string) { + return new Promise((resolve, reject) => { db.get( - `SELECT * FROM models WHERE id = ?`, - [modelId], - (err: any, row: any) => { - if (row) { - const product = { - id: row.id, - slug: row.slug, - name: row.name, - description: row.description, - avatarUrl: row.avatar_url, - longDescription: row.long_description, - technicalDescription: row.technical_description, - author: row.author, - version: row.version, - modelUrl: row.model_url, - nsfw: row.nsfw, - greeting: row.greeting, - type: row.type, - inputs: row.inputs, - outputs: row.outputs, - createdAt: new Date(row.created_at), - updatedAt: new Date(row.updated_at), - fileName: row.file_name, - downloadUrl: row.download_url, - }; - res(product); + "SELECT * FROM model_versions WHERE id = ?", + [versionId], + (err, row) => { + if (err) { + reject(err); } else { - res(undefined); + if (row) { + const product = { + id: row.id, + slug: row.slug, + name: row.name, + description: row.description, + avatarUrl: row.avatar_url, + longDescription: row.long_description, + technicalDescription: row.technical_description, + author: row.author, + version: row.version, + modelUrl: row.model_url, + nsfw: row.nsfw, + greeting: row.greeting, + type: row.type, + inputs: row.inputs, + outputs: row.outputs, + createdAt: new Date(row.created_at), + updatedAt: new Date(row.updated_at), + fileName: row.file_name, + downloadUrl: row.download_url, + }; + resolve(product); + } else { + resolve(undefined); + } } } ); + }); +} - db.close(); +async function fetchModel(db: any, modelId: string) { + return new Promise((resolve, reject) => { + db.get("SELECT * FROM models WHERE id = ?", [modelId], (err, row) => { + if (err) { + reject(err); + } else { + resolve(row); + } + }); }); } +const getModelById = async (versionId: string): Promise => { + const db = new sqlite3.Database(getDbPath()); + const modelVersion: any | undefined = await fetchModelVersion(db, versionId); + if (!modelVersion) return undefined; + const model: any | undefined = await fetchModel(db, modelVersion.model_id); + if (!model) return undefined; + + const assistantModel = { + id: modelVersion.id, + name: modelVersion.name, + quantMethod: modelVersion.quant_method, + bits: modelVersion.bits, + size: modelVersion.size, + maxRamRequired: modelVersion.max_ram_required, + usecase: modelVersion.usecase, + downloadLink: modelVersion.download_link, + startDownloadAt: modelVersion.start_download_at, + finishDownloadAt: modelVersion.finish_download_at, + productId: model.id, + productName: model.name, + shortDescription: model.short_description, + longDescription: model.long_description, + avatarUrl: model.avatar_url, + author: model.author, + version: model.version, + modelUrl: model.model_url, + nsfw: model.nsfw === 0 ? false : true, + greeting: model.default_greeting, + type: model.type, + createdAt: new Date(model.created_at).getTime(), + updatedAt: new Date(model.updated_at ?? "").getTime(), + status: "", + releaseDate: -1, + tags: model.tags.split(","), + }; + + return assistantModel; +}; + function getConversations() { return new Promise((res) => { - const db = new sqlite3.Database( - path.join(app.getPath("userData"), "jan.db") - ); + const db = new sqlite3.Database(getDbPath()); db.all( "SELECT * FROM conversations ORDER BY updated_at DESC", @@ -250,11 +404,10 @@ function getConversations() { db.close(); }); } + function storeConversation(conversation: any): Promise { return new Promise((res) => { - const db = new sqlite3.Database( - path.join(app.getPath("userData"), "jan.db") - ); + const db = new sqlite3.Database(getDbPath()); db.serialize(() => { const stmt = db.prepare( @@ -287,9 +440,7 @@ function storeConversation(conversation: any): Promise { function storeMessage(message: any): Promise { return new Promise((res) => { - const db = new sqlite3.Database( - path.join(app.getPath("userData"), "jan.db") - ); + const db = new sqlite3.Database(getDbPath()); db.serialize(() => { const stmt = db.prepare( @@ -319,11 +470,10 @@ function storeMessage(message: any): Promise { db.close(); }); } + function updateMessage(message: any): Promise { return new Promise((res) => { - const db = new sqlite3.Database( - path.join(app.getPath("userData"), "jan.db") - ); + const db = new sqlite3.Database(getDbPath()); db.serialize(() => { const stmt = db.prepare( @@ -340,9 +490,7 @@ function updateMessage(message: any): Promise { function deleteConversation(id: any) { return new Promise((res) => { - const db = new sqlite3.Database( - path.join(app.getPath("userData"), "jan.db") - ); + const db = new sqlite3.Database(getDbPath()); db.serialize(() => { const deleteConv = db.prepare("DELETE FROM conversations WHERE id = ?"); @@ -362,9 +510,7 @@ function deleteConversation(id: any) { function getConversationMessages(conversation_id: any) { return new Promise((res) => { - const db = new sqlite3.Database( - path.join(app.getPath("userData"), "jan.db") - ); + const db = new sqlite3.Database(getDbPath()); const query = `SELECT * FROM messages WHERE conversation_id = ${conversation_id} ORDER BY id DESC`; db.all(query, (err: Error, row: any) => { @@ -374,31 +520,6 @@ function getConversationMessages(conversation_id: any) { }); } -function parseToProduct(row: any) { - const product = { - id: row.id, - slug: row.slug, - name: row.name, - description: row.description, - avatarUrl: row.avatar_url, - longDescription: row.long_description, - technicalDescription: row.technical_description, - author: row.author, - version: row.version, - modelUrl: row.model_url, - nsfw: row.nsfw, - greeting: row.greeting, - type: row.type, - inputs: row.inputs, - outputs: row.outputs, - createdAt: new Date(row.created_at), - updatedAt: new Date(row.updated_at), - fileName: row.file_name, - downloadUrl: row.download_url, - }; - return product; -} - module.exports = { init, getConversations, diff --git a/electron/core/plugins/inference-plugin/module.ts b/electron/core/plugins/inference-plugin/module.ts index ac70b8c685..e80bc804c5 100644 --- a/electron/core/plugins/inference-plugin/module.ts +++ b/electron/core/plugins/inference-plugin/module.ts @@ -8,10 +8,10 @@ const { killPortProcess } = require("kill-port-process"); let subprocess = null; const PORT = 3928; -const initModel = (product) => { +const initModel = (fileName) => { return ( new Promise(async (resolve, reject) => { - if (!product?.fileName) { + if (!fileName) { reject("Model not found, please download again."); } if (subprocess) { @@ -20,7 +20,7 @@ const initModel = (product) => { ); killSubprocess(); } - resolve(product?.fileName); + resolve(fileName); }) // Kill port process if it is already in use .then((fileName) => @@ -46,7 +46,7 @@ const initModel = (product) => { config.custom_config = {}; } - const modelPath = path.join(app.getPath("userData"), product.fileName); + const modelPath = path.join(app.getPath("userData"), fileName); config.custom_config.llama_model_path = modelPath; diff --git a/electron/core/plugins/model-management-plugin/index.js b/electron/core/plugins/model-management-plugin/index.js index 702a04374c..f19382d660 100644 --- a/electron/core/plugins/model-management-plugin/index.js +++ b/electron/core/plugins/model-management-plugin/index.js @@ -47,6 +47,15 @@ const searchModels = async (params) => } }); +const getConfiguredModels = async () => + new Promise(async (resolve) => { + if (window.electronAPI) { + window.electronAPI + .invokePluginFunc(MODULE_PATH, "getConfiguredModels") + .then((res) => resolve(res)); + } + }); + // Register all the above functions and objects with the relevant extension points export function init({ register }) { register("getDownloadedModels", "getDownloadedModels", getDownloadedModels); @@ -54,4 +63,5 @@ export function init({ register }) { register("downloadModel", "downloadModel", downloadModel); register("deleteModel", "deleteModel", deleteModel); register("searchModels", "searchModels", searchModels); + register("getConfiguredModels", "getConfiguredModels", getConfiguredModels); } diff --git a/electron/core/plugins/model-management-plugin/module.js b/electron/core/plugins/model-management-plugin/module.js index ced07973e3..a5a4ff02cb 100644 --- a/electron/core/plugins/model-management-plugin/module.js +++ b/electron/core/plugins/model-management-plugin/module.js @@ -1,95 +1,16 @@ -const path = require("path"); -const { readdirSync, lstatSync } = require("fs"); -const { app } = require("electron"); const { listModels, listFiles, fileDownloadInfo } = require("@huggingface/hub"); +const https = require("https"); let modelsIterator = undefined; let currentSearchOwner = undefined; -const ALL_MODELS = [ - { - id: "llama-2-7b-chat.Q4_K_M.gguf.bin", - slug: "llama-2-7b-chat.Q4_K_M.gguf.bin", - name: "Llama 2 7B Chat - GGUF", - description: "medium, balanced quality - recommended", - avatarUrl: - "https://aeiljuispo.cloudimg.io/v7/https://cdn-uploads.huggingface.co/production/uploads/6426d3f3a7723d62b53c259b/tvPikpAzKTKGN5wrpadOJ.jpeg?w=200&h=200&f=face", - longDescription: - "GGUF is a new format introduced by the llama.cpp team on August 21st 2023. It is a replacement for GGML, which is no longer supported by llama.cpp. GGUF offers numerous advantages over GGML, such as better tokenisation, and support for special tokens. It is also supports metadata, and is designed to be extensible.", - technicalDescription: - 'GGML_TYPE_Q4_K - "type-1" 4-bit quantization in super-blocks containing 8 blocks, each block having 32 weights. Scales and mins are quantized with 6 bits. This ends up using 4.5 bpw.', - author: "The Bloke", - version: "1.0.0", - modelUrl: "https://google.com", - nsfw: false, - greeting: "Hello there", - type: "LLM", - inputs: undefined, - outputs: undefined, - createdAt: 0, - updatedAt: undefined, - fileName: "llama-2-7b-chat.Q4_K_M.gguf.bin", - downloadUrl: - "https://huggingface.co/TheBloke/Llama-2-7b-Chat-GGUF/resolve/main/llama-2-7b-chat.Q4_K_M.gguf", - }, - { - id: "llama-2-13b-chat.Q4_K_M.gguf", - slug: "llama-2-13b-chat.Q4_K_M.gguf", - name: "Llama 2 13B Chat - GGUF", - description: - "medium, balanced quality - not recommended for RAM 16GB and below", - avatarUrl: - "https://aeiljuispo.cloudimg.io/v7/https://cdn-uploads.huggingface.co/production/uploads/6426d3f3a7723d62b53c259b/tvPikpAzKTKGN5wrpadOJ.jpeg?w=200&h=200&f=face", - longDescription: - "GGUF is a new format introduced by the llama.cpp team on August 21st 2023. It is a replacement for GGML, which is no longer supported by llama.cpp. GGUF offers numerous advantages over GGML, such as better tokenisation, and support for special tokens. It is also supports metadata, and is designed to be extensible.", - technicalDescription: - 'GGML_TYPE_Q4_K - "type-1" 4-bit quantization in super-blocks containing 8 blocks, each block having 32 weights. Scales and mins are quantized with 6 bits. This ends up using 4.5 bpw.', - author: "The Bloke", - version: "1.0.0", - modelUrl: "https://google.com", - nsfw: false, - greeting: "Hello there", - type: "LLM", - inputs: undefined, - outputs: undefined, - createdAt: 0, - updatedAt: undefined, - fileName: "llama-2-13b-chat.Q4_K_M.gguf.bin", - downloadUrl: - "https://huggingface.co/TheBloke/Llama-2-13B-chat-GGUF/resolve/main/llama-2-13b-chat.Q4_K_M.gguf", - }, -]; - -function getDownloadedModels() { - const userDataPath = app.getPath("userData"); - - const allBinariesName = []; - var files = readdirSync(userDataPath); - for (var i = 0; i < files.length; i++) { - var filename = path.join(userDataPath, files[i]); - var stat = lstatSync(filename); - if (stat.isDirectory()) { - // ignore - } else if (filename.endsWith(".bin")) { - var binaryName = path.basename(filename); - allBinariesName.push(binaryName); - } - } - - const downloadedModels = ALL_MODELS.map((model) => { - if ( - model.fileName && - allBinariesName - .map((t) => t.toLowerCase()) - .includes(model.fileName.toLowerCase()) - ) { - return model; - } - return undefined; - }).filter((m) => m !== undefined); - - return downloadedModels; -} +// 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 = []; @@ -161,17 +82,131 @@ const listFilesByName = async (modelName) => { return fileDownloadInfoMap; }; -function getAvailableModels() { - const downloadedModelIds = getDownloadedModels().map((model) => model.id); - return ALL_MODELS.filter((model) => { - if (!downloadedModelIds.includes(model.id)) { - return model; - } +async function getConfiguredModels() { + const files = 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 = { - getDownloadedModels, - getAvailableModels, searchModels, + getConfiguredModels, }; diff --git a/package-lock.json b/package-lock.json index ccedb15ba6..5143bc970b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -32,22 +32,24 @@ "license": "MIT", "dependencies": { "@npmcli/arborist": "^7.1.0", - "electron-mocha": "^12.1.0", + "@uiball/loaders": "^1.3.0", "electron-store": "^8.1.0", "electron-updater": "^6.1.4", "pacote": "^17.0.4", + "react-intersection-observer": "^9.5.2", "request": "^2.88.2", - "request-progress": "^3.0.0" + "request-progress": "^3.0.0", + "use-debounce": "^9.0.4" }, "devDependencies": { + "@electron/notarize": "^2.1.0", "@playwright/test": "^1.38.1", "@typescript-eslint/eslint-plugin": "^6.7.3", "@typescript-eslint/parser": "^6.7.3", "electron": "26.2.1", "electron-builder": "^24.6.4", "electron-playwright-helpers": "^1.6.0", - "eslint-plugin-react": "^7.33.2", - "xvfb-maybe": "^0.2.1" + "eslint-plugin-react": "^7.33.2" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -711,6 +713,126 @@ "node": ">= 10" } }, + "node_modules/@next/swc-darwin-x64": { + "version": "13.4.10", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.10.tgz", + "integrity": "sha512-ngXhUBbcZIWZWqNbQSNxQrB9T1V+wgfCzAor2olYuo/YpaL6mUYNUEgeBMhr8qwV0ARSgKaOp35lRvB7EmCRBg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "13.4.10", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.10.tgz", + "integrity": "sha512-SjCZZCOmHD4uyM75MVArSAmF5Y+IJSGroPRj2v9/jnBT36SYFTORN8Ag/lhw81W9EeexKY/CUg2e9mdebZOwsg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "13.4.10", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.10.tgz", + "integrity": "sha512-F+VlcWijX5qteoYIOxNiBbNE8ruaWuRlcYyIRK10CugqI/BIeCDzEDyrHIHY8AWwbkTwe6GRHabMdE688Rqq4Q==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "13.4.10", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.10.tgz", + "integrity": "sha512-WDv1YtAV07nhfy3i1visr5p/tjiH6CeXp4wX78lzP1jI07t4PnHHG1WEDFOduXh3WT4hG6yN82EQBQHDi7hBrQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "13.4.10", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.10.tgz", + "integrity": "sha512-zFkzqc737xr6qoBgDa3AwC7jPQzGLjDlkNmt/ljvQJ/Veri5ECdHjZCUuiTUfVjshNIIpki6FuP0RaQYK9iCRg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "13.4.10", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.10.tgz", + "integrity": "sha512-IboRS8IWz5mWfnjAdCekkl8s0B7ijpWeDwK2O8CdgZkoCDY0ZQHBSGiJ2KViAG6+BJVfLvcP+a2fh6cdyBr9QQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-ia32-msvc": { + "version": "13.4.10", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.10.tgz", + "integrity": "sha512-bSA+4j8jY4EEiwD/M2bol4uVEu1lBlgsGdvM+mmBm/BbqofNBfaZ2qwSbwE2OwbAmzNdVJRFRXQZ0dkjopTRaQ==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "13.4.10", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.10.tgz", + "integrity": "sha512-g2+tU63yTWmcVQKDGY0MV1PjjqgZtwM4rB1oVVi/v0brdZAcrcTV+04agKzWtvWroyFz6IqtT0MoZJA7PNyLVw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -1666,6 +1788,15 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@uiball/loaders": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@uiball/loaders/-/loaders-1.3.0.tgz", + "integrity": "sha512-w372e7PMt/s6LZ321HoghgDDU8fomamAzJfrVAdBUhsWERJEpxJMqG37NFztUq/T4J7nzzjkvZI4UX7Z2F/O6A==", + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, "node_modules/@xmldom/xmldom": { "version": "0.8.10", "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz", @@ -1788,14 +1919,6 @@ "ajv": "^6.9.1" } }, - "node_modules/ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "engines": { - "node": ">=6" - } - }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -2610,11 +2733,6 @@ "node": ">=8" } }, - "node_modules/browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==" - }, "node_modules/browserslist": { "version": "4.22.1", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", @@ -2856,17 +2974,6 @@ "node": ">=6" } }, - "node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/camelcase-css": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", @@ -3104,6 +3211,7 @@ "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, "license": "ISC", "dependencies": { "string-width": "^4.2.0", @@ -3607,17 +3715,6 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "license": "MIT" }, - "node_modules/decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/decode-named-character-reference": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz", @@ -4070,38 +4167,6 @@ "node": ">=14.0.0" } }, - "node_modules/electron-mocha": { - "version": "12.1.0", - "resolved": "https://registry.npmjs.org/electron-mocha/-/electron-mocha-12.1.0.tgz", - "integrity": "sha512-9ZIvyHGbet4ZtvF2NYYjGm7/yPljnTxbHo8psVX/HQAFPp9vZE0mCNWlzwE42keq/42gBW6W40MtKmgn1v42hQ==", - "dependencies": { - "ansi-colors": "^4.1.1", - "electron-window": "^0.8.0", - "mocha": "^10.2.0", - "which": "^3.0.0", - "yargs": "^17.7.2" - }, - "bin": { - "electron-mocha": "bin/electron-mocha" - }, - "engines": { - "node": ">= 16.0.0" - } - }, - "node_modules/electron-mocha/node_modules/which": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", - "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/which.js" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/electron-playwright-helpers": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/electron-playwright-helpers/-/electron-playwright-helpers-1.6.0.tgz", @@ -4163,14 +4228,6 @@ "tiny-typed-emitter": "^2.1.0" } }, - "node_modules/electron-window": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/electron-window/-/electron-window-0.8.1.tgz", - "integrity": "sha512-W1i9LfnZJozk3MXE8VgsL2E5wOUHSgyCvcg1H2vQQjj+gqhO9lVudgY3z3SF7LJAmi+0vy3CJkbMqsynWB49EA==", - "dependencies": { - "is-electron-renderer": "^2.0.0" - } - }, "node_modules/electron/node_modules/@types/node": { "version": "18.18.3", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.3.tgz", @@ -5250,14 +5307,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "bin": { - "flat": "cli.js" - } - }, "node_modules/flat-cache": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.0.tgz", @@ -5512,6 +5561,7 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" @@ -6175,14 +6225,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "bin": { - "he": "bin/he" - } - }, "node_modules/highlight.js": { "version": "10.7.3", "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", @@ -6710,11 +6752,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-electron-renderer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-electron-renderer/-/is-electron-renderer-2.0.1.tgz", - "integrity": "sha512-pRlQnpaCFhDVPtkXkP+g9Ybv/CjbiQDjnKFQTEjpBfDKeV6dRDBczuFRDpM6DVfk2EjpMS8t5kwE5jPnqYl3zA==" - }, "node_modules/is-equal-shallow": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", @@ -7021,17 +7058,6 @@ "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", "license": "MIT" }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-weakmap": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", @@ -7540,21 +7566,6 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "license": "MIT" }, - "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/longest-streak": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", @@ -8552,249 +8563,6 @@ "mkdirp": "bin/cmd.js" } }, - "node_modules/mocha": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", - "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", - "dependencies": { - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.4", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.2.0", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "5.0.1", - "ms": "2.1.3", - "nanoid": "3.3.3", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "workerpool": "6.2.1", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha.js" - }, - "engines": { - "node": ">= 14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mochajs" - } - }, - "node_modules/mocha/node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/mocha/node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/mocha/node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "engines": { - "node": ">=8" - } - }, - "node_modules/mocha/node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/mocha/node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/mocha/node_modules/diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/mocha/node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/mocha/node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/mocha/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/mocha/node_modules/glob/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/mocha/node_modules/glob/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/mocha/node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/mocha/node_modules/minimatch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mocha/node_modules/nanoid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", - "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/mocha/node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/mocha/node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mocha/node_modules/yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", - "engines": { - "node": ">=10" - } - }, "node_modules/mri": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", @@ -10637,14 +10405,6 @@ "node": ">=0.10.0" } }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, "node_modules/react": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", @@ -10686,6 +10446,14 @@ "react": "^16.8.0 || ^17 || ^18" } }, + "node_modules/react-intersection-observer": { + "version": "9.5.2", + "resolved": "https://registry.npmjs.org/react-intersection-observer/-/react-intersection-observer-9.5.2.tgz", + "integrity": "sha512-EmoV66/yvksJcGa1rdW0nDNc4I1RifDWkT50gXSFnPLYQ4xUptuDD4V7k+Rj1OgVAlww628KLGcxPXFlOkkU/Q==", + "peerDependencies": { + "react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", @@ -11476,6 +11244,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -11845,14 +11614,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dependencies": { - "randombytes": "^2.1.0" - } - }, "node_modules/set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", @@ -12606,6 +12367,7 @@ "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -13569,6 +13331,17 @@ "node": ">=0.10.0" } }, + "node_modules/use-debounce": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/use-debounce/-/use-debounce-9.0.4.tgz", + "integrity": "sha512-6X8H/mikbrt0XE8e+JXRtZ8yYVvKkdYRfmIhWZYsP8rcNs9hk3APV8Ua2mFkKRLcJKVdnX2/Vwrmg2GWKUQEaQ==", + "engines": { + "node": ">= 10.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, "node_modules/utf8-byte-length": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz", @@ -13876,15 +13649,11 @@ "string-width": "^1.0.2 || 2 || 3 || 4" } }, - "node_modules/workerpool": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", - "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==" - }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -13954,54 +13723,11 @@ "node": ">=0.4" } }, - "node_modules/xvfb-maybe": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/xvfb-maybe/-/xvfb-maybe-0.2.1.tgz", - "integrity": "sha512-9IyRz3l6Qyhl6LvnGRF5jMPB4oBEepQnuzvVAFTynP6ACLLSevqigICJ9d/+ofl29m2daeaVBChnPYUnaeJ7yA==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^2.2.0", - "which": "^1.2.4" - }, - "bin": { - "xvfb-maybe": "src/xvfb-maybe.js" - } - }, - "node_modules/xvfb-maybe/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/xvfb-maybe/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" - }, - "node_modules/xvfb-maybe/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, "license": "ISC", "engines": { "node": ">=10" @@ -14026,6 +13752,7 @@ "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, "license": "MIT", "dependencies": { "cliui": "^8.0.1", @@ -14044,33 +13771,12 @@ "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, "license": "ISC", "engines": { "node": ">=12" } }, - "node_modules/yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dependencies": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-unparser/node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "engines": { - "node": ">=8" - } - }, "node_modules/yauzl": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", diff --git a/web/app/_components/ActiveModelTable/index.tsx b/web/app/_components/ActiveModelTable/index.tsx index 8007404229..72951e33d6 100644 --- a/web/app/_components/ActiveModelTable/index.tsx +++ b/web/app/_components/ActiveModelTable/index.tsx @@ -1,10 +1,10 @@ import { useAtomValue } from "jotai"; -import React, { Fragment } from "react"; +import React from "react"; import ModelTable from "../ModelTable"; -import { currentProductAtom } from "@/_helpers/atoms/Model.atom"; +import { activeAssistantModelAtom } from "@/_helpers/atoms/Model.atom"; const ActiveModelTable: React.FC = () => { - const activeModel = useAtomValue(currentProductAtom); + const activeModel = useAtomValue(activeAssistantModelAtom); if (!activeModel) return null; diff --git a/web/app/_components/AvailableModelCard/index.tsx b/web/app/_components/AvailableModelCard/index.tsx index 31e0ee2d44..b493ccac85 100644 --- a/web/app/_components/AvailableModelCard/index.tsx +++ b/web/app/_components/AvailableModelCard/index.tsx @@ -1,19 +1,19 @@ -import { Product } from "@/_models/Product"; import DownloadModelContent from "../DownloadModelContent"; import ModelDownloadButton from "../ModelDownloadButton"; import ModelDownloadingButton from "../ModelDownloadingButton"; import { useAtomValue } from "jotai"; import { modelDownloadStateAtom } from "@/_helpers/atoms/DownloadState.atom"; +import { AssistantModel } from "@/_models/AssistantModel"; type Props = { - product: Product; + model: AssistantModel; isRecommend: boolean; required?: string; - onDownloadClick?: (product: Product) => void; + onDownloadClick?: (model: AssistantModel) => void; }; const AvailableModelCard: React.FC = ({ - product, + model, isRecommend, required, onDownloadClick, @@ -24,14 +24,14 @@ const AvailableModelCard: React.FC = ({ let total = 0; let transferred = 0; - if (product.fileName && downloadState[product.fileName]) { + if (model.id && downloadState[model.id]) { isDownloading = - downloadState[product.fileName].error == null && - downloadState[product.fileName].percent < 1; + downloadState[model.id].error == null && + downloadState[model.id].percent < 1; if (isDownloading) { - total = downloadState[product.fileName].size.total; - transferred = downloadState[product.fileName].size.transferred; + total = downloadState[model.id].size.total; + transferred = downloadState[model.id].size.transferred; } } @@ -41,7 +41,7 @@ const AvailableModelCard: React.FC = ({
) : (
- onDownloadClick?.(product)} /> + onDownloadClick?.(model)} />
); @@ -50,11 +50,11 @@ const AvailableModelCard: React.FC = ({
{downloadButton}
diff --git a/web/app/_components/ConversationalCard/index.tsx b/web/app/_components/ConversationalCard/index.tsx index 9878c29b1f..8f09d1caf1 100644 --- a/web/app/_components/ConversationalCard/index.tsx +++ b/web/app/_components/ConversationalCard/index.tsx @@ -1,20 +1,20 @@ import React from "react"; import Image from "next/image"; import useCreateConversation from "@/_hooks/useCreateConversation"; -import { Product } from "@/_models/Product"; +import { AssistantModel } from "@/_models/AssistantModel"; type Props = { - product: Product; + model: AssistantModel; }; -const ConversationalCard: React.FC = ({ product }) => { +const ConversationalCard: React.FC = ({ model }) => { const { requestCreateConvo } = useCreateConversation(); - const { name, avatarUrl, description } = product; + const { name, avatarUrl, shortDescription } = model; return ( +
diff --git a/web/app/_components/ExploreModelItem/index.tsx b/web/app/_components/ExploreModelItem/index.tsx index 218166a8c5..a06a99a1f9 100644 --- a/web/app/_components/ExploreModelItem/index.tsx +++ b/web/app/_components/ExploreModelItem/index.tsx @@ -81,7 +81,7 @@ const ExploreModelItem = forwardRef(({ model }, ref) => { Tags - {model.availableVersions.length > 0 && ( + {model.availableVersions?.length > 0 && ( {show && ( { - const [loadMoreInProgress, setLoadMoreInProress] = useAtom(modelLoadMoreAtom); - const modelSearch = useAtomValue(modelSearchAtom); - const { modelList, getHuggingFaceModel } = useGetHuggingFaceModel(); - const { ref, inView } = useInView({ - threshold: 0, - triggerOnce: true, - }); + const { models } = useGetConfiguredModels(); useEffect(() => { - if (modelList.length === 0 && modelSearch.length > 0) { - setLoadMoreInProress(true); - } - getHuggingFaceModel(modelSearch); - }, [modelSearch]); - - useEffect(() => { - if (inView) { - console.debug("Load more models.."); - setLoadMoreInProress(true); - getHuggingFaceModel(modelSearch); - } - }, [inView]); + getConfiguredModels(); + }, []); return (
- {modelList.map((item, index) => ( - + {models.map((item) => ( + ))} - {loadMoreInProgress && ( -
- -
- )}
); }; diff --git a/web/app/_components/InputToolbar/index.tsx b/web/app/_components/InputToolbar/index.tsx index 9dbd02f926..6cea8f35b0 100644 --- a/web/app/_components/InputToolbar/index.tsx +++ b/web/app/_components/InputToolbar/index.tsx @@ -8,13 +8,13 @@ import SecondaryButton from "../SecondaryButton"; import { Fragment } from "react"; import { PlusIcon } from "@heroicons/react/24/outline"; import useCreateConversation from "@/_hooks/useCreateConversation"; -import { currentProductAtom } from "@/_helpers/atoms/Model.atom"; +import { activeAssistantModelAtom } from "@/_helpers/atoms/Model.atom"; import LoadingIndicator from "../LoadingIndicator"; import { currentConvoStateAtom } from "@/_helpers/atoms/Conversation.atom"; const InputToolbar: React.FC = () => { const showingAdvancedPrompt = useAtomValue(showingAdvancedPromptAtom); - const currentProduct = useAtomValue(currentProductAtom); + const activeModel = useAtomValue(activeAssistantModelAtom); const { requestCreateConvo } = useCreateConversation(); const currentConvoState = useAtomValue(currentConvoStateAtom); @@ -26,8 +26,8 @@ const InputToolbar: React.FC = () => { // const onRegenerateClick = () => {}; const onNewConversationClick = () => { - if (currentProduct) { - requestCreateConvo(currentProduct); + if (activeModel) { + requestCreateConvo(activeModel); } }; @@ -49,7 +49,6 @@ const InputToolbar: React.FC = () => { )} - {/* */} = ({ model }) => { const { startModel, stopModel } = useStartStopModel(); - const activeModel = useAtomValue(currentProductAtom); + const activeModel = useAtomValue(activeAssistantModelAtom); const { deleteModel } = useDeleteModel(); let status = ModelStatus.Installed; @@ -36,32 +36,23 @@ const ModelRow: React.FC = ({ model }) => { } }; - const onDeleteClick = () => { + const onDeleteClick = useCallback(() => { deleteModel(model); - }; + }, [model]); return ( - + {model.name} {model.version}
- {model.format} - {model.accelerated && ( - - - GPU Accelerated - - )} + GGUF
- {model.totalSize} + {toGigabytes(model.size)} diff --git a/web/app/_components/ModelSelector/index.tsx b/web/app/_components/ModelSelector/index.tsx index b32cd7c4e2..66461e6c63 100644 --- a/web/app/_components/ModelSelector/index.tsx +++ b/web/app/_components/ModelSelector/index.tsx @@ -1,10 +1,10 @@ import { Fragment, useEffect } from "react"; import { Listbox, Transition } from "@headlessui/react"; import { CheckIcon, ChevronUpDownIcon } from "@heroicons/react/20/solid"; -import { Product } from "@/_models/Product"; import { useAtom, useAtomValue } from "jotai"; import { selectedModelAtom } from "@/_helpers/atoms/Model.atom"; import { downloadedModelAtom } from "@/_helpers/atoms/DownloadedModel.atom"; +import { AssistantModel } from "@/_models/AssistantModel"; function classNames(...classes: any) { return classes.filter(Boolean).join(" "); @@ -20,7 +20,7 @@ const SelectModels: React.FC = () => { } }, [downloadedModels]); - const onModelSelected = (model: Product) => { + const onModelSelected = (model: AssistantModel) => { setSelectedModel(model); }; diff --git a/web/app/_components/ModelTable/index.tsx b/web/app/_components/ModelTable/index.tsx index 99d15cacb4..e632e12ab7 100644 --- a/web/app/_components/ModelTable/index.tsx +++ b/web/app/_components/ModelTable/index.tsx @@ -1,10 +1,10 @@ import React from "react"; -import { Product } from "@/_models/Product"; import ModelRow from "../ModelRow"; import ModelTableHeader from "../ModelTableHeader"; +import { AssistantModel } from "@/_models/AssistantModel"; type Props = { - models: Product[]; + models: AssistantModel[]; }; const tableHeaders = ["MODEL", "FORMAT", "SIZE", "STATUS", "ACTIONS"]; diff --git a/web/app/_components/ModelVersionItem/index.tsx b/web/app/_components/ModelVersionItem/index.tsx index ab530a87aa..4d9d40a53f 100644 --- a/web/app/_components/ModelVersionItem/index.tsx +++ b/web/app/_components/ModelVersionItem/index.tsx @@ -1,10 +1,11 @@ import React, { useMemo } from "react"; import { formatDownloadPercentage, toGigabytes } from "@/_utils/converter"; import Image from "next/image"; -import { ModelVersion, Product } from "@/_models/Product"; +import { Product } from "@/_models/Product"; import useDownloadModel from "@/_hooks/useDownloadModel"; import { modelDownloadStateAtom } from "@/_helpers/atoms/DownloadState.atom"; import { atom, useAtomValue } from "jotai"; +import { ModelVersion } from "@/_models/ModelVersion"; type Props = { model: Product; @@ -12,15 +13,15 @@ type Props = { }; const ModelVersionItem: React.FC = ({ model, modelVersion }) => { - const { downloadHfModel } = useDownloadModel(); + const { downloadModel } = useDownloadModel(); const downloadAtom = useMemo( - () => atom((get) => get(modelDownloadStateAtom)[modelVersion.path ?? ""]), - [modelVersion.path ?? ""] + () => atom((get) => get(modelDownloadStateAtom)[modelVersion.id ?? ""]), + [modelVersion.id ?? ""] ); const downloadState = useAtomValue(downloadAtom); const onDownloadClick = () => { - downloadHfModel(model, modelVersion); + downloadModel(model, modelVersion); }; let downloadButton = ( @@ -42,7 +43,7 @@ const ModelVersionItem: React.FC = ({ model, modelVersion }) => {
- {modelVersion.path} + {modelVersion.name}
diff --git a/web/app/_components/ModelVersionList/index.tsx b/web/app/_components/ModelVersionList/index.tsx index 09af4a6232..95c03039af 100644 --- a/web/app/_components/ModelVersionList/index.tsx +++ b/web/app/_components/ModelVersionList/index.tsx @@ -1,6 +1,7 @@ import React from "react"; import ModelVersionItem from "../ModelVersionItem"; -import { ModelVersion, Product } from "@/_models/Product"; +import { Product } from "@/_models/Product"; +import { ModelVersion } from "@/_models/ModelVersion"; type Props = { model: Product; @@ -12,7 +13,7 @@ const ModelVersionList: React.FC = ({ model, versions }) => (
Available Versions
{versions.map((item) => ( - + ))}
diff --git a/web/app/_components/MonitorBar/index.tsx b/web/app/_components/MonitorBar/index.tsx index 7c6b3b5591..3ded033f66 100644 --- a/web/app/_components/MonitorBar/index.tsx +++ b/web/app/_components/MonitorBar/index.tsx @@ -2,16 +2,16 @@ import ProgressBar from "../ProgressBar"; import SystemItem from "../SystemItem"; import { useAtomValue } from "jotai"; import { appDownloadProgress } from "@/_helpers/JotaiWrapper"; -import { currentProductAtom } from "@/_helpers/atoms/Model.atom"; import useGetAppVersion from "@/_hooks/useGetAppVersion"; import useGetSystemResources from "@/_hooks/useGetSystemResources"; import { modelDownloadStateAtom } from "@/_helpers/atoms/DownloadState.atom"; import { DownloadState } from "@/_models/DownloadState"; import { formatDownloadPercentage } from "@/_utils/converter"; +import { activeAssistantModelAtom } from "@/_helpers/atoms/Model.atom"; const MonitorBar: React.FC = () => { const progress = useAtomValue(appDownloadProgress); - const activeModel = useAtomValue(currentProductAtom); + const activeModel = useAtomValue(activeAssistantModelAtom); const { version } = useGetAppVersion(); const { ram, cpu } = useGetSystemResources(); const modelDownloadStates = useAtomValue(modelDownloadStateAtom); diff --git a/web/app/_components/NewChatButton/index.tsx b/web/app/_components/NewChatButton/index.tsx index 509da36ba6..2ac6ad1842 100644 --- a/web/app/_components/NewChatButton/index.tsx +++ b/web/app/_components/NewChatButton/index.tsx @@ -7,14 +7,14 @@ import { MainViewState, setMainViewStateAtom, } from "@/_helpers/atoms/MainView.atom"; -import { currentProductAtom } from "@/_helpers/atoms/Model.atom"; import useCreateConversation from "@/_hooks/useCreateConversation"; import useInitModel from "@/_hooks/useInitModel"; -import { Product } from "@/_models/Product"; import { PlusIcon } from "@heroicons/react/24/outline"; +import { activeAssistantModelAtom } from "@/_helpers/atoms/Model.atom"; +import { AssistantModel } from "@/_models/AssistantModel"; const NewChatButton: React.FC = () => { - const activeModel = useAtomValue(currentProductAtom); + const activeModel = useAtomValue(activeAssistantModelAtom); const setMainView = useSetAtom(setMainViewStateAtom); const { requestCreateConvo } = useCreateConversation(); const { initModel } = useInitModel(); @@ -27,7 +27,7 @@ const NewChatButton: React.FC = () => { } }; - const createConversationAndInitModel = async (model: Product) => { + const createConversationAndInitModel = async (model: AssistantModel) => { await requestCreateConvo(model); await initModel(model); }; diff --git a/web/app/_components/SidebarEmptyHistory/index.tsx b/web/app/_components/SidebarEmptyHistory/index.tsx index 5749da64e6..0ab03f4ca4 100644 --- a/web/app/_components/SidebarEmptyHistory/index.tsx +++ b/web/app/_components/SidebarEmptyHistory/index.tsx @@ -7,10 +7,10 @@ import { MainViewState, setMainViewStateAtom, } from "@/_helpers/atoms/MainView.atom"; -import { currentProductAtom } from "@/_helpers/atoms/Model.atom"; +import { activeAssistantModelAtom } from "@/_helpers/atoms/Model.atom"; import useInitModel from "@/_hooks/useInitModel"; -import { Product } from "@/_models/Product"; import { useGetDownloadedModels } from "@/_hooks/useGetDownloadedModels"; +import { AssistantModel } from "@/_models/AssistantModel"; enum ActionButton { DownloadModel = "Download a Model", @@ -19,7 +19,7 @@ enum ActionButton { const SidebarEmptyHistory: React.FC = () => { const { downloadedModels } = useGetDownloadedModels(); - const activeModel = useAtomValue(currentProductAtom); + const activeModel = useAtomValue(activeAssistantModelAtom); const setMainView = useSetAtom(setMainViewStateAtom); const { requestCreateConvo } = useCreateConversation(); const [action, setAction] = useState(ActionButton.DownloadModel); @@ -46,7 +46,7 @@ const SidebarEmptyHistory: React.FC = () => { } }; - const createConversationAndInitModel = async (model: Product) => { + const createConversationAndInitModel = async (model: AssistantModel) => { await requestCreateConvo(model); await initModel(model); }; diff --git a/web/app/_helpers/atoms/DownloadedModel.atom.ts b/web/app/_helpers/atoms/DownloadedModel.atom.ts index 9e924ea74d..28763aa0b8 100644 --- a/web/app/_helpers/atoms/DownloadedModel.atom.ts +++ b/web/app/_helpers/atoms/DownloadedModel.atom.ts @@ -1,4 +1,7 @@ -import { Product } from "@/_models/Product"; +import { AssistantModel } from "@/_models/AssistantModel"; import { atom } from "jotai"; -export const downloadedModelAtom = atom([]); +/** + * @description: This atom is used to store the downloaded models + */ +export const downloadedModelAtom = atom([]); diff --git a/web/app/_helpers/atoms/Model.atom.ts b/web/app/_helpers/atoms/Model.atom.ts index 053f03ac65..807179964c 100644 --- a/web/app/_helpers/atoms/Model.atom.ts +++ b/web/app/_helpers/atoms/Model.atom.ts @@ -1,6 +1,8 @@ -import { Product } from "@/_models/Product"; +import { AssistantModel } from "@/_models/AssistantModel"; import { atom } from "jotai"; -export const currentProductAtom = atom(undefined); +export const selectedModelAtom = atom(undefined); -export const selectedModelAtom = atom(undefined); +export const activeAssistantModelAtom = atom( + undefined +); diff --git a/web/app/_hooks/useCreateConversation.ts b/web/app/_hooks/useCreateConversation.ts index 100ffa9451..3aa970420e 100644 --- a/web/app/_hooks/useCreateConversation.ts +++ b/web/app/_hooks/useCreateConversation.ts @@ -2,7 +2,6 @@ import { useAtom, useSetAtom } from "jotai"; import { Conversation } from "@/_models/Conversation"; import { executeSerial } from "@/_services/pluginService"; import { DataService } from "../../shared/coreService"; -import { Product } from "@/_models/Product"; import { userConversationsAtom, setActiveConvoIdAtom, @@ -11,6 +10,7 @@ import { updateConversationErrorAtom, } from "@/_helpers/atoms/Conversation.atom"; import useInitModel from "./useInitModel"; +import { AssistantModel } from "@/_models/AssistantModel"; const useCreateConversation = () => { const { initModel } = useInitModel(); @@ -24,7 +24,7 @@ const useCreateConversation = () => { ); const updateConvError = useSetAtom(updateConversationErrorAtom); - const requestCreateConvo = async (model: Product) => { + const requestCreateConvo = async (model: AssistantModel) => { const conversationName = model.name; const conv: Conversation = { model_id: model.id, diff --git a/web/app/_hooks/useDeleteModel.ts b/web/app/_hooks/useDeleteModel.ts index 77646b8e97..3857ae31c1 100644 --- a/web/app/_hooks/useDeleteModel.ts +++ b/web/app/_hooks/useDeleteModel.ts @@ -1,16 +1,16 @@ import { execute, executeSerial } from "@/_services/pluginService"; import { DataService, ModelManagementService } from "../../shared/coreService"; -import { Product } from "@/_models/Product"; import { useSetAtom } from "jotai"; import { downloadedModelAtom } from "@/_helpers/atoms/DownloadedModel.atom"; import { getDownloadedModels } from "./useGetDownloadedModels"; +import { AssistantModel } from "@/_models/AssistantModel"; export default function useDeleteModel() { const setDownloadedModels = useSetAtom(downloadedModelAtom); - const deleteModel = async (model: Product) => { + const deleteModel = async (model: AssistantModel) => { execute(DataService.DELETE_DOWNLOAD_MODEL, model.id); - await executeSerial(ModelManagementService.DELETE_MODEL, model.fileName); + await executeSerial(ModelManagementService.DELETE_MODEL, model.id); // reload models const downloadedModels = await getDownloadedModels(); diff --git a/web/app/_hooks/useDownloadModel.ts b/web/app/_hooks/useDownloadModel.ts index de2ce898bc..5f2ff26e40 100644 --- a/web/app/_hooks/useDownloadModel.ts +++ b/web/app/_hooks/useDownloadModel.ts @@ -1,38 +1,20 @@ import { executeSerial } from "@/_services/pluginService"; import { DataService, ModelManagementService } from "../../shared/coreService"; -import { ModelVersion, Product } from "@/_models/Product"; +import { Product } from "@/_models/Product"; +import { ModelVersion } from "@/_models/ModelVersion"; export default function useDownloadModel() { - const downloadModel = async (model: Product) => { - await executeSerial(DataService.STORE_MODEL, model); - await executeSerial(ModelManagementService.DOWNLOAD_MODEL, { - downloadUrl: model.downloadUrl, - fileName: model.fileName, - }); - }; + const downloadModel = async (model: Product, modelVersion: ModelVersion) => { + modelVersion.startDownloadAt = Date.now(); - const downloadHfModel = async ( - model: Product, - modelVersion: ModelVersion - ) => { - const hfModel: Product = { - ...model, - id: `${model.author}.${modelVersion.path}`, - slug: `${model.author}.${modelVersion.path}`, - name: `${model.name} - ${modelVersion.path}`, - fileName: modelVersion.path, - totalSize: modelVersion.size, - downloadUrl: modelVersion.downloadUrl, - }; - await executeSerial(DataService.STORE_MODEL, hfModel); + await executeSerial(DataService.STORE_MODEL, { model, modelVersion }); await executeSerial(ModelManagementService.DOWNLOAD_MODEL, { - downloadUrl: hfModel.downloadUrl, - fileName: hfModel.fileName, + downloadUrl: modelVersion.downloadLink, + fileName: modelVersion.id, }); }; return { downloadModel, - downloadHfModel, }; } diff --git a/web/app/_hooks/useGetAvailableModels.ts b/web/app/_hooks/useGetAvailableModels.ts deleted file mode 100644 index b10cc617ba..0000000000 --- a/web/app/_hooks/useGetAvailableModels.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { Product } from "@/_models/Product"; -import { executeSerial } from "@/_services/pluginService"; -import { ModelManagementService } from "../../shared/coreService"; -import { useEffect, useState } from "react"; -import { getModelFiles } from "./useGetDownloadedModels"; -import { useAtomValue } from "jotai"; -import { modelDownloadStateAtom } from "@/_helpers/atoms/DownloadState.atom"; - -export default function useGetAvailableModels() { - const downloadState = useAtomValue(modelDownloadStateAtom); - const [allAvailableModels, setAllAvailableModels] = useState([]); - const [availableModels, setAvailableModels] = useState([]); - const [downloadedModels, setDownloadedModels] = useState([]); - - const getAvailableModelExceptDownloaded = async () => { - const avails = await getAvailableModels(); - const downloaded = await getModelFiles(); - - setAllAvailableModels(avails); - const availableOrDownloadingModels: Product[] = avails; - const successfullDownloadModels: Product[] = []; - - downloaded.forEach((item) => { - if (item.fileName && downloadState[item.fileName] == null) { - // if not downloading, consider as downloaded - successfullDownloadModels.push(item); - } else { - availableOrDownloadingModels.push(item); - } - }); - - setAvailableModels(availableOrDownloadingModels); - setDownloadedModels(successfullDownloadModels); - }; - - useEffect(() => { - getAvailableModelExceptDownloaded(); - }, []); - - return { - allAvailableModels, - availableModels, - downloadedModels, - getAvailableModelExceptDownloaded, - }; -} - -export async function getAvailableModels(): Promise { - const avails: Product[] = await executeSerial( - ModelManagementService.GET_AVAILABLE_MODELS - ); - - return avails ?? []; -} diff --git a/web/app/_hooks/useGetConfiguredModels.ts b/web/app/_hooks/useGetConfiguredModels.ts new file mode 100644 index 0000000000..c5dd5d46a3 --- /dev/null +++ b/web/app/_hooks/useGetConfiguredModels.ts @@ -0,0 +1,20 @@ +import { Product } from "@/_models/Product"; +import { useEffect, useState } from "react"; +import { getConfiguredModels } from "./useGetDownloadedModels"; + +export default function useGetConfiguredModels() { + const [models, setModels] = useState([]); + + const fetchModels = async () => { + const models = await getConfiguredModels(); + + setModels(models); + }; + + // TODO allow user for filter + useEffect(() => { + fetchModels(); + }, []); + + return { models }; +} diff --git a/web/app/_hooks/useGetDownloadedModels.ts b/web/app/_hooks/useGetDownloadedModels.ts index 3784d36d75..da75267173 100644 --- a/web/app/_hooks/useGetDownloadedModels.ts +++ b/web/app/_hooks/useGetDownloadedModels.ts @@ -1,10 +1,10 @@ -import { ModelVersion, Product, ProductType } from "@/_models/Product"; +import { Product } from "@/_models/Product"; import { useEffect } from "react"; import { executeSerial } from "../../../electron/core/plugin-manager/execution/extension-manager"; import { DataService, ModelManagementService } from "../../shared/coreService"; -import { SearchModelParamHf } from "@/_models/hf/SearchModelParam.hf"; import { useAtom } from "jotai"; import { downloadedModelAtom } from "@/_helpers/atoms/DownloadedModel.atom"; +import { AssistantModel } from "@/_models/AssistantModel"; export function useGetDownloadedModels() { const [downloadedModels, setDownloadedModels] = useAtom(downloadedModelAtom); @@ -18,76 +18,13 @@ export function useGetDownloadedModels() { return { downloadedModels }; } -export async function getDownloadedModels(): Promise { - const downloadedModels: Product[] = await executeSerial( +export async function getDownloadedModels(): Promise { + const downloadedModels: AssistantModel[] = await executeSerial( DataService.GET_FINISHED_DOWNLOAD_MODELS ); return downloadedModels ?? []; } -export async function getModelFiles(): Promise { - const downloadedModels: Product[] = await executeSerial( - ModelManagementService.GET_DOWNLOADED_MODELS - ); - return downloadedModels ?? []; +export async function getConfiguredModels(): Promise { + return executeSerial(ModelManagementService.GET_CONFIGURED_MODELS); } - -export async function searchModels( - params: SearchModelParamHf -): Promise { - const result = await executeSerial( - ModelManagementService.SEARCH_MODELS, - params - ); - - const products: Product[] = result.data.map((model: any) => { - const modelVersions: ModelVersion[] = []; - - for (const [, file] of Object.entries(model.files)) { - const fileData: any = file as any; - const modelVersion: ModelVersion = { - path: fileData.path, - type: fileData.type, - downloadUrl: fileData.downloadLink, - size: fileData.size, - }; - modelVersions.push(modelVersion); - } - - const p = { - id: model.id, - slug: model.name, - name: model.name, - description: model.name, - avatarUrl: "", - longDescription: model.name, - technicalDescription: model.name, - author: model.name.split("/")[0], - version: "1.0.0", - modelUrl: "https://google.com", - nsfw: false, - greeting: "Hello there", - type: ProductType.LLM, - createdAt: -1, - accelerated: true, - totalSize: -1, - format: "", - status: "Not downloaded", - releaseDate: -1, - availableVersions: modelVersions, - }; - - return p; - }); - - return { - data: products, - hasMore: result.hasMore, - }; -} - -// TODO define somewhere else -export type QueryProductResult = { - data: Product[]; - hasMore: boolean; -}; diff --git a/web/app/_hooks/useInitModel.ts b/web/app/_hooks/useInitModel.ts index 15ed78929a..1795c2ddd8 100644 --- a/web/app/_hooks/useInitModel.ts +++ b/web/app/_hooks/useInitModel.ts @@ -1,18 +1,19 @@ -import { Product } from "@/_models/Product"; import { executeSerial } from "@/_services/pluginService"; import { InferenceService } from "../../shared/coreService"; import { useAtom } from "jotai"; -import { currentProductAtom } from "@/_helpers/atoms/Model.atom"; +import { activeAssistantModelAtom } from "@/_helpers/atoms/Model.atom"; +import { AssistantModel } from "@/_models/AssistantModel"; export default function useInitModel() { - const [activeModel, setActiveModel] = useAtom(currentProductAtom); + const [activeModel, setActiveModel] = useAtom(activeAssistantModelAtom); - const initModel = async (model: Product) => { + const initModel = async (model: AssistantModel) => { if (activeModel && activeModel.id === model.id) { console.debug(`Model ${model.id} is already init. Ignore..`); return; } - const res = await executeSerial(InferenceService.INIT_MODEL, model); + + const res = await executeSerial(InferenceService.INIT_MODEL, model.id); if (res?.error) { console.log("error occured: ", res); return res; diff --git a/web/app/_hooks/useStartStopModel.ts b/web/app/_hooks/useStartStopModel.ts index 8d9e0c7bbe..5c5db96472 100644 --- a/web/app/_hooks/useStartStopModel.ts +++ b/web/app/_hooks/useStartStopModel.ts @@ -2,11 +2,11 @@ import { executeSerial } from "@/_services/pluginService"; import { DataService, InferenceService } from "../../shared/coreService"; import useInitModel from "./useInitModel"; import { useSetAtom } from "jotai"; -import { currentProductAtom } from "@/_helpers/atoms/Model.atom"; +import { activeAssistantModelAtom } from "@/_helpers/atoms/Model.atom"; export default function useStartStopModel() { const { initModel } = useInitModel(); - const setActiveModel = useSetAtom(currentProductAtom); + const setActiveModel = useSetAtom(activeAssistantModelAtom); const startModel = async (modelId: string) => { const model = await executeSerial(DataService.GET_MODEL_BY_ID, modelId); diff --git a/web/app/_models/AssistantModel.ts b/web/app/_models/AssistantModel.ts new file mode 100644 index 0000000000..57caf64a74 --- /dev/null +++ b/web/app/_models/AssistantModel.ts @@ -0,0 +1,65 @@ +import { ProductType } from "./Product"; + +/** + * Represent a model + */ +export type AssistantModel = { + /** + * Combination of owner and model name. + * Being used as file name. MUST be unique. + */ + id: string; + + name: string; + + quantMethod: string; + + bits: number; + + size: number; + + maxRamRequired: number; + + usecase: string; + + downloadLink: string; + + /** + * For tracking download info + */ + startDownloadAt?: number; + + finishDownloadAt?: number; + + productId: string; + + productName: string; + + shortDescription: string; + + longDescription: string; + + avatarUrl: string; + + author: string; + + version: string; + + modelUrl: string; + + nsfw: boolean; + + greeting: string; + + type: ProductType; + + createdAt: number; + + updatedAt?: number; + + status: string; // TODO: add this in the database // Downloaded, Active + + releaseDate: number; // TODO: add this in the database + + tags: string[]; +}; diff --git a/web/app/_models/ModelVersion.ts b/web/app/_models/ModelVersion.ts new file mode 100644 index 0000000000..d9d89d92d5 --- /dev/null +++ b/web/app/_models/ModelVersion.ts @@ -0,0 +1,23 @@ +/** + * Model type which will be stored in the database + */ +export type ModelVersion = { + /** + * Combination of owner and model name. + * Being used as file name. Should be unique. + */ + id: string; + name: string; + quantMethod: string; + bits: number; + size: number; + maxRamRequired: number; + usecase: string; + downloadLink: string; + productId: string; + /** + * For tracking download state + */ + startDownloadAt?: number; + finishDownloadAt?: number; +}; diff --git a/web/app/_models/Product.ts b/web/app/_models/Product.ts index d16d5a9b08..545a9bb824 100644 --- a/web/app/_models/Product.ts +++ b/web/app/_models/Product.ts @@ -1,3 +1,4 @@ +import { ModelVersion } from "./ModelVersion"; import { ProductInput } from "./ProductInput"; import { ProductOutput } from "./ProductOutput"; @@ -9,12 +10,10 @@ export enum ProductType { export interface Product { id: string; - slug: string; name: string; - description: string; + shortDescription: string; avatarUrl: string; longDescription: string; - technicalDescription: string; author: string; version: string; modelUrl: string; @@ -25,36 +24,8 @@ export interface Product { outputs?: ProductOutput; createdAt: number; updatedAt?: number; - fileName?: string; - downloadUrl?: string; - - accelerated: boolean; // TODO: add this in the database - totalSize: number; // TODO: add this in the database - format: string; // TODO: add this in the database // GGUF or something else status: string; // TODO: add this in the database // Downloaded, Active releaseDate: number; // TODO: add this in the database - + tags: string[]; availableVersions: ModelVersion[]; } - -export interface ModelVersion { - /** - * Act as the id of the model version - */ - path: string; - - /** - * currently, we only have `file` type - */ - type: string; - - /** - * The download url for the model version - */ - downloadUrl: string; - - /** - * File size in bytes - */ - size: number; -} diff --git a/web/app/_services/pluginService.ts b/web/app/_services/pluginService.ts index deb2159389..04c4052fd2 100644 --- a/web/app/_services/pluginService.ts +++ b/web/app/_services/pluginService.ts @@ -17,7 +17,7 @@ export const isCorePluginInstalled = () => { if (!extensionPoints.get(InferenceService.INIT_MODEL)) { return false; } - if (!extensionPoints.get(ModelManagementService.GET_DOWNLOADED_MODELS)) { + if (!extensionPoints.get(ModelManagementService.DOWNLOAD_MODEL)) { return false; } return true; @@ -34,7 +34,7 @@ export const setupBasePlugins = async () => { if ( !extensionPoints.get(DataService.GET_CONVERSATIONS) || !extensionPoints.get(InferenceService.INIT_MODEL) || - !extensionPoints.get(ModelManagementService.GET_DOWNLOADED_MODELS) + !extensionPoints.get(ModelManagementService.DOWNLOAD_MODEL) ) { const installed = await plugins.install(basePlugins); if (installed) { diff --git a/web/shared/coreService.ts b/web/shared/coreService.ts index 8a2c5372fd..cebbe39a9c 100644 --- a/web/shared/coreService.ts +++ b/web/shared/coreService.ts @@ -34,11 +34,10 @@ export enum InferenceService { } export enum ModelManagementService { - GET_DOWNLOADED_MODELS = "getDownloadedModels", - GET_AVAILABLE_MODELS = "getAvailableModels", DELETE_MODEL = "deleteModel", DOWNLOAD_MODEL = "downloadModel", SEARCH_MODELS = "searchModels", + GET_CONFIGURED_MODELS = "getConfiguredModels", } export enum PreferenceService { From 773bbaf4ccc9ab0cc702ed62c99514af5ea3dd45 Mon Sep 17 00:00:00 2001 From: James Date: Tue, 10 Oct 2023 18:53:56 -0700 Subject: [PATCH 15/42] update Signed-off-by: James --- electron/core/plugins/data-plugin/module.ts | 66 +++------------ .../core/plugins/data-plugin/package.json | 2 +- .../plugins/model-management-plugin/index.js | 12 +-- .../ExploreModelContainer/index.tsx | 4 +- .../_components/ExploreModelFilter/index.tsx | 3 +- .../_components/ExploreModelItem/index.tsx | 39 ++++++--- .../ExploreModelItemHeader/index.tsx | 80 ++++++++++++++----- .../_components/ModelVersionItem/index.tsx | 23 +++++- .../_components/ModelVersionList/index.tsx | 32 +++++--- .../_components/SimpleTag/TagStyleMapper.ts | 16 ++++ web/app/_components/SimpleTag/TagType.ts | 32 ++++++++ web/app/_components/SimpleTag/index.tsx | 55 +------------ web/app/_hooks/useGetHuggingFaceModel.ts | 17 ++-- .../_hooks/useGetMostSuitableModelVersion.ts | 29 +++++++ web/app/_hooks/useGetPerformanceTag.ts | 53 ++++++++++++ web/app/_models/AssistantModel.ts | 4 +- web/app/_models/Product.ts | 4 +- 17 files changed, 298 insertions(+), 173 deletions(-) create mode 100644 web/app/_components/SimpleTag/TagStyleMapper.ts create mode 100644 web/app/_components/SimpleTag/TagType.ts create mode 100644 web/app/_hooks/useGetMostSuitableModelVersion.ts create mode 100644 web/app/_hooks/useGetPerformanceTag.ts diff --git a/electron/core/plugins/data-plugin/module.ts b/electron/core/plugins/data-plugin/module.ts index a9bc20040d..8ee49798a2 100644 --- a/electron/core/plugins/data-plugin/module.ts +++ b/electron/core/plugins/data-plugin/module.ts @@ -116,22 +116,10 @@ function storeModel(params: any) { model.nsfw, modelTags, model.greeting, - model.type, - function (err: any) { - if (err) { - // Handle the insertion error here - console.error(err.message); - res(undefined); - return; - } - // @ts-ignoreF - const id = this.lastID; - res(id); - return; - } + model.type ); + stmt.finalize(); - // insert modelVersion to MODEL_VERSION_TABLE_INSERTION const stmt2 = db.prepare(MODEL_VERSION_TABLE_INSERTION); stmt2.run( modelVersion.id, @@ -143,25 +131,14 @@ function storeModel(params: any) { modelVersion.usecase, modelVersion.downloadLink, model.id, - modelVersion.startDownloadAt, - function (err: any) { - if (err) { - // Handle the insertion error here - console.error(err.message); - res(undefined); - return; - } - // @ts-ignoreF - const id = this.lastID; - res(id); - return; - } + modelVersion.startDownloadAt ); - stmt.finalize(); + stmt2.finalize(); }); db.close(); + res(undefined); }); } @@ -171,7 +148,7 @@ function storeModel(params: any) { * @param model Product */ function updateFinishedDownloadAt(modelVersionId: string) { - return new Promise((res) => { + return new Promise((res, rej) => { const db = new sqlite3.Database(getDbPath()); const time = Date.now(); console.debug( @@ -181,7 +158,7 @@ function updateFinishedDownloadAt(modelVersionId: string) { db.run(stmt, [time, modelVersionId], (err: any) => { if (err) { console.log(err); - res(undefined); + rej(err); } else { console.log("Updated 1 row"); res("Updated"); @@ -299,7 +276,7 @@ function deleteDownloadModel(modelId: string) { }); } -async function fetchModelVersion(db: any, versionId: string) { +function fetchModelVersion(db: any, versionId: string) { return new Promise((resolve, reject) => { db.get( "SELECT * FROM model_versions WHERE id = ?", @@ -308,32 +285,7 @@ async function fetchModelVersion(db: any, versionId: string) { if (err) { reject(err); } else { - if (row) { - const product = { - id: row.id, - slug: row.slug, - name: row.name, - description: row.description, - avatarUrl: row.avatar_url, - longDescription: row.long_description, - technicalDescription: row.technical_description, - author: row.author, - version: row.version, - modelUrl: row.model_url, - nsfw: row.nsfw, - greeting: row.greeting, - type: row.type, - inputs: row.inputs, - outputs: row.outputs, - createdAt: new Date(row.created_at), - updatedAt: new Date(row.updated_at), - fileName: row.file_name, - downloadUrl: row.download_url, - }; - resolve(product); - } else { - resolve(undefined); - } + resolve(row); } } ); diff --git a/electron/core/plugins/data-plugin/package.json b/electron/core/plugins/data-plugin/package.json index 2bdbf5ad44..062c53c468 100644 --- a/electron/core/plugins/data-plugin/package.json +++ b/electron/core/plugins/data-plugin/package.json @@ -1,6 +1,6 @@ { "name": "data-plugin", - "version": "1.0.0", + "version": "1.0.1", "description": "Jan Database Plugin efficiently stores conversation and model data using SQLite, providing accessible data management", "icon": "https://raw.githubusercontent.com/tailwindlabs/heroicons/88e98b0c2b458553fbadccddc2d2f878edc0387b/src/20/solid/circle-stack.svg", "main": "dist/index.js", diff --git a/electron/core/plugins/model-management-plugin/index.js b/electron/core/plugins/model-management-plugin/index.js index f19382d660..699770a933 100644 --- a/electron/core/plugins/model-management-plugin/index.js +++ b/electron/core/plugins/model-management-plugin/index.js @@ -1,6 +1,6 @@ const MODULE_PATH = "model-management-plugin/dist/module.js"; -const getDownloadedModels = async () => +const getDownloadedModels = () => new Promise(async (resolve) => { if (window.electronAPI) { window.electronAPI @@ -9,7 +9,7 @@ const getDownloadedModels = async () => } }); -const getAvailableModels = async () => +const getAvailableModels = () => new Promise(async (resolve) => { if (window.electronAPI) { window.electronAPI @@ -18,7 +18,7 @@ const getAvailableModels = async () => } }); -const downloadModel = async (product) => +const downloadModel = (product) => new Promise(async (resolve) => { if (window && window.electronAPI) { window.electronAPI @@ -29,7 +29,7 @@ const downloadModel = async (product) => } }); -const deleteModel = async (path) => +const deleteModel = (path) => new Promise(async (resolve) => { if (window.electronAPI) { console.debug(`Delete model model management plugin: ${path}`); @@ -38,7 +38,7 @@ const deleteModel = async (path) => } }); -const searchModels = async (params) => +const searchModels = (params) => new Promise(async (resolve) => { if (window.electronAPI) { window.electronAPI @@ -47,7 +47,7 @@ const searchModels = async (params) => } }); -const getConfiguredModels = async () => +const getConfiguredModels = () => new Promise(async (resolve) => { if (window.electronAPI) { window.electronAPI diff --git a/web/app/_components/ExploreModelContainer/index.tsx b/web/app/_components/ExploreModelContainer/index.tsx index 09743d1428..3102b2b49a 100644 --- a/web/app/_components/ExploreModelContainer/index.tsx +++ b/web/app/_components/ExploreModelContainer/index.tsx @@ -6,10 +6,10 @@ import ExploreModelFilter from "../ExploreModelFilter"; const ExploreModelContainer: React.FC = () => (
- + /> */}
diff --git a/web/app/_components/ExploreModelFilter/index.tsx b/web/app/_components/ExploreModelFilter/index.tsx index c04353e720..a3c1731309 100644 --- a/web/app/_components/ExploreModelFilter/index.tsx +++ b/web/app/_components/ExploreModelFilter/index.tsx @@ -1,7 +1,8 @@ import React from "react"; import SearchBar from "../SearchBar"; import SimpleCheckbox from "../SimpleCheckbox"; -import SimpleTag, { TagType } from "../SimpleTag"; +import SimpleTag from "../SimpleTag"; +import { TagType } from "../SimpleTag/TagType"; const tags = [ "Roleplay", diff --git a/web/app/_components/ExploreModelItem/index.tsx b/web/app/_components/ExploreModelItem/index.tsx index a06a99a1f9..ff16ce924d 100644 --- a/web/app/_components/ExploreModelItem/index.tsx +++ b/web/app/_components/ExploreModelItem/index.tsx @@ -4,10 +4,11 @@ import ExploreModelItemHeader from "../ExploreModelItemHeader"; import ModelVersionList from "../ModelVersionList"; -import { Fragment, forwardRef, useState } from "react"; -import SimpleTag, { TagType } from "../SimpleTag"; +import { Fragment, forwardRef, useEffect, useState } from "react"; +import SimpleTag from "../SimpleTag"; import { displayDate } from "@/_utils/datetime"; import { Product } from "@/_models/Product"; +import useGetMostSuitableModelVersion from "@/_hooks/useGetMostSuitableModelVersion"; type Props = { model: Product; @@ -16,15 +17,26 @@ type Props = { const ExploreModelItem = forwardRef(({ model }, ref) => { const [show, setShow] = useState(false); + const { availableVersions } = model; + const { suitableModel, getMostSuitableModelVersion } = + useGetMostSuitableModelVersion(); + + useEffect(() => { + getMostSuitableModelVersion(availableVersions); + }, [availableVersions]); + + if (!suitableModel) { + return null; + } + return (
@@ -42,11 +54,11 @@ const ExploreModelItem = forwardRef(({ model }, ref) => { Hardware Compatibility
- + /> */}
@@ -63,11 +75,11 @@ const ExploreModelItem = forwardRef(({ model }, ref) => {
Expected Performance
- + /> */}
@@ -77,8 +89,14 @@ const ExploreModelItem = forwardRef(({ model }, ref) => { {model.longDescription}
-
+
Tags +
+ {model.tags.map((tag) => ( + // @ts-ignore + + ))} +
{model.availableVersions?.length > 0 && ( @@ -87,6 +105,7 @@ const ExploreModelItem = forwardRef(({ model }, ref) => { )} From a289e6e2767406147a2a94a871086a5c89c0952a Mon Sep 17 00:00:00 2001 From: James Date: Thu, 12 Oct 2023 00:31:08 -0700 Subject: [PATCH 18/42] fix the exception caused by race condition Signed-off-by: James --- electron/core/plugins/data-plugin/module.ts | 136 +++++++++--------- .../core/plugins/data-plugin/package.json | 2 +- 2 files changed, 73 insertions(+), 65 deletions(-) diff --git a/electron/core/plugins/data-plugin/module.ts b/electron/core/plugins/data-plugin/module.ts index 8ee49798a2..da4994f2a8 100644 --- a/electron/core/plugins/data-plugin/module.ts +++ b/electron/core/plugins/data-plugin/module.ts @@ -190,75 +190,83 @@ function getUnfinishedDownloadModels() { async function getFinishedDownloadModels() { const db = new sqlite3.Database(getDbPath()); - - const query = `SELECT * FROM model_versions WHERE finish_download_at != -1 ORDER BY finish_download_at DESC`; - const modelVersions: any = await new Promise((resolve, reject) => { - db.all(query, (err: Error, rows: any[]) => { - if (err) { - reject(err); - } else { - resolve(rows); - } + try { + const query = `SELECT * FROM model_versions WHERE finish_download_at != -1 ORDER BY finish_download_at DESC`; + const modelVersions: any = await new Promise((resolve, reject) => { + db.all(query, (err: Error, rows: any[]) => { + if (err) { + reject(err); + } else { + resolve(rows); + } + }); }); - }); - const models = await Promise.all( - modelVersions.map(async (modelVersion) => { - const modelQuery = `SELECT * FROM models WHERE id = ?`; - return new Promise((resolve, reject) => { - db.get(modelQuery, [modelVersion.model_id], (err: Error, row: any) => { - if (err) { - reject(err); - } else { - resolve(row); - } + const models = await Promise.all( + modelVersions.map(async (modelVersion) => { + const modelQuery = `SELECT * FROM models WHERE id = ?`; + return new Promise((resolve, reject) => { + db.get( + modelQuery, + [modelVersion.model_id], + (err: Error, row: any) => { + if (err) { + reject(err); + } else { + resolve(row); + } + } + ); }); - }); - }) - ); - - const downloadedModels = []; - modelVersions.forEach((modelVersion: any) => { - const model = models.find((m: any) => m.id === modelVersion.model_id); - - if (!model) { - return; - } - - const assistantModel = { - id: modelVersion.id, - name: modelVersion.name, - quantMethod: modelVersion.quant_method, - bits: modelVersion.bits, - size: modelVersion.size, - maxRamRequired: modelVersion.max_ram_required, - usecase: modelVersion.usecase, - downloadLink: modelVersion.download_link, - startDownloadAt: modelVersion.start_download_at, - finishDownloadAt: modelVersion.finish_download_at, - productId: model.id, - productName: model.name, - shortDescription: model.short_description, - longDescription: model.long_description, - avatarUrl: model.avatar_url, - author: model.author, - version: model.version, - modelUrl: model.model_url, - nsfw: model.nsfw === 0 ? false : true, - greeting: model.default_greeting, - type: model.type, - createdAt: new Date(model.created_at).getTime(), - updatedAt: new Date(model.updated_at ?? "").getTime(), - status: "", - releaseDate: -1, - tags: model.tags.split(","), - }; - downloadedModels.push(assistantModel); - }); + }) + ); - db.close(); + const downloadedModels = []; + modelVersions.forEach((modelVersion: any) => { + const model = models.find((m: any) => m.id === modelVersion.model_id); + + if (!model) { + return; + } + + const assistantModel = { + id: modelVersion.id, + name: modelVersion.name, + quantMethod: modelVersion.quant_method, + bits: modelVersion.bits, + size: modelVersion.size, + maxRamRequired: modelVersion.max_ram_required, + usecase: modelVersion.usecase, + downloadLink: modelVersion.download_link, + startDownloadAt: modelVersion.start_download_at, + finishDownloadAt: modelVersion.finish_download_at, + productId: model.id, + productName: model.name, + shortDescription: model.short_description, + longDescription: model.long_description, + avatarUrl: model.avatar_url, + author: model.author, + version: model.version, + modelUrl: model.model_url, + nsfw: model.nsfw === 0 ? false : true, + greeting: model.default_greeting, + type: model.type, + createdAt: new Date(model.created_at).getTime(), + updatedAt: new Date(model.updated_at ?? "").getTime(), + status: "", + releaseDate: -1, + tags: model.tags.split(","), + }; + downloadedModels.push(assistantModel); + }); + + db.close(); - return downloadedModels; + return downloadedModels; + } catch (err) { + console.error(err); + return []; + } } function deleteDownloadModel(modelId: string) { diff --git a/electron/core/plugins/data-plugin/package.json b/electron/core/plugins/data-plugin/package.json index 062c53c468..9eda7c99d9 100644 --- a/electron/core/plugins/data-plugin/package.json +++ b/electron/core/plugins/data-plugin/package.json @@ -1,6 +1,6 @@ { "name": "data-plugin", - "version": "1.0.1", + "version": "1.0.2", "description": "Jan Database Plugin efficiently stores conversation and model data using SQLite, providing accessible data management", "icon": "https://raw.githubusercontent.com/tailwindlabs/heroicons/88e98b0c2b458553fbadccddc2d2f878edc0387b/src/20/solid/circle-stack.svg", "main": "dist/index.js", From ba90045cbfe44e037daa2d6d8d316e3e864a1f44 Mon Sep 17 00:00:00 2001 From: 0xSage Date: Fri, 13 Oct 2023 14:08:40 +0800 Subject: [PATCH 19/42] style: convo text css, better chat box --- .../BasicPromptAccessories/index.tsx | 35 ++++++++++--------- .../_components/BasicPromptInput/index.tsx | 32 +++++++++++------ web/app/_components/InputToolbar/index.tsx | 15 +++++--- web/app/_components/SendButton/index.tsx | 10 ++---- .../_components/SimpleTextMessage/index.tsx | 2 +- 5 files changed, 54 insertions(+), 40 deletions(-) diff --git a/web/app/_components/BasicPromptAccessories/index.tsx b/web/app/_components/BasicPromptAccessories/index.tsx index 332b9625ef..8baf25d6ad 100644 --- a/web/app/_components/BasicPromptAccessories/index.tsx +++ b/web/app/_components/BasicPromptAccessories/index.tsx @@ -1,7 +1,7 @@ "use client"; import { useSetAtom } from "jotai"; -import SecondaryButton from "../SecondaryButton"; +import { FaceSmileIcon } from "@heroicons/react/24/outline"; import SendButton from "../SendButton"; import { showingAdvancedPromptAtom } from "@/_helpers/atoms/Modal.atom"; @@ -11,22 +11,23 @@ const BasicPromptAccessories: React.FC = () => { const shouldShowAdvancedPrompt = false; return ( -
- {shouldShowAdvancedPrompt && ( - setShowingAdvancedPrompt(true)} - /> - )} -
- {!shouldShowAdvancedPrompt && } +
+ {/* Emoji */} +
+
+ +
+
+ {/* send buton */} +
+ +
); }; diff --git a/web/app/_components/BasicPromptInput/index.tsx b/web/app/_components/BasicPromptInput/index.tsx index 7ff99d5408..2dfa4e71a2 100644 --- a/web/app/_components/BasicPromptInput/index.tsx +++ b/web/app/_components/BasicPromptInput/index.tsx @@ -45,16 +45,28 @@ const BasicPromptInput: React.FC = () => { }; return ( -