From 3aeb6434b8d65f5540778ceff311c63d6683d933 Mon Sep 17 00:00:00 2001 From: hiento09 <136591877+hiento09@users.noreply.github.com> Date: Mon, 11 Mar 2024 13:02:54 +0700 Subject: [PATCH 01/12] codesign script force sign (#2291) Co-authored-by: Hien To --- .github/scripts/auto-sign.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/scripts/auto-sign.sh b/.github/scripts/auto-sign.sh index a2130e791..e7ea49d40 100755 --- a/.github/scripts/auto-sign.sh +++ b/.github/scripts/auto-sign.sh @@ -7,6 +7,6 @@ if [[ -z "$APP_PATH" ]] || [[ -z "$DEVELOPER_ID" ]]; then fi # If both variables are set, execute the following commands -find "$APP_PATH" \( -type f -perm +111 -o -name "*.node" \) -exec codesign -s "$DEVELOPER_ID" --options=runtime {} \; +find "$APP_PATH" \( -type f -perm +111 -o -name "*.node" \) -exec codesign --force -s "$DEVELOPER_ID" --options=runtime {} \; -find "$APP_PATH" -type f -name "*.o" -exec codesign -s "$DEVELOPER_ID" --options=runtime {} \; +find "$APP_PATH" -type f -name "*.o" -exec codesign --force -s "$DEVELOPER_ID" --options=runtime {} \; From 15064ac12539b9054847574420a070d4e7907d4a Mon Sep 17 00:00:00 2001 From: Service Account Date: Mon, 11 Mar 2024 06:17:51 +0000 Subject: [PATCH 02/12] janhq/jan: Update README.md with nightly build artifact URL --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 8a4c03098..dd9b05088 100644 --- a/README.md +++ b/README.md @@ -76,31 +76,31 @@ Jan is an open-source ChatGPT alternative that runs 100% offline on your compute Experimental (Nightly Build) - + jan.exe - + Intel - + M1/M2 - + jan.deb - + jan.AppImage From 1474a28dea28ca7df94a50a61f1640698eabf843 Mon Sep 17 00:00:00 2001 From: Service Account Date: Mon, 11 Mar 2024 06:35:11 +0000 Subject: [PATCH 03/12] Update README.md with Stable Download URLs --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index dd9b05088..43b43b3e2 100644 --- a/README.md +++ b/README.md @@ -43,31 +43,31 @@ Jan is an open-source ChatGPT alternative that runs 100% offline on your compute Stable (Recommended) - + jan.exe - + Intel - + M1/M2 - + jan.deb - + jan.AppImage From 0f14faf762a3e996718a2b4dfa73a1164de9be0b Mon Sep 17 00:00:00 2001 From: Arista Indrajaya Date: Mon, 11 Mar 2024 14:10:11 +0700 Subject: [PATCH 04/12] docs: fix the navbar style on darkmode version --- docs/src/css/custom.css | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/src/css/custom.css b/docs/src/css/custom.css index 4593f4f94..deab47c88 100644 --- a/docs/src/css/custom.css +++ b/docs/src/css/custom.css @@ -33,16 +33,24 @@ /* Dark mode styles based on Docusaurus dark theme */ [data-theme='dark'] .head_Menu div { + font-weight: bold; background-color: var(--ifm-background-color); color: var(--ifm-font-color-base); + margin-left: 0.7rem; + font-size: larger; } [data-theme='dark'] .head_Menu li { + font-weight: normal; background-color: var(--ifm-background-color); + margin-bottom: 5px; color: var(--ifm-font-color-base); } [data-theme='dark'] .head_SubMenu div { + font-weight: normal; background-color: var(--ifm-background-color); color: var(--ifm-font-color-base); + margin-left: 0rem; + font-size: medium; } From 1ce3f1158d48545e99477430fa45bb4b2682881e Mon Sep 17 00:00:00 2001 From: Service Account Date: Mon, 11 Mar 2024 09:44:33 +0000 Subject: [PATCH 05/12] janhq/jan: Update README.md with nightly build artifact URL --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 43b43b3e2..f847d63d2 100644 --- a/README.md +++ b/README.md @@ -76,31 +76,31 @@ Jan is an open-source ChatGPT alternative that runs 100% offline on your compute Experimental (Nightly Build) - + jan.exe - + Intel - + M1/M2 - + jan.deb - + jan.AppImage From 9876cf2156f1cbbadd0a227504d34927bf5153ed Mon Sep 17 00:00:00 2001 From: Arista Indrajaya Date: Mon, 11 Mar 2024 20:21:03 +0700 Subject: [PATCH 06/12] docs: redirect the install slug to /install --- docs/docusaurus.config.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js index 79d675c7a..43334c988 100644 --- a/docs/docusaurus.config.js +++ b/docs/docusaurus.config.js @@ -1,6 +1,5 @@ // @ts-check // Note: type annotations allow type checking and IDEs autocompletion - require("dotenv").config(); const darkCodeTheme = require("prism-react-renderer/themes/dracula"); @@ -105,6 +104,9 @@ const config = { { from: "/troubleshooting/undefined-issue/", to: "/guides/error-codes/undefined-issue/", + }, { + from: "/install/", + to: "/guides/install/", }, ], }, From 1fac400d70400dc7aea60491b259298b308f2f30 Mon Sep 17 00:00:00 2001 From: Louis Date: Mon, 11 Mar 2024 20:30:32 +0700 Subject: [PATCH 07/12] fix: replace robotjs by nutjs (#2295) (#2302) * fix: replace robotjs by nutjs (#2295) * fix: do not create quick ask window on test --- electron/main.ts | 24 +++-------------------- electron/package.json | 3 +-- electron/utils/selectedText.ts | 35 +++++++++++++++++++--------------- electron/utils/tray.ts | 24 +++++++++++++++++++++++ 4 files changed, 48 insertions(+), 38 deletions(-) create mode 100644 electron/utils/tray.ts diff --git a/electron/main.ts b/electron/main.ts index 21f95cd00..8fe4247d6 100644 --- a/electron/main.ts +++ b/electron/main.ts @@ -27,6 +27,7 @@ import { setupReactDevTool } from './utils/dev' import { cleanLogs } from './utils/log' import { registerShortcut } from './utils/selectedText' +import { createSystemTray } from './utils/tray' const preloadPath = join(__dirname, 'preload.js') const rendererPath = join(__dirname, '..', 'renderer') @@ -48,33 +49,14 @@ app .then(setupMenu) .then(handleIPCs) .then(handleAppUpdates) - .then(createQuickAskWindow) + .then(() => process.env.CI !== 'e2e' && createQuickAskWindow()) .then(createMainWindow) .then(() => { if (!app.isPackaged) { windowManager.mainWindow?.webContents.openDevTools() } }) - .then(() => { - const iconPath = join(app.getAppPath(), 'icons', 'icon-tray.png') - const tray = new Tray(iconPath) - tray.setToolTip(app.getName()) - - const contextMenu = Menu.buildFromTemplate([ - { - label: 'Open Jan', - type: 'normal', - click: () => windowManager.showMainWindow(), - }, - { - label: 'Open Quick Ask', - type: 'normal', - click: () => windowManager.showQuickAskWindow(), - }, - { label: 'Quit', type: 'normal', click: () => app.quit() }, - ]) - tray.setContextMenu(contextMenu) - }) + .then(() => process.env.CI !== 'e2e' && createSystemTray()) .then(() => { log(`Version: ${app.getVersion()}`) }) diff --git a/electron/package.json b/electron/package.json index 93c30682c..e09e0daf2 100644 --- a/electron/package.json +++ b/electron/package.json @@ -41,7 +41,6 @@ "notarize": { "teamId": "F8AH6NHVY5" }, - "icon": "icons/icon.png" }, "linux": { @@ -92,7 +91,7 @@ "request": "^2.88.2", "request-progress": "^3.0.0", "ulid": "^2.3.0", - "@hurdlegroup/robotjs": "^0.11.4" + "@nut-tree/nut-js": "^4.0.0" }, "devDependencies": { "@electron/notarize": "^2.1.0", diff --git a/electron/utils/selectedText.ts b/electron/utils/selectedText.ts index 6b2349725..a39e331a9 100644 --- a/electron/utils/selectedText.ts +++ b/electron/utils/selectedText.ts @@ -1,19 +1,24 @@ -import { clipboard, globalShortcut } from "electron"; -import { keyTap, keys } from "@hurdlegroup/robotjs"; +import { clipboard, globalShortcut } from 'electron' +import { keyboard, Key } from '@nut-tree/nut-js' /** * Gets selected text by synthesizing the keyboard shortcut * "CommandOrControl+c" then reading text from the clipboard */ export const getSelectedText = async () => { - const currentClipboardContent = clipboard.readText(); // preserve clipboard content - clipboard.clear(); - keyTap("c" as keys, process.platform === "darwin" ? "command" : "control"); - await new Promise((resolve) => setTimeout(resolve, 200)); // add a delay before checking clipboard - const selectedText = clipboard.readText(); - clipboard.writeText(currentClipboardContent); - return selectedText; -}; + const currentClipboardContent = clipboard.readText() // preserve clipboard content + clipboard.clear() + const hotkeys: Key[] = [ + process.platform === 'darwin' ? Key.LeftCmd : Key.LeftControl, + Key.C, + ] + await keyboard.pressKey(...hotkeys) + await keyboard.releaseKey(...hotkeys) + await new Promise((resolve) => setTimeout(resolve, 200)) // add a delay before checking clipboard + const selectedText = clipboard.readText() + clipboard.writeText(currentClipboardContent) + return selectedText +} /** * Registers a global shortcut of `accelerator`. The `callback` is called @@ -26,14 +31,14 @@ export const registerShortcut = ( callback: (selectedText: string) => void ) => { return globalShortcut.register(accelerator, async () => { - callback(await getSelectedText()); - }); -}; + callback(await getSelectedText()) + }) +} /** * Unregisters a global shortcut of `accelerator` and * is equivalent to electron.globalShortcut.unregister */ export const unregisterShortcut = (accelerator: Electron.Accelerator) => { - globalShortcut.unregister(accelerator); -}; \ No newline at end of file + globalShortcut.unregister(accelerator) +} diff --git a/electron/utils/tray.ts b/electron/utils/tray.ts new file mode 100644 index 000000000..2ab3e6dcc --- /dev/null +++ b/electron/utils/tray.ts @@ -0,0 +1,24 @@ +import { join } from 'path' +import { Tray, app, Menu } from 'electron' +import { windowManager } from '../managers/window' + +export const createSystemTray = () => { + const iconPath = join(app.getAppPath(), 'icons', 'icon-tray.png') + const tray = new Tray(iconPath) + tray.setToolTip(app.getName()) + + const contextMenu = Menu.buildFromTemplate([ + { + label: 'Open Jan', + type: 'normal', + click: () => windowManager.showMainWindow(), + }, + { + label: 'Open Quick Ask', + type: 'normal', + click: () => windowManager.showQuickAskWindow(), + }, + { label: 'Quit', type: 'normal', click: () => app.quit() }, + ]) + tray.setContextMenu(contextMenu) +} From 86af902d19e0b91068a401002fe9103b08809626 Mon Sep 17 00:00:00 2001 From: NamH Date: Mon, 11 Mar 2024 21:24:31 +0700 Subject: [PATCH 08/12] fix: message from quick ask not get the selected model (#2307) Signed-off-by: James Co-authored-by: James --- web/hooks/useSendChatMessage.ts | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/web/hooks/useSendChatMessage.ts b/web/hooks/useSendChatMessage.ts index 9e88e763a..11a57a598 100644 --- a/web/hooks/useSendChatMessage.ts +++ b/web/hooks/useSendChatMessage.ts @@ -79,6 +79,8 @@ export default function useSendChatMessage() { const setIsGeneratingResponse = useSetAtom(isGeneratingResponseAtom) const activeThreadRef = useRef() + const selectedModelRef = useRef() + useEffect(() => { modelRef.current = activeModel }, [activeModel]) @@ -91,6 +93,10 @@ export default function useSendChatMessage() { activeThreadRef.current = activeThread }, [activeThread]) + useEffect(() => { + selectedModelRef.current = selectedModel + }, [selectedModel]) + const resendChatMessage = async (currentMessage: ThreadMessage) => { if (!activeThreadRef.current) { console.error('No active thread') @@ -128,11 +134,13 @@ export default function useSendChatMessage() { type: MessageRequestType.Thread, messages: messages, threadId: activeThreadRef.current.id, - model: activeThreadRef.current.assistants[0].model ?? selectedModel, + model: + activeThreadRef.current.assistants[0].model ?? selectedModelRef.current, } const modelId = - selectedModel?.id ?? activeThreadRef.current.assistants[0].model.id + selectedModelRef.current?.id ?? + activeThreadRef.current.assistants[0].model.id if (modelRef.current?.id !== modelId) { setQueuedMessage(true) @@ -213,7 +221,7 @@ export default function useSendChatMessage() { { role: ChatCompletionRole.User, content: - selectedModel && base64Blob + selectedModelRef.current && base64Blob ? [ { type: ChatCompletionMessageContentType.Text, @@ -242,7 +250,7 @@ export default function useSendChatMessage() { ) let modelRequest = - selectedModel ?? activeThreadRef.current.assistants[0].model + selectedModelRef?.current ?? activeThreadRef.current.assistants[0].model if (runtimeParams.stream == null) { runtimeParams.stream = true } @@ -344,7 +352,8 @@ export default function useSendChatMessage() { ?.addNewMessage(threadMessage) const modelId = - selectedModel?.id ?? activeThreadRef.current.assistants[0].model.id + selectedModelRef.current?.id ?? + activeThreadRef.current.assistants[0].model.id if (modelRef.current?.id !== modelId) { setQueuedMessage(true) From c8ea16e661bc4ae74e50e4b1bbd01a9e7961b06f Mon Sep 17 00:00:00 2001 From: Louis Date: Mon, 11 Mar 2024 22:58:18 +0700 Subject: [PATCH 09/12] fix: quick ask blocks app update (#2310) --- electron/handlers/update.ts | 2 ++ electron/main.ts | 31 +++++++++++++++++++++--------- electron/managers/tray.ts | 38 +++++++++++++++++++++++++++++++++++++ electron/utils/tray.ts | 24 ----------------------- 4 files changed, 62 insertions(+), 33 deletions(-) create mode 100644 electron/managers/tray.ts delete mode 100644 electron/utils/tray.ts diff --git a/electron/handlers/update.ts b/electron/handlers/update.ts index 3f52c401e..5ea261e54 100644 --- a/electron/handlers/update.ts +++ b/electron/handlers/update.ts @@ -7,6 +7,7 @@ import { autoUpdater, } from 'electron-updater' import { AppEvent } from '@janhq/core' +import { trayManager } from '../managers/tray' export let waitingToInstallVersion: string | undefined = undefined @@ -22,6 +23,7 @@ export function handleAppUpdates() { message: 'Would you like to download and install it now?', buttons: ['Download', 'Later'], }) + trayManager.destroyCurrentTray() if (action.response === 0) await autoUpdater.downloadUpdate() }) diff --git a/electron/main.ts b/electron/main.ts index 8fe4247d6..e72c7f95a 100644 --- a/electron/main.ts +++ b/electron/main.ts @@ -1,4 +1,4 @@ -import { app, BrowserWindow, Menu, Tray } from 'electron' +import { app, BrowserWindow, Tray } from 'electron' import { join } from 'path' /** @@ -27,7 +27,7 @@ import { setupReactDevTool } from './utils/dev' import { cleanLogs } from './utils/log' import { registerShortcut } from './utils/selectedText' -import { createSystemTray } from './utils/tray' +import { trayManager } from './managers/tray' const preloadPath = join(__dirname, 'preload.js') const rendererPath = join(__dirname, '..', 'renderer') @@ -39,6 +39,8 @@ const quickAskUrl = `${mainUrl}/search` const quickAskHotKey = 'CommandOrControl+J' +const gotTheLock = app.requestSingleInstanceLock() + app .whenReady() .then(setupReactDevTool) @@ -56,11 +58,23 @@ app windowManager.mainWindow?.webContents.openDevTools() } }) - .then(() => process.env.CI !== 'e2e' && createSystemTray()) + .then(() => process.env.CI !== 'e2e' && trayManager.createSystemTray()) .then(() => { log(`Version: ${app.getVersion()}`) }) .then(() => { + if (!gotTheLock) { + app.quit() + } else { + app.on('second-instance', (_event, _commandLine, _workingDirectory) => { + // Someone tried to run a second instance, we should focus our window. + if (windowManager.mainWindow) { + if (windowManager.mainWindow.isMinimized()) + windowManager.mainWindow.restore() + windowManager.mainWindow.focus() + } + }) + } app.on('activate', () => { if (!BrowserWindow.getAllWindows().length) { createMainWindow() @@ -73,6 +87,10 @@ app.on('ready', () => { registerGlobalShortcuts() }) +app.on('before-quit', function (evt) { + trayManager.destroyCurrentTray() +}) + app.once('quit', () => { cleanUpAndQuit() }) @@ -89,12 +107,7 @@ function createMainWindow() { function registerGlobalShortcuts() { const ret = registerShortcut(quickAskHotKey, (selectedText: string) => { - if (!windowManager.isQuickAskWindowVisible()) { - windowManager.showQuickAskWindow() - windowManager.sendQuickAskSelectedText(selectedText) - } else { - windowManager.hideQuickAskWindow() - } + windowManager.showMainWindow() }) if (!ret) { diff --git a/electron/managers/tray.ts b/electron/managers/tray.ts new file mode 100644 index 000000000..18661e58e --- /dev/null +++ b/electron/managers/tray.ts @@ -0,0 +1,38 @@ +import { join } from 'path' +import { Tray, app, Menu } from 'electron' +import { windowManager } from '../managers/window' + +class TrayManager { + currentTray: Tray | undefined + + createSystemTray = () => { + if (this.currentTray) { + return + } + const iconPath = join(app.getAppPath(), 'icons', 'icon-tray.png') + const tray = new Tray(iconPath) + tray.setToolTip(app.getName()) + + const contextMenu = Menu.buildFromTemplate([ + { + label: 'Open Jan', + type: 'normal', + click: () => windowManager.showMainWindow(), + }, + { + label: 'Open Quick Ask', + type: 'normal', + click: () => windowManager.showQuickAskWindow(), + }, + { label: 'Quit', type: 'normal', click: () => app.quit() }, + ]) + tray.setContextMenu(contextMenu) + } + + destroyCurrentTray() { + this.currentTray?.destroy() + this.currentTray = undefined + } +} + +export const trayManager = new TrayManager() diff --git a/electron/utils/tray.ts b/electron/utils/tray.ts deleted file mode 100644 index 2ab3e6dcc..000000000 --- a/electron/utils/tray.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { join } from 'path' -import { Tray, app, Menu } from 'electron' -import { windowManager } from '../managers/window' - -export const createSystemTray = () => { - const iconPath = join(app.getAppPath(), 'icons', 'icon-tray.png') - const tray = new Tray(iconPath) - tray.setToolTip(app.getName()) - - const contextMenu = Menu.buildFromTemplate([ - { - label: 'Open Jan', - type: 'normal', - click: () => windowManager.showMainWindow(), - }, - { - label: 'Open Quick Ask', - type: 'normal', - click: () => windowManager.showQuickAskWindow(), - }, - { label: 'Quit', type: 'normal', click: () => app.quit() }, - ]) - tray.setContextMenu(contextMenu) -} From bbfc686c33334e0b619ed07f80084293aed3aa4a Mon Sep 17 00:00:00 2001 From: Louis Date: Mon, 11 Mar 2024 23:29:39 +0700 Subject: [PATCH 10/12] fix: quick ask not show (#2315) * fix: quick ask not show * fix: window resize does not work on windows 11 --- electron/main.ts | 13 +++++++------ electron/managers/window.ts | 1 + 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/electron/main.ts b/electron/main.ts index e72c7f95a..78577ac68 100644 --- a/electron/main.ts +++ b/electron/main.ts @@ -68,11 +68,7 @@ app } else { app.on('second-instance', (_event, _commandLine, _workingDirectory) => { // Someone tried to run a second instance, we should focus our window. - if (windowManager.mainWindow) { - if (windowManager.mainWindow.isMinimized()) - windowManager.mainWindow.restore() - windowManager.mainWindow.focus() - } + windowManager.showMainWindow() }) } app.on('activate', () => { @@ -107,7 +103,12 @@ function createMainWindow() { function registerGlobalShortcuts() { const ret = registerShortcut(quickAskHotKey, (selectedText: string) => { - windowManager.showMainWindow() + if (!windowManager.isQuickAskWindowVisible()) { + windowManager.showQuickAskWindow() + windowManager.sendQuickAskSelectedText(selectedText) + } else { + windowManager.hideQuickAskWindow() + } }) if (!ret) { diff --git a/electron/managers/window.ts b/electron/managers/window.ts index 796a5d54a..eed80c37c 100644 --- a/electron/managers/window.ts +++ b/electron/managers/window.ts @@ -101,6 +101,7 @@ class WindowManager { expandQuickAskWindow(heightOffset: number): void { const width = quickAskWindowConfig.width! const height = quickAskWindowConfig.height! + heightOffset + this._quickAskWindow?.setMinimumSize(width, height) this._quickAskWindow?.setSize(width, height, true) } From 6f899eb1186860a07bf8880a112473cbc40eb760 Mon Sep 17 00:00:00 2001 From: Service Account Date: Mon, 11 Mar 2024 17:43:46 +0000 Subject: [PATCH 11/12] janhq/jan: Update README.md with nightly build artifact URL --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index f847d63d2..ef9516b81 100644 --- a/README.md +++ b/README.md @@ -76,31 +76,31 @@ Jan is an open-source ChatGPT alternative that runs 100% offline on your compute Experimental (Nightly Build) - + jan.exe - + Intel - + M1/M2 - + jan.deb - + jan.AppImage From de433bbe6e76c97c5aa98ecc533b253ce2f6bb5e Mon Sep 17 00:00:00 2001 From: Service Account Date: Mon, 11 Mar 2024 20:20:46 +0000 Subject: [PATCH 12/12] janhq/jan: Update README.md with nightly build artifact URL --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index ef9516b81..496bbd434 100644 --- a/README.md +++ b/README.md @@ -76,31 +76,31 @@ Jan is an open-source ChatGPT alternative that runs 100% offline on your compute Experimental (Nightly Build) - + jan.exe - + Intel - + M1/M2 - + jan.deb - + jan.AppImage