diff --git a/electron/core/plugin-manager/execution/facade.js b/electron/core/plugin-manager/execution/facade.js index f8e0eeb757..2ec14d461a 100644 --- a/electron/core/plugin-manager/execution/facade.js +++ b/electron/core/plugin-manager/execution/facade.js @@ -7,7 +7,7 @@ import Plugin from "./Plugin"; import { register } from "./activation-manager"; -import plugins from "../../plugins/plugin.json" +import plugins from "../../../../web/public/plugins/plugin.json" /** * @typedef {Object.} installOptions The {@link https://www.npmjs.com/package/pacote|pacote options} diff --git a/package.json b/package.json index 10e37fa29a..67c7086b23 100644 --- a/package.json +++ b/package.json @@ -35,8 +35,8 @@ "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", - "buid:web-plugins": "yarn build:plugins && cp \"./electron/core/plugins/data-plugin/dist/index.js\" \"./web/public/plugins/data-plugin\" && cp \"./electron/core/plugins/inference-plugin/dist/index.js\" \"./web/public/plugins/inference-plugin\" && cp \"./electron/core/plugins/model-management-plugin/dist/index.js\" \"./web/public/plugins/model-management-plugin\" && cp \"./electron/core/plugins/monitoring-plugin/dist/bundle.js\" \"./web/public/plugins/monitoring-plugin\"", - "server:dev": "yarn build:web && cpx \"web/out/**\" \"server/renderer/\" && yarn buid:web-plugins && cp -r ./electron/core/plugins ./server/plugins && yarn workspace server dev" + "buid:web-plugins": "yarn build:plugins && yarn build:web && cp \"./plugins/data-plugin/dist/esm/index.js\" \"./web/public/plugins/data-plugin\" && cp \"./plugins/inference-plugin/dist/index.js\" \"./web/public/plugins/inference-plugin\" && cp \"./plugins/model-management-plugin/dist/index.js\" \"./web/public/plugins/model-management-plugin\" && cp \"./plugins/monitoring-plugin/dist/bundle.js\" \"./web/public/plugins/monitoring-plugin\"", + "server:dev": "yarn buid:web-plugins && cpx \"web/out/**\" \"server/renderer/\" && mkdir -p ./server/@janhq && cp -r ./plugins/* ./server/@janhq && yarn workspace server dev" }, "devDependencies": { diff --git a/plugin-core/events.ts b/plugin-core/events.ts index 664c230802..4145461656 100644 --- a/plugin-core/events.ts +++ b/plugin-core/events.ts @@ -6,6 +6,9 @@ export enum EventName { OnNewMessageRequest = "onNewMessageRequest", OnNewMessageResponse = "onNewMessageResponse", OnMessageResponseUpdate = "onMessageResponseUpdate", + OnDownloadUpdate = "OnDownloadUpdate", + OnDownloadSuccess = "OnDownloadSuccess", + OnDownloadError = "OnDownloadError" } /** diff --git a/plugins/data-plugin/module.ts b/plugins/data-plugin/module.ts index b5497e978e..21878d0f77 100644 --- a/plugins/data-plugin/module.ts +++ b/plugins/data-plugin/module.ts @@ -16,7 +16,7 @@ const dbs: Record = {}; */ function createCollection(name: string, schema?: { [key: string]: any }): Promise { return new Promise((resolve) => { - const dbPath = path.join(app.getPath("userData"), "databases"); + const dbPath = path.join(appPath(), "databases"); if (!fs.existsSync(dbPath)) fs.mkdirSync(dbPath); const db = new PouchDB(`${path.join(dbPath, name)}`); dbs[name] = db; @@ -226,6 +226,13 @@ function findMany( .then((data) => data.docs); // Return documents } +function appPath() { + if (app) { + return app.getPath("userData"); + } + return process.env.APPDATA || (process.platform == 'darwin' ? process.env.HOME + '/Library/Preferences' : process.env.HOME + "/.local/share"); +} + module.exports = { createCollection, deleteCollection, diff --git a/plugins/inference-plugin/module.ts b/plugins/inference-plugin/module.ts index e80bc804c5..7ada4a39f5 100644 --- a/plugins/inference-plugin/module.ts +++ b/plugins/inference-plugin/module.ts @@ -46,7 +46,7 @@ const initModel = (fileName) => { config.custom_config = {}; } - const modelPath = path.join(app.getPath("userData"), fileName); + const modelPath = path.join(appPath(), fileName); config.custom_config.llama_model_path = modelPath; @@ -112,6 +112,13 @@ function killSubprocess() { } } +function appPath() { + if (app) { + return app.getPath("userData"); + } + return process.env.APPDATA || (process.platform == 'darwin' ? process.env.HOME + '/Library/Preferences' : process.env.HOME + "/.local/share"); +} + module.exports = { initModel, killSubprocess, diff --git a/plugins/model-management-plugin/index.ts b/plugins/model-management-plugin/index.ts index 26acdde3ee..d64a0302fd 100644 --- a/plugins/model-management-plugin/index.ts +++ b/plugins/model-management-plugin/index.ts @@ -1,4 +1,4 @@ -import { ModelManagementService, PluginService, RegisterExtensionPoint, core, store } from "@janhq/plugin-core"; +import { ModelManagementService, PluginService, RegisterExtensionPoint, core, store, EventName, events } from "@janhq/plugin-core"; const PluginName = "@janhq/model-management-plugin"; const MODULE_PATH = "@janhq/model-management-plugin/dist/module.js"; @@ -7,7 +7,60 @@ const getDownloadedModels = () => core.invokePluginFunc(MODULE_PATH, "getDownloa const getAvailableModels = () => core.invokePluginFunc(MODULE_PATH, "getAvailableModels"); -const downloadModel = (product) => core.downloadFile(product.downloadUrl, product.fileName); +const downloadModel = (product) => { + core.downloadFile(product.downloadUrl, product.fileName); + checkDownloadProgress(product.fileName); +} + +async function checkDownloadProgress(fileName: string) { + if (typeof window !== "undefined" && typeof (window as any).electronAPI === "undefined") { + const intervalId = setInterval(() => { + downloadProgress(fileName, intervalId); + }, 3000); + } +} + +async function downloadProgress(fileName: string, intervalId: NodeJS.Timeout): Promise { + const response = await fetch("/api/v1/downloadProgress", { + method: 'POST', + body: JSON.stringify({ fileName: fileName }), + headers: { 'Content-Type': 'application/json', 'Authorization': '' } + }); + + if (!response.ok) { + events.emit(EventName.OnDownloadError, null); + clearInterval(intervalId); + } + else if (response.status >= 400) { + events.emit(EventName.OnDownloadError, null); + clearInterval(intervalId); + } + else { + const text = await response.text(); + try { + const json = JSON.parse(text) + if (isEmptyObject(json)) { + if (!fileName) { + clearInterval(intervalId); + } + return; + } + if (json?.success === true) { + events.emit(EventName.OnDownloadSuccess, json); + clearInterval(intervalId); + } else { + events.emit(EventName.OnDownloadUpdate, json); + } + } catch (err) { + events.emit(EventName.OnDownloadError, null); + clearInterval(intervalId); + } + } +} + +function isEmptyObject(ojb: any): boolean { + return Object.keys(ojb).length === 0; +} const deleteModel = (path) => core.deleteFile(path); @@ -79,6 +132,7 @@ function getModelById(modelId: string): Promise { function onStart() { store.createCollection("models", {}); + checkDownloadProgress(null); } // Register all the above functions and objects with the relevant extension points diff --git a/server/main.ts b/server/main.ts index 1439252f2d..70f49fe88f 100644 --- a/server/main.ts +++ b/server/main.ts @@ -1,6 +1,6 @@ import express, { Express, Request, Response } from 'express' import cors from "cors"; -import { resolve} from "path"; +import { resolve } from "path"; import { unlink, createWriteStream } from "fs"; import * as http from 'http'; const progress = require("request-progress"); @@ -13,11 +13,16 @@ const port: number = 4000 const dataDir = __dirname; type DownloadProgress = Record; const downloadProgress: DownloadProgress = {}; - const app: Express = express() + app.use(express.static('renderer')) app.use(cors(options)) app.use(express.json()); +app.use((err: Error, req: Request, res: Response, next: Function) => { + console.error(err.stack); + res.status(500).send({ error: err }); +}); + app.post('/api/v1/invokeFunction', (req: Request, res: Response) => { const method = req.body["method"]; const args = req.body["args"]; @@ -27,6 +32,12 @@ app.post('/api/v1/invokeFunction', (req: Request, res: Response) => { res.json(Object()); break; case "downloadFile": + const obj = downloadingFile(); + if (obj) { + res.status(500) + res.json({ error: obj.fileName + " is being downloaded!" }) + return; + } (async () => { downloadModel(args.downloadUrl, args.fileName); })().catch(e => { @@ -47,31 +58,17 @@ app.post('/api/v1/invokeFunction', (req: Request, res: Response) => { } }); -app.post('/api/v1/chatCompletion', (baseRequest: Request, baseReponse: Response) => { - const postData = JSON.stringify(baseRequest.body); - const options: http.RequestOptions = { - path: '/llama/chat_completion', - hostname: 'localhost', - port: 3928, - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'Content-Length': postData.length - } - }; - const req = http.request(options, function (resp: http.IncomingMessage) { - baseReponse.setHeader('content-disposition', resp.headers['content-disposition'] ?? "attachment; filename=chat_completions.txt"); - baseReponse.setHeader('Content-type', resp.headers['content-type'] ?? "text/plain; charset=utf-8"); - resp.pipe(baseReponse); - }); - req.write(postData); - req.end(); -}); - app.post('/api/v1/downloadProgress', (req: Request, res: Response) => { const fileName = req.body["fileName"]; - if(fileName && downloadProgress[fileName]){ + if (fileName && downloadProgress[fileName]) { res.json(downloadProgress[fileName]) + return; + } else { + const obj = downloadingFile(); + if (obj) { + res.json(obj) + return; + } } res.json(Object()); }); @@ -79,16 +76,17 @@ app.post('/api/v1/downloadProgress', (req: Request, res: Response) => { app.listen(port, () => console.log(`Application is running on port ${port}`)); -const invokeFunction = (modulePath: string, method: string, ...args: any): Promise => { +const invokeFunction = async (modulePath: string, method: string, args: any): Promise => { console.log(modulePath, method, args); const module = require(/* webpackIgnore: true */ path.join( dataDir, - "plugins", + "", modulePath )); requiredModules[modulePath] = module; if (typeof module[method] === "function") { - return module[method](...args); + return (module[method](...args)) + .catch((err: any) => { console.log(err) }) } else { return Promise.resolve(); } @@ -101,21 +99,23 @@ const downloadModel = (downloadUrl: string, fileName: string) => { console.log("Download file", fileName, "to", destination); progress(request(downloadUrl), {}) .on("progress", function (state: any) { - downloadProgress[fileName] = state; + downloadProgress[fileName] = { + ...state, + fileName, + }; console.log("downloading file", fileName, state.percent); }) .on("error", function (err: Error) { - console.log("err downloading file", fileName, err); - delete downloadProgress[fileName]; + downloadProgress[fileName] = { + success: false, + fileName: fileName, + }; }) .on("end", function () { - invokeFunction( - "data-plugin/dist/module.js", - "updateFinishedDownloadAt", - fileName, - Date.now() - ); - delete downloadProgress[fileName]; + downloadProgress[fileName] = { + success: true, + fileName: fileName, + }; }) .pipe(createWriteStream(destination)); } @@ -138,3 +138,7 @@ const deleteFile = (filePath: string) => { return result; } +const downloadingFile = (): any | undefined => { + const obj = Object.values(downloadProgress).find(obj => obj && typeof obj.success === "undefined") + return obj +} \ No newline at end of file diff --git a/web/app/_helpers/EventHandler.tsx b/web/app/_helpers/EventHandler.tsx index 219a383907..82ae5e8ee4 100644 --- a/web/app/_helpers/EventHandler.tsx +++ b/web/app/_helpers/EventHandler.tsx @@ -1,12 +1,20 @@ import { addNewMessageAtom, updateMessageAtom } from "@/_helpers/atoms/ChatMessage.atom"; +import { setDownloadStateAtom, setDownloadStateSuccessAtom } from "@/_helpers/atoms/DownloadState.atom"; import { toChatMessage } from "@/_models/ChatMessage"; import { events, EventName, NewMessageResponse } from "@janhq/plugin-core"; import { useSetAtom } from "jotai"; import { ReactNode, useEffect } from "react"; +import { executeSerial } from "../../../electron/core/plugin-manager/execution/extension-manager"; +import { ModelManagementService } from "@janhq/plugin-core"; +import { getDownloadedModels } from "@/_hooks/useGetDownloadedModels"; +import { downloadedModelAtom } from "./atoms/DownloadedModel.atom"; export default function EventHandler({ children }: { children: ReactNode }) { const addNewMessage = useSetAtom(addNewMessageAtom); const updateMessage = useSetAtom(updateMessageAtom); + const setDownloadState = useSetAtom(setDownloadStateAtom); + const setDownloadStateSuccess = useSetAtom(setDownloadStateSuccessAtom); + const setDownloadedModels = useSetAtom(downloadedModelAtom); function handleNewMessageResponse(message: NewMessageResponse) { const newResponse = toChatMessage(message); @@ -17,10 +25,28 @@ export default function EventHandler({ children }: { children: ReactNode }) { updateMessage(messageResponse._id, messageResponse.conversationId, messageResponse.message); } + function handleDownloadUpdate(state: any) { + if (!state) return; + setDownloadState(state); + } + + function handleDownloadSuccess(state: any) { + if (state && state.fileName && state.success === true) { + setDownloadStateSuccess(state.fileName); + executeSerial(ModelManagementService.UpdateFinishedDownloadAt, state.fileName).then(() => { + getDownloadedModels().then((models) => { + setDownloadedModels(models); + }); + }); + } + } + useEffect(() => { if (window.corePlugin.events) { events.on(EventName.OnNewMessageResponse, handleNewMessageResponse); events.on(EventName.OnMessageResponseUpdate, handleMessageResponseUpdate); + events.on(EventName.OnDownloadUpdate, handleDownloadUpdate); + events.on(EventName.OnDownloadSuccess, handleDownloadSuccess); } }, []); @@ -28,6 +54,8 @@ export default function EventHandler({ children }: { children: ReactNode }) { return () => { events.off(EventName.OnNewMessageResponse, handleNewMessageResponse); events.off(EventName.OnMessageResponseUpdate, handleMessageResponseUpdate); + events.off(EventName.OnDownloadUpdate, handleDownloadUpdate); + events.off(EventName.OnDownloadSuccess, handleDownloadSuccess); }; }, []); return <> {children}; diff --git a/web/app/_hooks/useGetSystemResources.ts b/web/app/_hooks/useGetSystemResources.ts index 7461a2f7c7..407b208cde 100644 --- a/web/app/_hooks/useGetSystemResources.ts +++ b/web/app/_hooks/useGetSystemResources.ts @@ -23,12 +23,12 @@ export default function useGetSystemResources() { getSystemResources(); // Fetch interval - every 3s - // const intervalId = setInterval(() => { - // getSystemResources(); - // }, 3000); + const intervalId = setInterval(() => { + getSystemResources(); + }, 3000); // clean up - // return () => clearInterval(intervalId); + return () => clearInterval(intervalId); }, []); return { diff --git a/web/app/_services/coreService.ts b/web/app/_services/coreService.ts index 83818351a1..4edd95dd8d 100644 --- a/web/app/_services/coreService.ts +++ b/web/app/_services/coreService.ts @@ -1,10 +1,7 @@ import { store } from "./storeService"; import { EventEmitter } from "./eventsService"; - import { version } from '../../package.json'; -const API_PATH: string = "http://localhost:4000/api/v1/invokeFunction"; -const CHAT_API: string = "http://localhost:4000/api/v1/chatCompletion"; -const DOWNLOAD_PROGRESS_API: string = "http://localhost:4000/api/v1/downloadProgress"; +const API_BASE_PATH: string = "/api/v1"; export const setupCoreServices = () => { if (typeof window === "undefined") { console.log("undefine", window); @@ -22,8 +19,7 @@ export const setupCoreServices = () => { invokePluginFunc, downloadFile, deleteFile, - appVersion, - inferenceUrl + appVersion }; } }; @@ -32,14 +28,11 @@ async function appVersion() { return Promise.resolve(version) } -function invokePluginFunc(modulePath: string, pluginFunc: string, args: any): Promise { +function invokePluginFunc(modulePath: string, pluginFunc: string, ...args: any): Promise { return fetchApi(modulePath, pluginFunc, args); }; async function downloadFile(downloadUrl: string, fileName: string) { - const intervalId = setInterval(() => { - downloadProgress(fileName, intervalId); - }, 3000); return fetchApi("", "downloadFile", { downloadUrl: downloadUrl, fileName: fileName }); } @@ -47,12 +40,8 @@ async function deleteFile(fileName: string) { return fetchApi("", "deleteFile", fileName); } -function inferenceUrl() { - return CHAT_API; -} - async function fetchApi(modulePath: string, pluginFunc: string, args: any): Promise { - const response = await fetch(API_PATH, { + const response = await fetch(API_BASE_PATH + "/invokeFunction", { method: 'POST', body: JSON.stringify({ "modulePath": modulePath, "method": pluginFunc, "args": args }), headers: { 'Content-Type': 'application/json', 'Authorization': '' } @@ -77,31 +66,3 @@ async function fetchApi(modulePath: string, pluginFunc: string, args: any): Prom } } -async function downloadProgress(fileName: string, intervalId: NodeJS.Timeout): Promise { - const response = await fetch(DOWNLOAD_PROGRESS_API, { - method: 'POST', - body: JSON.stringify({ fileName: fileName }), - headers: { 'Content-Type': 'application/json', 'Authorization': '' } - }); - - if (!response.ok) { - console.error("Error"); - clearInterval(intervalId); - return null; - } - else if (response.status >= 400) { - console.error('HTTP Error: ' + response.status + ' - ' + response.text); - clearInterval(intervalId); - return null; - } - else { - const text = await response.text(); - try { - const json = JSON.parse(text) - return Promise.resolve(json); - } catch (err) { - clearInterval(intervalId); - return Promise.resolve(text); - } - } -} \ No newline at end of file diff --git a/web/app/page.tsx b/web/app/page.tsx index 8bb3950812..bb928f9698 100644 --- a/web/app/page.tsx +++ b/web/app/page.tsx @@ -5,15 +5,6 @@ import JotaiWrapper from "./_helpers/JotaiWrapper"; import { ModalWrapper } from "./_helpers/ModalWrapper"; import { useEffect, useState } from "react"; import Image from "next/image"; -import {setupMiddleware} from './middlware'; - -import {"use client"; -import { PluginService } from "@janhq/plugin-core"; -import { ThemeWrapper } from "./_helpers/ThemeWrapper"; -import JotaiWrapper from "./_helpers/JotaiWrapper"; -import { ModalWrapper } from "./_helpers/ModalWrapper"; -import { useEffect, useState } from "react"; -import Image from "next/image"; import { setup, plugins, activationPoints, extensionPoints } from "../../electron/core/plugin-manager/execution/index"; import { isCorePluginInstalled, setupBasePlugins } from "./_services/pluginService"; import EventListenerWrapper from "./_helpers/EventListenerWrapper"; @@ -59,95 +50,7 @@ const Page: React.FC = () => { useEffect(() => { if (setupCore) { // Electron - if (window && window.electronAPI) { - setupPE(); - } else { - // Host - setActivated(true); - } - } - }, [setupCore]); - - return ( - - {setupCore && ( - - - - {activated ? ( - - ) : ( -
- -
- )} -
-
-
- )} -
- ); -}; - -export default Page; - - setup, - plugins, - activationPoints, -} from "../../electron/core/plugin-manager/execution/index"; -import { - isCorePluginInstalled, - setupBasePlugins, -} from "./_services/pluginService"; -import EventListenerWrapper from "./_helpers/EventListenerWrapper"; -import { setupCoreServices } from "./_services/coreService"; -import MainContainer from "./_components/MainContainer"; -import { executeSerial } from "../../electron/core/plugin-manager/execution/extension-manager"; - -const Page: React.FC = () => { - const [setupCore, setSetupCore] = useState(false); - const [activated, setActivated] = useState(false); - setupMiddleware(); - // Services Setup - useEffect(() => { - // Setup Core Service - setupCoreServices(); - - async function setupPE() { - // Enable activation point management - setup({ - importer: (plugin: string) => - import(/* webpackIgnore: true */ plugin).catch((err) => { - console.log(err); - }), - }); - - // Register all active plugins with their activation points - await plugins.registerActive(); - setTimeout(async () => { - // Trigger activation points - await activationPoints.trigger("init"); - if (!isCorePluginInstalled()) { - setupBasePlugins(); - return; - } - if (extensionPoints.get(PluginService.OnStart)) { - await executeSerial(PluginService.OnStart); - } - setActivated(true); - }, 500); - } - - // Services Setup - useEffect(() => { - setupCoreServices(); - setSetupCore(true); - }, []); - - useEffect(() => { - if (setupCore) { - // Electron - if (window && window.electronAPI) { + if (window && window.coreAPI) { setupPE(); } else { // Host @@ -177,4 +80,4 @@ const Page: React.FC = () => { ); }; -export default Page; +export default Page; \ No newline at end of file diff --git a/web/public/plugins/data-plugin/index.js b/web/public/plugins/data-plugin/index.js index b34c21a43b..4e2a710c1c 100644 --- a/web/public/plugins/data-plugin/index.js +++ b/web/public/plugins/data-plugin/index.js @@ -1 +1,673 @@ -var e={d:(d,n)=>{for(var i in n)e.o(n,i)&&!e.o(d,i)&&Object.defineProperty(d,i,{enumerable:!0,get:n[i]})},o:(e,d)=>Object.prototype.hasOwnProperty.call(e,d)},d={};e.d(d,{S:()=>P});const n="data-plugin/dist/module.js",i=e=>new Promise((d=>{"undefined"!=typeof window&&void 0!==window.middleware&&window.middleware.invokePluginFunc(n,"storeModel",e).then((e=>d(e)))})),o=()=>new Promise((e=>{"undefined"!=typeof window&&void 0!==window.middleware&&window.middleware.invokePluginFunc(n,"getFinishedDownloadModels").then((d=>e(d)))})),w=e=>new Promise((d=>{"undefined"!=typeof window&&void 0!==window.middleware&&window.middleware.invokePluginFunc(n,"getModelById",e).then((e=>d(e)))})),t=e=>new Promise((d=>{"undefined"!=typeof window&&void 0!==window.middleware&&window.middleware.invokePluginFunc(n,"updateFinishedDownloadAt",e,Date.now()).then((e=>d(e)))})),l=()=>new Promise((e=>{"undefined"!=typeof window&&void 0!==window.middleware?window.middleware.invokePluginFunc(n,"getUnfinishedDownloadModels").then((d=>e(d))):e([])})),a=e=>new Promise((d=>{"undefined"!=typeof window&&void 0!==window.middleware&&window.middleware.invokePluginFunc(n,"deleteDownloadModel",e).then((e=>d(e)))})),s=()=>new Promise((e=>{"undefined"!=typeof window&&void 0!==window.middleware?window.middleware.invokePluginFunc(n,"getConversations").then((d=>e(d))):e([])})),r=e=>new Promise((d=>{"undefined"!=typeof window&&void 0!==window.middleware?window.middleware.invokePluginFunc(n,"getConversationMessages",e).then((e=>d(e))):d([])})),u=e=>new Promise((d=>{"undefined"!=typeof window&&void 0!==window.middleware?window.middleware.invokePluginFunc(n,"storeConversation",e).then((e=>{d(e)})):d(void 0)})),v=e=>new Promise((d=>{"undefined"!=typeof window&&void 0!==window.middleware?window.middleware.invokePluginFunc(n,"storeMessage",e).then((e=>{d(e)})):d(void 0)})),g=e=>new Promise((d=>{"undefined"!=typeof window&&void 0!==window.middleware?window.middleware.invokePluginFunc(n,"updateMessage",e).then((e=>{d(e)})):d(void 0)})),m=e=>new Promise((d=>{"undefined"!=typeof window&&void 0!==window.middleware?window.middleware.invokePluginFunc(n,"deleteConversation",e).then((e=>{d(e)})):d("-")})),f=()=>{"undefined"!=typeof window&&void 0!==window.middleware&&window.middleware.invokePluginFunc(n,"init")};function P({register:e}){f(),e("getConversations","getConv",s,1),e("createConversation","insertConv",u),e("updateMessage","updateMessage",g),e("deleteConversation","deleteConv",m),e("createMessage","insertMessage",v),e("getConversationMessages","getMessages",r),e("storeModel","storeModel",i),e("updateFinishedDownloadAt","updateFinishedDownloadAt",t),e("getUnfinishedDownloadModels","getUnfinishedDownloadModels",l),e("deleteDownloadModel","deleteDownloadModel",a),e("getModelById","getModelById",w),e("getFinishedDownloadModels","getFinishedDownloadModels",o)}var p=d.S;export{p as init}; \ No newline at end of file +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/define property getters */ +/******/ (() => { +/******/ // define getter functions for harmony exports +/******/ __webpack_require__.d = (exports, definition) => { +/******/ for(var key in definition) { +/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { +/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); +/******/ } +/******/ } +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; + +// EXPORTS +__webpack_require__.d(__webpack_exports__, { + S: () => (/* binding */ init) +}); + +;// CONCATENATED MODULE: ../../plugin-core/lib/store.js +/** + * Creates, reads, updates, and deletes data in a data store. + * @module + */ +/** + * Creates a new collection in the data store. + * @param {string} name - The name of the collection to create. + * @param { [key: string]: any } schema - schema of the collection to create, include fields and their types + * @returns {Promise} A promise that resolves when the collection is created. + */ +function createCollection(name, schema) { + var _a, _b; + return (_b = (_a = window.corePlugin) === null || _a === void 0 ? void 0 : _a.store) === null || _b === void 0 ? void 0 : _b.createCollection(name, schema); +} +/** + * Deletes a collection from the data store. + * @param {string} name - The name of the collection to delete. + * @returns {Promise} A promise that resolves when the collection is deleted. + */ +function deleteCollection(name) { + var _a, _b; + return (_b = (_a = window.corePlugin) === null || _a === void 0 ? void 0 : _a.store) === null || _b === void 0 ? void 0 : _b.deleteCollection(name); +} +/** + * Inserts a value into a collection in the data store. + * @param {string} collectionName - The name of the collection to insert the value into. + * @param {any} value - The value to insert into the collection. + * @returns {Promise} A promise that resolves with the inserted value. + */ +function insertOne(collectionName, value) { + var _a, _b; + return (_b = (_a = window.corePlugin) === null || _a === void 0 ? void 0 : _a.store) === null || _b === void 0 ? void 0 : _b.insertOne(collectionName, value); +} +/** + * Retrieve a record from a collection in the data store. + * @param {string} collectionName - The name of the collection containing the record to retrieve. + * @param {string} key - The key of the record to retrieve. + * @returns {Promise} A promise that resolves when the record is retrieved. + */ +function findOne(collectionName, key) { + var _a, _b; + return (_b = (_a = window.corePlugin) === null || _a === void 0 ? void 0 : _a.store) === null || _b === void 0 ? void 0 : _b.findOne(collectionName, key); +} +/** + * Retrieves all records that match a selector in a collection in the data store. + * @param {string} collectionName - The name of the collection to retrieve. + * @param {{ [key: string]: any }} selector - The selector to use to get records from the collection. + * @param {[{ [key: string]: any }]} sort - The sort options to use to retrieve records. + * @returns {Promise} A promise that resolves when all records are retrieved. + */ +function findMany(collectionName, selector, sort) { + var _a, _b; + return (_b = (_a = window.corePlugin) === null || _a === void 0 ? void 0 : _a.store) === null || _b === void 0 ? void 0 : _b.findMany(collectionName, selector, sort); +} +/** + * Updates the value of a record in a collection in the data store. + * @param {string} collectionName - The name of the collection containing the record to update. + * @param {string} key - The key of the record to update. + * @param {any} value - The new value for the record. + * @returns {Promise} A promise that resolves when the record is updated. + */ +function updateOne(collectionName, key, value) { + var _a, _b; + return (_b = (_a = window.corePlugin) === null || _a === void 0 ? void 0 : _a.store) === null || _b === void 0 ? void 0 : _b.updateOne(collectionName, key, value); +} +/** + * Updates all records that match a selector in a collection in the data store. + * @param {string} collectionName - The name of the collection containing the records to update. + * @param {{ [key: string]: any }} selector - The selector to use to get the records to update. + * @param {any} value - The new value for the records. + * @returns {Promise} A promise that resolves when the records are updated. + */ +function updateMany(collectionName, value, selector) { + var _a, _b; + return (_b = (_a = window.corePlugin) === null || _a === void 0 ? void 0 : _a.store) === null || _b === void 0 ? void 0 : _b.updateMany(collectionName, selector, value); +} +/** + * Deletes a single record from a collection in the data store. + * @param {string} collectionName - The name of the collection containing the record to delete. + * @param {string} key - The key of the record to delete. + * @returns {Promise} A promise that resolves when the record is deleted. + */ +function deleteOne(collectionName, key) { + var _a, _b; + return (_b = (_a = window.corePlugin) === null || _a === void 0 ? void 0 : _a.store) === null || _b === void 0 ? void 0 : _b.deleteOne(collectionName, key); +} +/** + * Deletes all records with a matching key from a collection in the data store. + * @param {string} collectionName - The name of the collection to delete the records from. + * @param {{ [key: string]: any }} selector - The selector to use to get the records to delete. + * @returns {Promise} A promise that resolves when the records are deleted. + */ +function deleteMany(collectionName, selector) { + var _a, _b; + return (_b = (_a = window.corePlugin) === null || _a === void 0 ? void 0 : _a.store) === null || _b === void 0 ? void 0 : _b.deleteMany(collectionName, selector); +} +/** + * Exports the data store operations as an object. + */ +const store = { + createCollection, + deleteCollection, + insertOne, + findOne, + findMany, + updateOne, + updateMany, + deleteOne, + deleteMany, +}; + +;// CONCATENATED MODULE: ../../plugin-core/lib/core.js +/** + * Execute a plugin module function in main process + * + * @param plugin plugin name to import + * @param method function name to execute + * @param args arguments to pass to the function + * @returns Promise + * + */ +const invokePluginFunc = (plugin, method, ...args) => { + var _a, _b, _c; + return (_b = (_a = window.coreAPI) === null || _a === void 0 ? void 0 : _a.invokePluginFunc(plugin, method, ...args)) !== null && _b !== void 0 ? _b : (_c = window.electronAPI) === null || _c === void 0 ? void 0 : _c.invokePluginFunc(plugin, method, ...args); +}; +/** + * Downloads a file from a URL and saves it to the local file system. + * @param {string} url - The URL of the file to download. + * @param {string} fileName - The name to use for the downloaded file. + * @returns {Promise} A promise that resolves when the file is downloaded. + */ +const downloadFile = (url, fileName) => { var _a, _b, _c; return (_b = (_a = window.coreAPI) === null || _a === void 0 ? void 0 : _a.downloadFile(url, fileName)) !== null && _b !== void 0 ? _b : (_c = window.electronAPI) === null || _c === void 0 ? void 0 : _c.downloadFile(url, fileName); }; +/** + * Deletes a file from the local file system. + * @param {string} path - The path of the file to delete. + * @returns {Promise} A promise that resolves when the file is deleted. + */ +const deleteFile = (path) => { var _a, _b, _c; return (_b = (_a = window.coreAPI) === null || _a === void 0 ? void 0 : _a.deleteFile(path)) !== null && _b !== void 0 ? _b : (_c = window.electronAPI) === null || _c === void 0 ? void 0 : _c.deleteFile(path); }; +const appData = () => { + if (typeof window !== "undefined") { + return window.electronAPI.appData(); + } + return process.env.APPDATA || (process.platform == 'darwin' ? process.env.HOME + '/Library/Preferences' : process.env.HOME + "/.local/share"); +}; +/** + * Core exports + */ +const core = { + invokePluginFunc, + downloadFile, + deleteFile, + appData +}; + +;// CONCATENATED MODULE: ../../plugin-core/lib/events.js +/** + * The `EventName` enumeration contains the names of all the available events in the Jan platform. + */ +var EventName; +(function (EventName) { + EventName["OnNewConversation"] = "onNewConversation"; + EventName["OnNewMessageRequest"] = "onNewMessageRequest"; + EventName["OnNewMessageResponse"] = "onNewMessageResponse"; + EventName["OnMessageResponseUpdate"] = "onMessageResponseUpdate"; + EventName["OnDownloadUpdate"] = "OnDownloadUpdate"; + EventName["OnDownloadSuccess"] = "OnDownloadSuccess"; + EventName["OnDownloadError"] = "OnDownloadError"; +})(EventName || (EventName = {})); +/** + * Adds an observer for an event. + * + * @param eventName The name of the event to observe. + * @param handler The handler function to call when the event is observed. + */ +const on = (eventName, handler) => { + var _a, _b; + (_b = (_a = window.corePlugin) === null || _a === void 0 ? void 0 : _a.events) === null || _b === void 0 ? void 0 : _b.on(eventName, handler); +}; +/** + * Removes an observer for an event. + * + * @param eventName The name of the event to stop observing. + * @param handler The handler function to call when the event is observed. + */ +const off = (eventName, handler) => { + var _a, _b; + (_b = (_a = window.corePlugin) === null || _a === void 0 ? void 0 : _a.events) === null || _b === void 0 ? void 0 : _b.off(eventName, handler); +}; +/** + * Emits an event. + * + * @param eventName The name of the event to emit. + * @param object The object to pass to the event callback. + */ +const emit = (eventName, object) => { + var _a, _b; + (_b = (_a = window.corePlugin) === null || _a === void 0 ? void 0 : _a.events) === null || _b === void 0 ? void 0 : _b.emit(eventName, object); +}; +const events = { + on, + off, + emit, +}; + +;// CONCATENATED MODULE: ../../plugin-core/lib/preferences.js + +/** + * Returns the value of the specified preference for the specified plugin. + * + * @param pluginName The name of the plugin. + * @param preferenceKey The key of the preference. + * @returns A promise that resolves to the value of the preference. + */ +function get(pluginName, preferenceKey) { + return store + .createCollection("preferences", {}) + .then(() => store.findOne("preferences", `${pluginName}.${preferenceKey}`)) + .then((doc) => { var _a; return (_a = doc === null || doc === void 0 ? void 0 : doc.value) !== null && _a !== void 0 ? _a : ""; }); +} +/** + * Sets the value of the specified preference for the specified plugin. + * + * @param pluginName The name of the plugin. + * @param preferenceKey The key of the preference. + * @param value The value of the preference. + * @returns A promise that resolves when the preference has been set. + */ +function set(pluginName, preferenceKey, value) { + return store + .createCollection("preferences", {}) + .then(() => store + .findOne("preferences", `${pluginName}.${preferenceKey}`) + .then((doc) => doc + ? store.updateOne("preferences", `${pluginName}.${preferenceKey}`, { value }) + : store.insertOne("preferences", { _id: `${pluginName}.${preferenceKey}`, value }))); +} +/** + * Clears all preferences for the specified plugin. + * + * @param pluginName The name of the plugin. + * @returns A promise that resolves when the preferences have been cleared. + */ +function clear(pluginName) { + return Promise.resolve(); +} +/** + * Registers a preference with the specified default value. + * + * @param register The function to use for registering the preference. + * @param pluginName The name of the plugin. + * @param preferenceKey The key of the preference. + * @param preferenceName The name of the preference. + * @param preferenceDescription The description of the preference. + * @param defaultValue The default value of the preference. + */ +function registerPreferences(register, pluginName, preferenceKey, preferenceName, preferenceDescription, defaultValue) { + register("PluginPreferences", `${pluginName}.${preferenceKey}`, () => ({ + pluginName, + preferenceKey, + preferenceName, + preferenceDescription, + defaultValue, + })); +} +/** + * An object that provides methods for getting, setting, and clearing preferences. + */ +const preferences = { + get, + set, + clear, + registerPreferences, +}; + +;// CONCATENATED MODULE: ../../plugin-core/lib/index.js +/** + * CoreService exports + */ +/** + * Represents the available methods for the StoreService. + * @enum {string} + */ +var StoreService; +(function (StoreService) { + /** + * Creates a new collection in the database store. + */ + StoreService["CreateCollection"] = "createCollection"; + /** + * Deletes an existing collection from the database store. + */ + StoreService["DeleteCollection"] = "deleteCollection"; + /** + * Inserts a new value into an existing collection in the database store. + */ + StoreService["InsertOne"] = "insertOne"; + /** + * Updates an existing value in an existing collection in the database store. + */ + StoreService["UpdateOne"] = "updateOne"; + /** + * Updates multiple records in a collection in the database store. + */ + StoreService["UpdateMany"] = "updateMany"; + /** + * Deletes an existing value from an existing collection in the database store. + */ + StoreService["DeleteOne"] = "deleteOne"; + /** + * Delete multiple records in a collection in the database store. + */ + StoreService["DeleteMany"] = "deleteMany"; + /** + * Retrieve multiple records from a collection in the data store + */ + StoreService["FindMany"] = "findMany"; + /** + * Retrieve a record from a collection in the data store. + */ + StoreService["FindOne"] = "findOne"; +})(StoreService || (StoreService = {})); +/** + * DataService exports. + * @enum {string} + */ +var DataService; +(function (DataService) { + /** + * Gets a list of conversations from the server. + */ + DataService["GetConversations"] = "getConversations"; + /** + * Creates a new conversation on the server. + */ + DataService["CreateConversation"] = "createConversation"; + /** + * Updates an existing conversation on the server. + */ + DataService["UpdateConversation"] = "updateConversation"; + /** + * Deletes an existing conversation from the server. + */ + DataService["DeleteConversation"] = "deleteConversation"; + /** + * Creates a new message in an existing conversation on the server. + */ + DataService["CreateMessage"] = "createMessage"; + /** + * Updates an existing message in an existing conversation on the server. + */ + DataService["UpdateMessage"] = "updateMessage"; + /** + * Gets a list of messages for an existing conversation from the server. + */ + DataService["GetConversationMessages"] = "getConversationMessages"; +})(DataService || (DataService = {})); +/** + * InferenceService exports. + * @enum {string} + */ +var InferenceService; +(function (InferenceService) { + /** + * Initializes a model for inference. + */ + InferenceService["InitModel"] = "initModel"; + /** + * Stops a running inference model. + */ + InferenceService["StopModel"] = "stopModel"; +})(InferenceService || (InferenceService = {})); +/** + * ModelManagementService exports. + * @enum {string} + */ +var ModelManagementService; +(function (ModelManagementService) { + /** + * Gets a list of downloaded models. + */ + ModelManagementService["GetDownloadedModels"] = "getDownloadedModels"; + /** + * Gets a list of available models from the server. + */ + ModelManagementService["GetAvailableModels"] = "getAvailableModels"; + /** + * Deletes a downloaded model. + */ + ModelManagementService["DeleteModel"] = "deleteModel"; + /** + * Downloads a model from the server. + */ + ModelManagementService["DownloadModel"] = "downloadModel"; + /** + * Searches for models on the server. + */ + ModelManagementService["SearchModels"] = "searchModels"; + /** + * Gets configued models from the database. + */ + ModelManagementService["GetConfiguredModels"] = "getConfiguredModels"; + /** + * Stores a model in the database. + */ + ModelManagementService["StoreModel"] = "storeModel"; + /** + * Updates the finished download time for a model in the database. + */ + ModelManagementService["UpdateFinishedDownloadAt"] = "updateFinishedDownloadAt"; + /** + * Gets a list of unfinished download models from the database. + */ + ModelManagementService["GetUnfinishedDownloadModels"] = "getUnfinishedDownloadModels"; + /** + * Gets a list of finished download models from the database. + */ + ModelManagementService["GetFinishedDownloadModels"] = "getFinishedDownloadModels"; + /** + * Deletes a download model from the database. + */ + ModelManagementService["DeleteDownloadModel"] = "deleteDownloadModel"; + /** + * Gets a model by its ID from the database. + */ + ModelManagementService["GetModelById"] = "getModelById"; +})(ModelManagementService || (ModelManagementService = {})); +/** + * PreferenceService exports. + * @enum {string} + */ +var PreferenceService; +(function (PreferenceService) { + /** + * The experiment component for which preferences are being managed. + */ + PreferenceService["ExperimentComponent"] = "experimentComponent"; +})(PreferenceService || (PreferenceService = {})); +/** + * SystemMonitoringService exports. + * @enum {string} + */ +var SystemMonitoringService; +(function (SystemMonitoringService) { + /** + * Gets information about system resources. + */ + SystemMonitoringService["GetResourcesInfo"] = "getResourcesInfo"; + /** + * Gets the current system load. + */ + SystemMonitoringService["GetCurrentLoad"] = "getCurrentLoad"; +})(SystemMonitoringService || (SystemMonitoringService = {})); +/** + * PluginService exports. + * @enum {string} + */ +var PluginService; +(function (PluginService) { + /** + * The plugin is being started. + */ + PluginService["OnStart"] = "pluginOnStart"; + /** + * The plugin is being started. + */ + PluginService["OnPreferencesUpdate"] = "pluginPreferencesUpdate"; + /** + * The plugin is being stopped. + */ + PluginService["OnStop"] = "pluginOnStop"; + /** + * The plugin is being destroyed. + */ + PluginService["OnDestroy"] = "pluginOnDestroy"; +})(PluginService || (PluginService = {})); +/** + * Store module exports. + * @module + */ + +/** + * Core module exports. + * @module + */ + +/** + * Events module exports. + * @module + */ + +/** + * Preferences module exports. + * @module + */ + + +;// CONCATENATED MODULE: ./index.ts + +const PluginName = "@janhq/data-plugin"; +const MODULE_PATH = "@janhq/data-plugin/dist/cjs/module.js"; +/** + * Create a collection on data store + * + * @param name name of the collection to create + * @param schema schema of the collection to create, include fields and their types + * @returns Promise + * + */ +function index_createCollection({ name, schema }) { + return core.invokePluginFunc(MODULE_PATH, "createCollection", name, schema); +} +/** + * Delete a collection + * + * @param name name of the collection to delete + * @returns Promise + * + */ +function index_deleteCollection(name) { + return core.invokePluginFunc(MODULE_PATH, "deleteCollection", name); +} +/** + * Insert a value to a collection + * + * @param collectionName name of the collection + * @param value value to insert + * @returns Promise + * + */ +function index_insertOne({ collectionName, value }) { + return core.invokePluginFunc(MODULE_PATH, "insertOne", collectionName, value); +} +/** + * Update value of a collection's record + * + * @param collectionName name of the collection + * @param key key of the record to update + * @param value value to update + * @returns Promise + * + */ +function index_updateOne({ collectionName, key, value }) { + return core.invokePluginFunc(MODULE_PATH, "updateOne", collectionName, key, value); +} +/** + * Updates all records that match a selector in a collection in the data store. + * @param collectionName - The name of the collection containing the records to update. + * @param selector - The selector to use to get the records to update. + * @param value - The new value for the records. + * @returns {Promise} A promise that resolves when the records are updated. + */ +function index_updateMany({ collectionName, value, selector, }) { + return core.invokePluginFunc(MODULE_PATH, "updateMany", collectionName, value, selector); +} +/** + * Delete a collection's record + * + * @param collectionName name of the collection + * @param key key of the record to delete + * @returns Promise + * + */ +function index_deleteOne({ collectionName, key }) { + return core.invokePluginFunc(MODULE_PATH, "deleteOne", collectionName, key); +} +/** + * Deletes all records with a matching key from a collection in the data store. + * + * @param collectionName name of the collection + * @param selector selector to use to get the records to delete. + * @returns {Promise} + * + */ +function index_deleteMany({ collectionName, selector, }) { + return core.invokePluginFunc(MODULE_PATH, "deleteMany", collectionName, selector); +} +/** + * Retrieve a record from a collection in the data store. + * @param {string} collectionName - The name of the collection containing the record to retrieve. + * @param {string} key - The key of the record to retrieve. + * @returns {Promise} A promise that resolves when the record is retrieved. + */ +function index_findOne({ collectionName, key }) { + return core.invokePluginFunc(MODULE_PATH, "findOne", collectionName, key); +} +/** + * Gets records in a collection in the data store using a selector. + * @param {string} collectionName - The name of the collection containing the record to get the value from. + * @param {{ [key: string]: any }} selector - The selector to use to get the value from the record. + * @param {[{ [key: string]: any }]} sort - The sort options to use to retrieve records. + * @returns {Promise} A promise that resolves with the selected value. + */ +function index_findMany({ collectionName, selector, sort, }) { + return core.invokePluginFunc(MODULE_PATH, "findMany", collectionName, selector, sort); +} +function onStart() { + index_createCollection({ name: "conversations", schema: {} }); + index_createCollection({ name: "messages", schema: {} }); +} +// Register all the above functions and objects with the relevant extension points +function init({ register }) { + register(PluginService.OnStart, PluginName, onStart); + register(StoreService.CreateCollection, index_createCollection.name, index_createCollection); + register(StoreService.DeleteCollection, index_deleteCollection.name, index_deleteCollection); + register(StoreService.InsertOne, index_insertOne.name, index_insertOne); + register(StoreService.UpdateOne, index_updateOne.name, index_updateOne); + register(StoreService.UpdateMany, index_updateMany.name, index_updateMany); + register(StoreService.DeleteOne, index_deleteOne.name, index_deleteOne); + register(StoreService.DeleteMany, index_deleteMany.name, index_deleteMany); + register(StoreService.FindOne, index_findOne.name, index_findOne); + register(StoreService.FindMany, index_findMany.name, index_findMany); + register(DataService.GetConversations, getConversations.name, getConversations); + register(DataService.CreateConversation, createConversation.name, createConversation); + register(DataService.UpdateConversation, updateConversation.name, updateConversation); + register(DataService.UpdateMessage, updateMessage.name, updateMessage); + register(DataService.DeleteConversation, deleteConversation.name, deleteConversation); + register(DataService.CreateMessage, createMessage.name, createMessage); + register(DataService.GetConversationMessages, getConversationMessages.name, getConversationMessages); +} +function getConversations() { + return store.findMany("conversations", {}, [{ updatedAt: "desc" }]); +} +function createConversation(conversation) { + return store.insertOne("conversations", conversation); +} +function updateConversation(conversation) { + return store.updateOne("conversations", conversation._id, conversation); +} +function createMessage(message) { + return store.insertOne("messages", message); +} +function updateMessage(message) { + return store.updateOne("messages", message._id, message); +} +function deleteConversation(id) { + return store.deleteOne("conversations", id).then(() => store.deleteMany("messages", { conversationId: id })); +} +function getConversationMessages(conversationId) { + return store.findMany("messages", { conversationId }, [{ createdAt: "desc" }]); +} + +var __webpack_exports__init = __webpack_exports__.S; +export { __webpack_exports__init as init }; diff --git a/web/public/plugins/inference-plugin/index.js b/web/public/plugins/inference-plugin/index.js new file mode 100644 index 0000000000..ca35e54f0a --- /dev/null +++ b/web/public/plugins/inference-plugin/index.js @@ -0,0 +1 @@ +var e={d:(n,o)=>{for(var t in o)e.o(o,t)&&!e.o(n,t)&&Object.defineProperty(n,t,{enumerable:!0,get:o[t]})},o:(e,n)=>Object.prototype.hasOwnProperty.call(e,n)},n={};e.d(n,{S:()=>y});const o=function(e,n){var o,t;return null===(t=null===(o=window.corePlugin)||void 0===o?void 0:o.store)||void 0===t?void 0:t.insertOne(e,n)},t=function(e,n,o){var t,s;return null===(s=null===(t=window.corePlugin)||void 0===t?void 0:t.store)||void 0===s?void 0:s.findMany(e,n,o)},s=function(e,n,o){var t,s;return null===(s=null===(t=window.corePlugin)||void 0===t?void 0:t.store)||void 0===s?void 0:s.updateOne(e,n,o)},i=(e,n,...o)=>{var t,s,i;return null!==(s=null===(t=window.coreAPI)||void 0===t?void 0:t.invokePluginFunc(e,n,...o))&&void 0!==s?s:null===(i=window.electronAPI)||void 0===i?void 0:i.invokePluginFunc(e,n,...o)};var d;!function(e){e.OnNewConversation="onNewConversation",e.OnNewMessageRequest="onNewMessageRequest",e.OnNewMessageResponse="onNewMessageResponse",e.OnMessageResponseUpdate="onMessageResponseUpdate",e.OnDownloadUpdate="OnDownloadUpdate",e.OnDownloadSuccess="OnDownloadSuccess",e.OnDownloadError="OnDownloadError"}(d||(d={}));const a=(e,n)=>{var o,t;null===(t=null===(o=window.corePlugin)||void 0===o?void 0:o.events)||void 0===t||t.emit(e,n)};var l,r,c,u,v,g,p;!function(e){e.CreateCollection="createCollection",e.DeleteCollection="deleteCollection",e.InsertOne="insertOne",e.UpdateOne="updateOne",e.UpdateMany="updateMany",e.DeleteOne="deleteOne",e.DeleteMany="deleteMany",e.FindMany="findMany",e.FindOne="findOne"}(l||(l={})),function(e){e.GetConversations="getConversations",e.CreateConversation="createConversation",e.UpdateConversation="updateConversation",e.DeleteConversation="deleteConversation",e.CreateMessage="createMessage",e.UpdateMessage="updateMessage",e.GetConversationMessages="getConversationMessages"}(r||(r={})),function(e){e.InitModel="initModel",e.StopModel="stopModel"}(c||(c={})),function(e){e.GetDownloadedModels="getDownloadedModels",e.GetAvailableModels="getAvailableModels",e.DeleteModel="deleteModel",e.DownloadModel="downloadModel",e.SearchModels="searchModels",e.GetConfiguredModels="getConfiguredModels",e.StoreModel="storeModel",e.UpdateFinishedDownloadAt="updateFinishedDownloadAt",e.GetUnfinishedDownloadModels="getUnfinishedDownloadModels",e.GetFinishedDownloadModels="getFinishedDownloadModels",e.DeleteDownloadModel="deleteDownloadModel",e.GetModelById="getModelById"}(u||(u={})),function(e){e.ExperimentComponent="experimentComponent"}(v||(v={})),function(e){e.GetResourcesInfo="getResourcesInfo",e.GetCurrentLoad="getCurrentLoad"}(g||(g={})),function(e){e.OnStart="pluginOnStart",e.OnPreferencesUpdate="pluginPreferencesUpdate",e.OnStop="pluginOnStop",e.OnDestroy="pluginOnDestroy"}(p||(p={}));var M=function(e,n,o,t){return new(o||(o=Promise))((function(s,i){function d(e){try{l(t.next(e))}catch(e){i(e)}}function a(e){try{l(t.throw(e))}catch(e){i(e)}}function l(e){var n;e.done?s(e.value):(n=e.value,n instanceof o?n:new o((function(e){e(n)}))).then(d,a)}l((t=t.apply(e,n||[])).next())}))};const w="@janhq/inference-plugin",f=`${w}/dist/module.js`,O=e=>M(void 0,void 0,void 0,(function*(){return i(f,"initModel",e)})),m=()=>{i(f,"killSubprocess")};function D(e){var n,i,l,r;return M(this,void 0,void 0,(function*(){const c=(null!==(n=yield t("messages",{conversationId:e.conversationId},[{createdAt:"asc"}]))&&void 0!==n?n:[]).filter((e=>""!==e.message&&("user"===e.user||"assistant"===e.user))).slice(-10).map((e=>({content:e.message.trim(),role:"user"===e.user?"user":"assistant"}))),u=Object.assign(Object.assign({},e),{message:"",user:"assistant",createdAt:(new Date).toISOString(),_id:void 0}),v=yield o("messages",u);u._id=v,a(d.OnNewMessageResponse,u);const g=(yield fetch("http://localhost:3928/llama/chat_completion",{method:"POST",headers:{"Content-Type":"application/json",Accept:"text/event-stream","Access-Control-Allow-Origi":"*"},body:JSON.stringify({messages:c,stream:!0,model:"gpt-3.5-turbo",max_tokens:500})})).body,p=new TextDecoder("utf-8"),M=null==g?void 0:g.getReader();let w="";for(;M;){const{done:e,value:n}=yield M.read();if(e){console.log("SSE stream closed");break}const o=p.decode(n).trim().split("\n");for(const e of o)if(e.startsWith("data: ")&&!e.includes("data: [DONE]")){const n=JSON.parse(e.replace("data: ",""));w+=null!==(r=null===(l=null===(i=n.choices[0])||void 0===i?void 0:i.delta)||void 0===l?void 0:l.content)&&void 0!==r?r:"",w.startsWith("assistant: ")&&(w=w.replace("assistant: ","")),u.message=w,a(d.OnMessageResponseUpdate,u)}}u.message=w.trim(),yield s("messages",u._id,u)}))}const C=()=>M(void 0,void 0,void 0,(function*(){var e,n,o,t;e=d.OnNewMessageRequest,n=D,null===(t=null===(o=window.corePlugin)||void 0===o?void 0:o.events)||void 0===t||t.on(e,n)}));function y({register:e}){e(p.OnStart,w,C),e(c.InitModel,O.name,O),e(c.StopModel,m.name,m)}var h=n.S;export{h as init}; \ No newline at end of file diff --git a/web/public/plugins/model-management-plugin/index.js b/web/public/plugins/model-management-plugin/index.js index 31f9e680a8..dcf8a18611 100644 --- a/web/public/plugins/model-management-plugin/index.js +++ b/web/public/plugins/model-management-plugin/index.js @@ -27,7 +27,7 @@ __webpack_require__.d(__webpack_exports__, { S: () => (/* binding */ init) }); -;// CONCATENATED MODULE: ../../../../plugin-core/lib/store.js +;// CONCATENATED MODULE: ../../plugin-core/lib/store.js /** * Creates, reads, updates, and deletes data in a data store. * @module @@ -139,7 +139,7 @@ const store = { deleteMany, }; -;// CONCATENATED MODULE: ../../../../plugin-core/lib/core.js +;// CONCATENATED MODULE: ../../plugin-core/lib/core.js /** * Execute a plugin module function in main process * @@ -166,6 +166,12 @@ const downloadFile = (url, fileName) => { var _a, _b, _c; return (_b = (_a = win * @returns {Promise} A promise that resolves when the file is deleted. */ const deleteFile = (path) => { var _a, _b, _c; return (_b = (_a = window.coreAPI) === null || _a === void 0 ? void 0 : _a.deleteFile(path)) !== null && _b !== void 0 ? _b : (_c = window.electronAPI) === null || _c === void 0 ? void 0 : _c.deleteFile(path); }; +const appData = () => { + if (typeof window !== "undefined") { + return window.electronAPI.appData(); + } + return process.env.APPDATA || (process.platform == 'darwin' ? process.env.HOME + '/Library/Preferences' : process.env.HOME + "/.local/share"); +}; /** * Core exports */ @@ -173,9 +179,130 @@ const core = { invokePluginFunc, downloadFile, deleteFile, + appData +}; + +;// CONCATENATED MODULE: ../../plugin-core/lib/events.js +/** + * The `EventName` enumeration contains the names of all the available events in the Jan platform. + */ +var EventName; +(function (EventName) { + EventName["OnNewConversation"] = "onNewConversation"; + EventName["OnNewMessageRequest"] = "onNewMessageRequest"; + EventName["OnNewMessageResponse"] = "onNewMessageResponse"; + EventName["OnMessageResponseUpdate"] = "onMessageResponseUpdate"; + EventName["OnDownloadUpdate"] = "OnDownloadUpdate"; + EventName["OnDownloadSuccess"] = "OnDownloadSuccess"; + EventName["OnDownloadError"] = "OnDownloadError"; +})(EventName || (EventName = {})); +/** + * Adds an observer for an event. + * + * @param eventName The name of the event to observe. + * @param handler The handler function to call when the event is observed. + */ +const on = (eventName, handler) => { + var _a, _b; + (_b = (_a = window.corePlugin) === null || _a === void 0 ? void 0 : _a.events) === null || _b === void 0 ? void 0 : _b.on(eventName, handler); +}; +/** + * Removes an observer for an event. + * + * @param eventName The name of the event to stop observing. + * @param handler The handler function to call when the event is observed. + */ +const off = (eventName, handler) => { + var _a, _b; + (_b = (_a = window.corePlugin) === null || _a === void 0 ? void 0 : _a.events) === null || _b === void 0 ? void 0 : _b.off(eventName, handler); +}; +/** + * Emits an event. + * + * @param eventName The name of the event to emit. + * @param object The object to pass to the event callback. + */ +const emit = (eventName, object) => { + var _a, _b; + (_b = (_a = window.corePlugin) === null || _a === void 0 ? void 0 : _a.events) === null || _b === void 0 ? void 0 : _b.emit(eventName, object); }; +const events = { + on, + off, + emit, +}; + +;// CONCATENATED MODULE: ../../plugin-core/lib/preferences.js -;// CONCATENATED MODULE: ../../../../plugin-core/lib/index.js +/** + * Returns the value of the specified preference for the specified plugin. + * + * @param pluginName The name of the plugin. + * @param preferenceKey The key of the preference. + * @returns A promise that resolves to the value of the preference. + */ +function get(pluginName, preferenceKey) { + return store + .createCollection("preferences", {}) + .then(() => store.findOne("preferences", `${pluginName}.${preferenceKey}`)) + .then((doc) => { var _a; return (_a = doc === null || doc === void 0 ? void 0 : doc.value) !== null && _a !== void 0 ? _a : ""; }); +} +/** + * Sets the value of the specified preference for the specified plugin. + * + * @param pluginName The name of the plugin. + * @param preferenceKey The key of the preference. + * @param value The value of the preference. + * @returns A promise that resolves when the preference has been set. + */ +function set(pluginName, preferenceKey, value) { + return store + .createCollection("preferences", {}) + .then(() => store + .findOne("preferences", `${pluginName}.${preferenceKey}`) + .then((doc) => doc + ? store.updateOne("preferences", `${pluginName}.${preferenceKey}`, { value }) + : store.insertOne("preferences", { _id: `${pluginName}.${preferenceKey}`, value }))); +} +/** + * Clears all preferences for the specified plugin. + * + * @param pluginName The name of the plugin. + * @returns A promise that resolves when the preferences have been cleared. + */ +function clear(pluginName) { + return Promise.resolve(); +} +/** + * Registers a preference with the specified default value. + * + * @param register The function to use for registering the preference. + * @param pluginName The name of the plugin. + * @param preferenceKey The key of the preference. + * @param preferenceName The name of the preference. + * @param preferenceDescription The description of the preference. + * @param defaultValue The default value of the preference. + */ +function registerPreferences(register, pluginName, preferenceKey, preferenceName, preferenceDescription, defaultValue) { + register("PluginPreferences", `${pluginName}.${preferenceKey}`, () => ({ + pluginName, + preferenceKey, + preferenceName, + preferenceDescription, + defaultValue, + })); +} +/** + * An object that provides methods for getting, setting, and clearing preferences. + */ +const preferences = { + get, + set, + clear, + registerPreferences, +}; + +;// CONCATENATED MODULE: ../../plugin-core/lib/index.js /** * CoreService exports */ @@ -263,10 +390,6 @@ var DataService; */ var InferenceService; (function (InferenceService) { - /** - * The URL for the inference server. - */ - InferenceService["InferenceUrl"] = "inferenceUrl"; /** * Initializes a model for inference. */ @@ -357,6 +480,29 @@ var SystemMonitoringService; */ SystemMonitoringService["GetCurrentLoad"] = "getCurrentLoad"; })(SystemMonitoringService || (SystemMonitoringService = {})); +/** + * PluginService exports. + * @enum {string} + */ +var PluginService; +(function (PluginService) { + /** + * The plugin is being started. + */ + PluginService["OnStart"] = "pluginOnStart"; + /** + * The plugin is being started. + */ + PluginService["OnPreferencesUpdate"] = "pluginPreferencesUpdate"; + /** + * The plugin is being stopped. + */ + PluginService["OnStop"] = "pluginOnStop"; + /** + * The plugin is being destroyed. + */ + PluginService["OnDestroy"] = "pluginOnDestroy"; +})(PluginService || (PluginService = {})); /** * Store module exports. * @module @@ -367,13 +513,88 @@ var SystemMonitoringService; * @module */ +/** + * Events module exports. + * @module + */ + +/** + * Preferences module exports. + * @module + */ + ;// CONCATENATED MODULE: ./index.ts +var __awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; -const MODULE_PATH = "model-management-plugin/dist/module.js"; +const PluginName = "@janhq/model-management-plugin"; +const MODULE_PATH = "@janhq/model-management-plugin/dist/module.js"; const getDownloadedModels = () => core.invokePluginFunc(MODULE_PATH, "getDownloadedModels"); const getAvailableModels = () => core.invokePluginFunc(MODULE_PATH, "getAvailableModels"); -const downloadModel = (product) => core.downloadFile(product.downloadUrl, product.fileName); +const downloadModel = (product) => { + core.downloadFile(product.downloadUrl, product.fileName); + checkDownloadProgress(product.fileName); +}; +function checkDownloadProgress(fileName) { + return __awaiter(this, void 0, void 0, function* () { + if (typeof window !== "undefined" && typeof window.electronAPI === "undefined") { + const intervalId = setInterval(() => { + downloadProgress(fileName, intervalId); + }, 3000); + } + }); +} +function downloadProgress(fileName, intervalId) { + return __awaiter(this, void 0, void 0, function* () { + const response = yield fetch("/api/v1/downloadProgress", { + method: 'POST', + body: JSON.stringify({ fileName: fileName }), + headers: { 'Content-Type': 'application/json', 'Authorization': '' } + }); + if (!response.ok) { + events.emit(EventName.OnDownloadError, null); + clearInterval(intervalId); + } + else if (response.status >= 400) { + events.emit(EventName.OnDownloadError, null); + clearInterval(intervalId); + } + else { + const text = yield response.text(); + try { + const json = JSON.parse(text); + if (isEmptyObject(json)) { + if (!fileName) { + clearInterval(intervalId); + } + return; + } + if ((json === null || json === void 0 ? void 0 : json.success) === true) { + events.emit(EventName.OnDownloadSuccess, json); + clearInterval(intervalId); + } + else { + events.emit(EventName.OnDownloadUpdate, json); + } + } + catch (err) { + events.emit(EventName.OnDownloadError, null); + clearInterval(intervalId); + } + } + }); +} +function isEmptyObject(ojb) { + return Object.keys(ojb).length === 0; +} const deleteModel = (path) => core.deleteFile(path); const searchModels = (params) => core.invokePluginFunc(MODULE_PATH, "searchModels", params); const getConfiguredModels = () => core.invokePluginFunc(MODULE_PATH, "getConfiguredModels"); @@ -436,10 +657,11 @@ function getModelById(modelId) { } function onStart() { store.createCollection("models", {}); + checkDownloadProgress(null); } // Register all the above functions and objects with the relevant extension points function init({ register }) { - onStart(); + register(PluginService.OnStart, PluginName, onStart); register(ModelManagementService.GetDownloadedModels, getDownloadedModels.name, getDownloadedModels); register(ModelManagementService.GetAvailableModels, getAvailableModels.name, getAvailableModels); register(ModelManagementService.DownloadModel, downloadModel.name, downloadModel); diff --git a/web/public/plugins/monitoring-plugin/bundle.js b/web/public/plugins/monitoring-plugin/bundle.js index c815b83ee1..9e37299902 100644 --- a/web/public/plugins/monitoring-plugin/bundle.js +++ b/web/public/plugins/monitoring-plugin/bundle.js @@ -1 +1 @@ -var e={d:(o,n)=>{for(var t in n)e.o(n,t)&&!e.o(o,t)&&Object.defineProperty(o,t,{enumerable:!0,get:n[t]})},o:(e,o)=>Object.prototype.hasOwnProperty.call(e,o)},o={};e.d(o,{S:()=>c});const n=(e,o,...n)=>{var t,d,l;return null!==(d=null===(t=window.coreAPI)||void 0===t?void 0:t.invokePluginFunc(e,o,...n))&&void 0!==d?d:null===(l=window.electronAPI)||void 0===l?void 0:l.invokePluginFunc(e,o,...n)};var t,d,l,a,i,s;!function(e){e.CreateCollection="createCollection",e.DeleteCollection="deleteCollection",e.InsertOne="insertOne",e.UpdateOne="updateOne",e.UpdateMany="updateMany",e.DeleteOne="deleteOne",e.DeleteMany="deleteMany",e.FindMany="findMany",e.FindOne="findOne"}(t||(t={})),function(e){e.GetConversations="getConversations",e.CreateConversation="createConversation",e.UpdateConversation="updateConversation",e.DeleteConversation="deleteConversation",e.CreateMessage="createMessage",e.UpdateMessage="updateMessage",e.GetConversationMessages="getConversationMessages"}(d||(d={})),function(e){e.InferenceUrl="inferenceUrl",e.InitModel="initModel",e.StopModel="stopModel"}(l||(l={})),function(e){e.GetDownloadedModels="getDownloadedModels",e.GetAvailableModels="getAvailableModels",e.DeleteModel="deleteModel",e.DownloadModel="downloadModel",e.SearchModels="searchModels",e.GetConfiguredModels="getConfiguredModels",e.StoreModel="storeModel",e.UpdateFinishedDownloadAt="updateFinishedDownloadAt",e.GetUnfinishedDownloadModels="getUnfinishedDownloadModels",e.GetFinishedDownloadModels="getFinishedDownloadModels",e.DeleteDownloadModel="deleteDownloadModel",e.GetModelById="getModelById"}(a||(a={})),function(e){e.ExperimentComponent="experimentComponent"}(i||(i={})),function(e){e.GetResourcesInfo="getResourcesInfo",e.GetCurrentLoad="getCurrentLoad"}(s||(s={}));const r="monitoring-plugin/dist/module.js",M=()=>new Promise((e=>{n(r,"getResourcesInfo").then((o=>{e(o)}))})),u=()=>new Promise((e=>{n(r,"getCurrentLoad").then((o=>{e(o)}))}));function c({register:e}){e("getResourcesInfo","getResourcesInfo",M),e("getCurrentLoad","getCurrentLoad",u)}var g=o.S;export{g as init}; \ No newline at end of file +var e={d:(n,o)=>{for(var t in o)e.o(o,t)&&!e.o(n,t)&&Object.defineProperty(n,t,{enumerable:!0,get:o[t]})},o:(e,n)=>Object.prototype.hasOwnProperty.call(e,n)},n={};e.d(n,{S:()=>p});const o=(e,n,...o)=>{var t,d,s;return null!==(d=null===(t=window.coreAPI)||void 0===t?void 0:t.invokePluginFunc(e,n,...o))&&void 0!==d?d:null===(s=window.electronAPI)||void 0===s?void 0:s.invokePluginFunc(e,n,...o)};var t,d,s,a,l,r,i,u;!function(e){e.OnNewConversation="onNewConversation",e.OnNewMessageRequest="onNewMessageRequest",e.OnNewMessageResponse="onNewMessageResponse",e.OnMessageResponseUpdate="onMessageResponseUpdate",e.OnDownloadUpdate="OnDownloadUpdate",e.OnDownloadSuccess="OnDownloadSuccess",e.OnDownloadError="OnDownloadError"}(t||(t={})),function(e){e.CreateCollection="createCollection",e.DeleteCollection="deleteCollection",e.InsertOne="insertOne",e.UpdateOne="updateOne",e.UpdateMany="updateMany",e.DeleteOne="deleteOne",e.DeleteMany="deleteMany",e.FindMany="findMany",e.FindOne="findOne"}(d||(d={})),function(e){e.GetConversations="getConversations",e.CreateConversation="createConversation",e.UpdateConversation="updateConversation",e.DeleteConversation="deleteConversation",e.CreateMessage="createMessage",e.UpdateMessage="updateMessage",e.GetConversationMessages="getConversationMessages"}(s||(s={})),function(e){e.InitModel="initModel",e.StopModel="stopModel"}(a||(a={})),function(e){e.GetDownloadedModels="getDownloadedModels",e.GetAvailableModels="getAvailableModels",e.DeleteModel="deleteModel",e.DownloadModel="downloadModel",e.SearchModels="searchModels",e.GetConfiguredModels="getConfiguredModels",e.StoreModel="storeModel",e.UpdateFinishedDownloadAt="updateFinishedDownloadAt",e.GetUnfinishedDownloadModels="getUnfinishedDownloadModels",e.GetFinishedDownloadModels="getFinishedDownloadModels",e.DeleteDownloadModel="deleteDownloadModel",e.GetModelById="getModelById"}(l||(l={})),function(e){e.ExperimentComponent="experimentComponent"}(r||(r={})),function(e){e.GetResourcesInfo="getResourcesInfo",e.GetCurrentLoad="getCurrentLoad"}(i||(i={})),function(e){e.OnStart="pluginOnStart",e.OnPreferencesUpdate="pluginPreferencesUpdate",e.OnStop="pluginOnStop",e.OnDestroy="pluginOnDestroy"}(u||(u={}));const M="@janhq/monitoring-plugin/dist/module.js",g=()=>new Promise((e=>{o(M,"getResourcesInfo").then((n=>{e(n)}))})),c=()=>new Promise((e=>{o(M,"getCurrentLoad").then((n=>{e(n)}))}));function p({register:e}){e("getResourcesInfo","getResourcesInfo",g),e("getCurrentLoad","getCurrentLoad",c)}var w=n.S;export{w as init}; \ No newline at end of file diff --git a/plugins/plugin.json b/web/public/plugins/plugin.json similarity index 100% rename from plugins/plugin.json rename to web/public/plugins/plugin.json