[desktop] Various improvements (#1407)
- Restore macOS icon - Remove unnecessary require - Spruce dependencies docs - Use standard import for jpeg-js - Rearrange files - Import onnxruntime with TypeScript types
This commit is contained in:
commit
549ad77ac6
33 changed files with 107 additions and 92 deletions
BIN
desktop/build/icon.icns
Normal file
BIN
desktop/build/icon.icns
Normal file
Binary file not shown.
|
@ -1,5 +1,9 @@
|
|||
# Dependencies
|
||||
|
||||
* [Electron](#electron)
|
||||
* [Dev dependencies](#dev)
|
||||
* [Functionality](#functionality)
|
||||
|
||||
## Electron
|
||||
|
||||
[Electron](https://www.electronjs.org) is a cross-platform (Linux, Windows,
|
||||
|
@ -73,7 +77,7 @@ Electron process. This allows us to directly use the output produced by
|
|||
|
||||
## Dev
|
||||
|
||||
See [web/docs/dependencies#DX](../../web/docs/dependencies.md#dev) for the
|
||||
See [web/docs/dependencies#dev](../../web/docs/dependencies.md#dev) for the
|
||||
general development experience related dependencies like TypeScript etc, which
|
||||
are similar to that in the web code.
|
||||
|
||||
|
@ -88,7 +92,7 @@ Some extra ones specific to the code here are:
|
|||
|
||||
## Functionality
|
||||
|
||||
### Conversion
|
||||
### Format conversion
|
||||
|
||||
The main tool we use is for arbitrary conversions is FFMPEG. To bundle a
|
||||
(platform specific) static binary of ffmpeg with our app, we use
|
||||
|
@ -104,20 +108,23 @@ resources (`build`) folder. This is used for thumbnail generation on Linux.
|
|||
On macOS, we use the `sips` CLI tool for conversion, but that is already
|
||||
available on the host machine, and is not bundled with our app.
|
||||
|
||||
### AI/ML
|
||||
|
||||
[onnxruntime-node](https://github.com/Microsoft/onnxruntime) is used as the
|
||||
AI/ML runtime. It powers both natural language searches (using CLIP) and face
|
||||
detection (using YOLO).
|
||||
|
||||
[jpeg-js](https://github.com/jpeg-js/jpeg-js#readme) is used for decoding
|
||||
JPEG data into raw RGB bytes before passing it to ONNX.
|
||||
|
||||
html-entities is used by the bundled clip-bpe-ts tokenizer for CLIP.
|
||||
|
||||
### Watch Folders
|
||||
|
||||
[chokidar](https://github.com/paulmillr/chokidar) is used as a file system
|
||||
watcher for the watch folders functionality.
|
||||
|
||||
### AI/ML
|
||||
|
||||
- [onnxruntime-node](https://github.com/Microsoft/onnxruntime) is used for
|
||||
natural language searches based on CLIP.
|
||||
- html-entities is used by the bundled clip-bpe-ts tokenizer.
|
||||
- [jpeg-js](https://github.com/jpeg-js/jpeg-js#readme) is used for decoding
|
||||
JPEG data into raw RGB bytes before passing it to ONNX.
|
||||
|
||||
## ZIP
|
||||
### ZIP
|
||||
|
||||
[node-stream-zip](https://github.com/antelle/node-stream-zip) is used for
|
||||
reading of large ZIP files (e.g. during imports of Google Takeout ZIPs).
|
||||
|
|
|
@ -26,9 +26,9 @@ import {
|
|||
import { attachFSWatchIPCHandlers, attachIPCHandlers } from "./main/ipc";
|
||||
import log, { initLogging } from "./main/log";
|
||||
import { createApplicationMenu } from "./main/menu";
|
||||
import { setupAutoUpdater } from "./main/services/app-update";
|
||||
import { initWatcher } from "./main/services/chokidar";
|
||||
import { isDev } from "./main/util";
|
||||
import { setupAutoUpdater } from "./services/app-update";
|
||||
import { initWatcher } from "./services/chokidar";
|
||||
|
||||
let appIsQuitting = false;
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { dialog } from "electron/main";
|
||||
import path from "node:path";
|
||||
import { getDirFilePaths, getElectronFile } from "../services/fs";
|
||||
import { getElectronFilesFromGoogleZip } from "../services/upload";
|
||||
import type { ElectronFile } from "../types/ipc";
|
||||
import { getDirFilePaths, getElectronFile } from "./services/fs";
|
||||
import { getElectronFilesFromGoogleZip } from "./services/upload";
|
||||
|
||||
export const selectDirectory = async () => {
|
||||
const result = await dialog.showOpenDialog({
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import { app, BrowserWindow, nativeImage, Tray } from "electron";
|
||||
import { BrowserWindow, Tray, app, nativeImage, shell } from "electron";
|
||||
import { existsSync } from "node:fs";
|
||||
import path from "node:path";
|
||||
import { isAppQuitting, rendererURL } from "../main";
|
||||
import autoLauncher from "../services/autoLauncher";
|
||||
import { getHideDockIconPreference } from "../services/userPreference";
|
||||
import { isPlatform } from "../utils/common/platform";
|
||||
import log from "./log";
|
||||
import { createTrayContextMenu } from "./menu";
|
||||
import { isPlatform } from "./platform";
|
||||
import autoLauncher from "./services/autoLauncher";
|
||||
import { getHideDockIconPreference } from "./services/userPreference";
|
||||
import { isDev } from "./util";
|
||||
|
||||
/**
|
||||
|
@ -109,7 +109,7 @@ export function handleDownloads(mainWindow: BrowserWindow) {
|
|||
export function handleExternalLinks(mainWindow: BrowserWindow) {
|
||||
mainWindow.webContents.setWindowOpenHandler(({ url }) => {
|
||||
if (!url.startsWith(rendererURL)) {
|
||||
require("electron").shell.openExternal(url);
|
||||
shell.openExternal(url);
|
||||
return { action: "deny" };
|
||||
} else {
|
||||
return { action: "allow" };
|
||||
|
|
|
@ -10,37 +10,6 @@
|
|||
|
||||
import type { FSWatcher } from "chokidar";
|
||||
import { ipcMain } from "electron/main";
|
||||
import {
|
||||
appVersion,
|
||||
skipAppUpdate,
|
||||
updateAndRestart,
|
||||
updateOnNextRestart,
|
||||
} from "../services/app-update";
|
||||
import { clipImageEmbedding, clipTextEmbedding } from "../services/clip";
|
||||
import { runFFmpegCmd } from "../services/ffmpeg";
|
||||
import { getDirFiles } from "../services/fs";
|
||||
import {
|
||||
convertToJPEG,
|
||||
generateImageThumbnail,
|
||||
} from "../services/imageProcessor";
|
||||
import {
|
||||
clearStores,
|
||||
encryptionKey,
|
||||
saveEncryptionKey,
|
||||
} from "../services/store";
|
||||
import {
|
||||
getElectronFilesFromGoogleZip,
|
||||
getPendingUploads,
|
||||
setToUploadCollection,
|
||||
setToUploadFiles,
|
||||
} from "../services/upload";
|
||||
import {
|
||||
addWatchMapping,
|
||||
getWatchMappings,
|
||||
removeWatchMapping,
|
||||
updateWatchMappingIgnoredFiles,
|
||||
updateWatchMappingSyncedFiles,
|
||||
} from "../services/watch";
|
||||
import type { ElectronFile, FILE_PATH_TYPE, WatchMapping } from "../types/ipc";
|
||||
import {
|
||||
selectDirectory,
|
||||
|
@ -61,6 +30,37 @@ import {
|
|||
saveStreamToDisk,
|
||||
} from "./fs";
|
||||
import { logToDisk } from "./log";
|
||||
import {
|
||||
appVersion,
|
||||
skipAppUpdate,
|
||||
updateAndRestart,
|
||||
updateOnNextRestart,
|
||||
} from "./services/app-update";
|
||||
import { clipImageEmbedding, clipTextEmbedding } from "./services/clip";
|
||||
import { runFFmpegCmd } from "./services/ffmpeg";
|
||||
import { getDirFiles } from "./services/fs";
|
||||
import {
|
||||
convertToJPEG,
|
||||
generateImageThumbnail,
|
||||
} from "./services/imageProcessor";
|
||||
import {
|
||||
clearStores,
|
||||
encryptionKey,
|
||||
saveEncryptionKey,
|
||||
} from "./services/store";
|
||||
import {
|
||||
getElectronFilesFromGoogleZip,
|
||||
getPendingUploads,
|
||||
setToUploadCollection,
|
||||
setToUploadFiles,
|
||||
} from "./services/upload";
|
||||
import {
|
||||
addWatchMapping,
|
||||
getWatchMappings,
|
||||
removeWatchMapping,
|
||||
updateWatchMappingIgnoredFiles,
|
||||
updateWatchMappingSyncedFiles,
|
||||
} from "./services/watch";
|
||||
import { openDirectory, openLogDirectory } from "./util";
|
||||
|
||||
/**
|
||||
|
|
|
@ -6,12 +6,12 @@ import {
|
|||
shell,
|
||||
} from "electron";
|
||||
import { setIsAppQuitting } from "../main";
|
||||
import { forceCheckForAppUpdates } from "../services/app-update";
|
||||
import autoLauncher from "../services/autoLauncher";
|
||||
import { forceCheckForAppUpdates } from "./services/app-update";
|
||||
import autoLauncher from "./services/autoLauncher";
|
||||
import {
|
||||
getHideDockIconPreference,
|
||||
setHideDockIconPreference,
|
||||
} from "../services/userPreference";
|
||||
} from "./services/userPreference";
|
||||
import { openLogDirectory } from "./util";
|
||||
|
||||
/** Create and return the entries in the app's main menu bar */
|
||||
|
|
|
@ -2,10 +2,10 @@ import { compareVersions } from "compare-versions";
|
|||
import { app, BrowserWindow } from "electron";
|
||||
import { default as electronLog } from "electron-log";
|
||||
import { autoUpdater } from "electron-updater";
|
||||
import { setIsAppQuitting, setIsUpdateAvailable } from "../main";
|
||||
import log from "../main/log";
|
||||
import { setIsAppQuitting, setIsUpdateAvailable } from "../../main";
|
||||
import { AppUpdateInfo } from "../../types/ipc";
|
||||
import log from "../log";
|
||||
import { userPreferencesStore } from "../stores/user-preferences";
|
||||
import { AppUpdateInfo } from "../types/ipc";
|
||||
|
||||
export const setupAutoUpdater = (mainWindow: BrowserWindow) => {
|
||||
autoUpdater.logger = electronLog;
|
|
@ -1,5 +1,5 @@
|
|||
import { AutoLauncherClient } from "../types/main";
|
||||
import { isPlatform } from "../utils/common/platform";
|
||||
import { AutoLauncherClient } from "../../types/main";
|
||||
import { isPlatform } from "../platform";
|
||||
import linuxAndWinAutoLauncher from "./autoLauncherClients/linuxAndWinAutoLauncher";
|
||||
import macAutoLauncher from "./autoLauncherClients/macAutoLauncher";
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import AutoLaunch from "auto-launch";
|
||||
import { app } from "electron";
|
||||
import { AutoLauncherClient } from "../../types/main";
|
||||
import { AutoLauncherClient } from "../../../types/main";
|
||||
|
||||
const LAUNCHED_AS_HIDDEN_FLAG = "hidden";
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import { app } from "electron";
|
||||
import { AutoLauncherClient } from "../../types/main";
|
||||
import { AutoLauncherClient } from "../../../types/main";
|
||||
|
||||
class MacAutoLauncher implements AutoLauncherClient {
|
||||
async isEnabled() {
|
|
@ -1,9 +1,9 @@
|
|||
import chokidar from "chokidar";
|
||||
import { BrowserWindow } from "electron";
|
||||
import path from "path";
|
||||
import log from "../main/log";
|
||||
import { getWatchMappings } from "../services/watch";
|
||||
import log from "../log";
|
||||
import { getElectronFile } from "./fs";
|
||||
import { getWatchMappings } from "./watch";
|
||||
|
||||
/**
|
||||
* Convert a file system {@link filePath} that uses the local system specific
|
|
@ -11,16 +11,16 @@
|
|||
*/
|
||||
import { app, net } from "electron/main";
|
||||
import { existsSync } from "fs";
|
||||
import jpeg from "jpeg-js";
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { writeStream } from "../main/fs";
|
||||
import log from "../main/log";
|
||||
import { CustomErrors } from "../types/ipc";
|
||||
import Tokenizer from "../utils/clip-bpe-ts/mod";
|
||||
import { generateTempFilePath } from "../utils/temp";
|
||||
import * as ort from "onnxruntime-node";
|
||||
import Tokenizer from "../../thirdparty/clip-bpe-ts/mod";
|
||||
import { CustomErrors } from "../../types/ipc";
|
||||
import { writeStream } from "../fs";
|
||||
import log from "../log";
|
||||
import { generateTempFilePath } from "../temp";
|
||||
import { deleteTempFile } from "./ffmpeg";
|
||||
const jpeg = require("jpeg-js");
|
||||
const ort = require("onnxruntime-node");
|
||||
|
||||
const textModelName = "clip-text-vit-32-uint8.onnx";
|
||||
const textModelByteSize = 64173509; // 61.2 MB
|
|
@ -1,11 +1,11 @@
|
|||
import pathToFfmpeg from "ffmpeg-static";
|
||||
import { existsSync } from "node:fs";
|
||||
import fs from "node:fs/promises";
|
||||
import { writeStream } from "../main/fs";
|
||||
import log from "../main/log";
|
||||
import { execAsync } from "../main/util";
|
||||
import { ElectronFile } from "../types/ipc";
|
||||
import { generateTempFilePath, getTempDirPath } from "../utils/temp";
|
||||
import { ElectronFile } from "../../types/ipc";
|
||||
import { writeStream } from "../fs";
|
||||
import log from "../log";
|
||||
import { generateTempFilePath, getTempDirPath } from "../temp";
|
||||
import { execAsync } from "../util";
|
||||
|
||||
const INPUT_PATH_PLACEHOLDER = "INPUT";
|
||||
const FFMPEG_PLACEHOLDER = "FFMPEG";
|
|
@ -2,8 +2,8 @@ import StreamZip from "node-stream-zip";
|
|||
import { existsSync } from "node:fs";
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import log from "../main/log";
|
||||
import { ElectronFile } from "../types/ipc";
|
||||
import { ElectronFile } from "../../types/ipc";
|
||||
import log from "../log";
|
||||
|
||||
const FILE_STREAM_CHUNK_SIZE: number = 4 * 1024 * 1024;
|
||||
|
|
@ -1,12 +1,12 @@
|
|||
import { existsSync } from "fs";
|
||||
import fs from "node:fs/promises";
|
||||
import path from "path";
|
||||
import { writeStream } from "../main/fs";
|
||||
import log from "../main/log";
|
||||
import { execAsync, isDev } from "../main/util";
|
||||
import { CustomErrors, ElectronFile } from "../types/ipc";
|
||||
import { isPlatform } from "../utils/common/platform";
|
||||
import { generateTempFilePath } from "../utils/temp";
|
||||
import { CustomErrors, ElectronFile } from "../../types/ipc";
|
||||
import { writeStream } from "../fs";
|
||||
import log from "../log";
|
||||
import { isPlatform } from "../platform";
|
||||
import { generateTempFilePath } from "../temp";
|
||||
import { execAsync, isDev } from "../util";
|
||||
import { deleteTempFile } from "./ffmpeg";
|
||||
|
||||
const IMAGE_MAGICK_PLACEHOLDER = "IMAGE_MAGICK";
|
|
@ -1,10 +1,9 @@
|
|||
import StreamZip from "node-stream-zip";
|
||||
import path from "path";
|
||||
import { getElectronFile } from "../services/fs";
|
||||
import { ElectronFile, FILE_PATH_TYPE } from "../../types/ipc";
|
||||
import { FILE_PATH_KEYS } from "../../types/main";
|
||||
import { uploadStatusStore } from "../stores/upload.store";
|
||||
import { ElectronFile, FILE_PATH_TYPE } from "../types/ipc";
|
||||
import { FILE_PATH_KEYS } from "../types/main";
|
||||
import { getValidPaths, getZipFileStream } from "./fs";
|
||||
import { getElectronFile, getValidPaths, getZipFileStream } from "./fs";
|
||||
|
||||
export const getPendingUploads = async () => {
|
||||
const filePaths = getSavedFilePaths(FILE_PATH_TYPE.FILES);
|
|
@ -1,7 +1,7 @@
|
|||
import type { FSWatcher } from "chokidar";
|
||||
import ElectronLog from "electron-log";
|
||||
import { WatchMapping, WatchStoreType } from "../../types/ipc";
|
||||
import { watchStore } from "../stores/watch.store";
|
||||
import { WatchMapping, WatchStoreType } from "../types/ipc";
|
||||
|
||||
export const addWatchMapping = async (
|
||||
watcher: FSWatcher,
|
|
@ -1,5 +1,5 @@
|
|||
import Store, { Schema } from "electron-store";
|
||||
import type { KeysStoreType } from "../types/main";
|
||||
import type { KeysStoreType } from "../../types/main";
|
||||
|
||||
const keysStoreSchema: Schema<KeysStoreType> = {
|
||||
AnonymizeUserID: {
|
|
@ -1,5 +1,5 @@
|
|||
import Store, { Schema } from "electron-store";
|
||||
import type { SafeStorageStoreType } from "../types/main";
|
||||
import type { SafeStorageStoreType } from "../../types/main";
|
||||
|
||||
const safeStorageSchema: Schema<SafeStorageStoreType> = {
|
||||
encryptionKey: {
|
|
@ -1,5 +1,5 @@
|
|||
import Store, { Schema } from "electron-store";
|
||||
import type { UploadStoreType } from "../types/main";
|
||||
import type { UploadStoreType } from "../../types/main";
|
||||
|
||||
const uploadStoreSchema: Schema<UploadStoreType> = {
|
||||
filePaths: {
|
|
@ -1,5 +1,5 @@
|
|||
import Store, { Schema } from "electron-store";
|
||||
import { WatchStoreType } from "../types/ipc";
|
||||
import { WatchStoreType } from "../../types/ipc";
|
||||
|
||||
const watchStoreSchema: Schema<WatchStoreType> = {
|
||||
mappings: {
|
9
desktop/src/main/types/onnx-runtime.d.ts
vendored
Normal file
9
desktop/src/main/types/onnx-runtime.d.ts
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
/**
|
||||
* Types for [onnxruntime-node](https://onnxruntime.ai/docs/api/js/index.html).
|
||||
*
|
||||
* Note: these are not the official types but are based on a temporary
|
||||
* [workaround](https://github.com/microsoft/onnxruntime/issues/17979).
|
||||
*/
|
||||
declare module "onnxruntime-node" {
|
||||
export * from "onnxruntime-common";
|
||||
}
|
Loading…
Add table
Reference in a new issue