diff --git a/.github/workflows/build-and-release.yml b/.github/workflows/build-and-release.yml index 4c5e84014..62e90f580 100644 --- a/.github/workflows/build-and-release.yml +++ b/.github/workflows/build-and-release.yml @@ -319,7 +319,6 @@ jobs: unzip -o *.zip rm *.zip ls -l - - name: Setup Node uses: actions/setup-node@v4 with: diff --git a/backend/.gitignore b/backend/.gitignore index 80b0492e0..2cb1d8440 100644 --- a/backend/.gitignore +++ b/backend/.gitignore @@ -136,5 +136,6 @@ cython_debug/ images/ -dist/ +dist/* +!dist/README.md tests/inputs/PictoPy.thumbnails/ diff --git a/backend/app/custom_logging.py b/backend/app/custom_logging.py deleted file mode 100644 index 5d938203a..000000000 --- a/backend/app/custom_logging.py +++ /dev/null @@ -1,79 +0,0 @@ -# Reference: https://medium.com/1mgofficial/how-to-override-uvicorn-logger-in-fastapi-using-loguru-124133cdcd4e - -# Custom Logger Using Loguru - -import logging -import sys -from pathlib import Path -from loguru import logger -import json - - -class InterceptHandler(logging.Handler): - loglevel_mapping = { - 50: "CRITICAL", - 40: "ERROR", - 30: "WARNING", - 20: "INFO", - 10: "DEBUG", - 0: "NOTSET", - } - - def emit(self, record): - try: - level = logger.level(record.levelname).name - except AttributeError: - level = self.loglevel_mapping[record.levelno] - - frame, depth = logging.currentframe(), 2 - while frame.f_code.co_filename == logging.__file__: - frame = frame.f_back - depth += 1 - - log = logger.bind(request_id="app") - log.opt(depth=depth, exception=record.exc_info).log(level, record.getMessage()) - - -class CustomizeLogger: - @classmethod - def make_logger(cls, config_path: Path): - print("hello logger") - config = cls.load_logging_config(config_path) - logging_config = config.get("logger") - - logger = cls.customize_logging( - logging_config.get("path"), - level=logging_config.get("level"), - retention=logging_config.get("retention"), - rotation=logging_config.get("rotation"), - format=logging_config.get("format"), - ) - return logger - - @classmethod - def customize_logging( - cls, filepath: Path, level: str, rotation: str, retention: str, format: str - ): - logger.remove() - logger.add( - sys.stdout, enqueue=True, backtrace=True, level=level.upper(), format=format - ) - logger.add( - str(filepath), - rotation=rotation, - retention=retention, - enqueue=True, - backtrace=True, - level=level.upper(), - format=format, - ) - logging.basicConfig(handlers=[InterceptHandler()], level=0) - - return logger.bind(request_id=None, method=None) - - @classmethod - def load_logging_config(cls, config_path): - config = None - with open(config_path) as config_file: - config = json.load(config_file) - return config diff --git a/backend/app/logging_config.json b/backend/app/logging_config.json deleted file mode 100644 index 7c8bc3282..000000000 --- a/backend/app/logging_config.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "logger": { - "path": "app/logs/PictoPy.log", - "filename": "PictoPy.log", - "level": "info", - "rotation": "1 days", - "retention": "1 months", - "format": "{level: <8} {time:YYYY-MM-DD HH:mm:ss.SSS} request id: {extra[request_id]} - {name}:{function} - {message}" - } -} diff --git a/backend/app/utils/microservice.py b/backend/app/utils/microservice.py index 6e47b157c..f5a78e6d3 100644 --- a/backend/app/utils/microservice.py +++ b/backend/app/utils/microservice.py @@ -52,13 +52,13 @@ def _start_frozen_sync_service() -> bool: # Get the directory where the current executable is located if getattr(sys, "frozen", False): # When frozen, sys.executable points to the main executable - app_dir = Path(sys.executable).parent + app_dir = Path(sys.executable).parent.parent else: # Fallback (shouldn't happen in this function) app_dir = Path(__file__).parent.parent.parent.parent - # Look for the PictoPy_Sync directory and executable - sync_dir = app_dir / "PictoPy_Sync" + # Look for the sync-microservice directory and executable + sync_dir = app_dir / "sync-microservice" # Determine executable name based on platform system = platform.system().lower() diff --git a/backend/dist/README.md b/backend/dist/README.md index f64e2558f..5e72c294e 100644 --- a/backend/dist/README.md +++ b/backend/dist/README.md @@ -1,3 +1,3 @@ -## Do not delete this file. +## Do not delete the "dist" folder. -This file is essential for the development environment to start. +This folder is essential for the development environment to start. diff --git a/backend/main.py b/backend/main.py index a6fb86b8e..1abfd8fdc 100644 --- a/backend/main.py +++ b/backend/main.py @@ -27,7 +27,6 @@ from app.routes.face_clusters import router as face_clusters_router from app.routes.user_preferences import router as user_preferences_router from fastapi.openapi.utils import get_openapi -from app.custom_logging import CustomizeLogger @asynccontextmanager @@ -66,8 +65,6 @@ async def lifespan(app: FastAPI): ], ) -app.logger = CustomizeLogger.make_logger("app/logging_config.json") - def generate_openapi_json(): try: @@ -90,9 +87,9 @@ def generate_openapi_json(): with open(openapi_path, "w") as f: json.dump(openapi_schema, f, indent=2) - app.logger.info(f"OpenAPI JSON generated at {openapi_path}") + print(f"OpenAPI JSON generated at {openapi_path}") except Exception as e: - app.logger.error(f"Failed to generate openapi.json: {e}") + print(f"Failed to generate openapi.json: {e}") # Add CORS middleware @@ -106,7 +103,7 @@ def generate_openapi_json(): # Basic health check endpoint -@app.get("/", tags=["Health"]) +@app.get("/health", tags=["Health"]) async def root(): return {"message": "PictoPy Server is up and running!"} @@ -125,6 +122,11 @@ async def root(): # Entry point for running with: python3 main.py if __name__ == "__main__": multiprocessing.freeze_support() # Required for Windows - config = Config(app=app, host="0.0.0.0", port=8000, log_config=None) + config = Config( + app=app, + host="0.0.0.0", + port=8000, + log_level="info", + ) server = Server(config) server.run() diff --git a/backend/requirements.txt b/backend/requirements.txt index 8071a3bbc..d8b54a1cc 100644 Binary files a/backend/requirements.txt and b/backend/requirements.txt differ diff --git a/docs/backend/backend_python/openapi.json b/docs/backend/backend_python/openapi.json index a524e5186..673b56d1f 100644 --- a/docs/backend/backend_python/openapi.json +++ b/docs/backend/backend_python/openapi.json @@ -16,13 +16,13 @@ } ], "paths": { - "/": { + "/health": { "get": { "tags": [ "Health" ], "summary": "Root", - "operationId": "root__get", + "operationId": "root_health_get", "responses": { "200": { "description": "Successful Response", diff --git a/frontend/api/api-functions/face_clusters.ts b/frontend/api/api-functions/face_clusters.ts deleted file mode 100644 index e69de29bb..000000000 diff --git a/frontend/api/api-functions/index.ts b/frontend/api/api-functions/index.ts deleted file mode 100644 index e69de29bb..000000000 diff --git a/frontend/api/apiEndpoints.ts b/frontend/api/apiEndpoints.ts deleted file mode 100644 index e69de29bb..000000000 diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 879f059ef..a9e02c437 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -27,6 +27,7 @@ "@tauri-apps/api": ">=2.0.0-beta.0", "@tauri-apps/plugin-dialog": "^2.2.0", "@tauri-apps/plugin-fs": "^2.2.0", + "@tauri-apps/plugin-process": "^2.3.0", "@tauri-apps/plugin-shell": "^2.2.0", "@tauri-apps/plugin-store": "^2.2.0", "@tauri-apps/plugin-updater": "^2.7.1", @@ -5157,9 +5158,9 @@ } }, "node_modules/@tauri-apps/api": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.2.0.tgz", - "integrity": "sha512-R8epOeZl1eJEl603aUMIGb4RXlhPjpgxbGVEaqY+0G5JG9vzV/clNlzTeqc+NLYXVqXcn8mb4c5b9pJIUDEyAg==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.8.0.tgz", + "integrity": "sha512-ga7zdhbS2GXOMTIZRT0mYjKJtR9fivsXzsyq5U3vjDL0s6DTMwYRm0UHNjzTY5dh4+LSC68Sm/7WEiimbQNYlw==", "license": "Apache-2.0 OR MIT", "funding": { "type": "opencollective", @@ -5383,6 +5384,15 @@ "@tauri-apps/api": "^2.0.0" } }, + "node_modules/@tauri-apps/plugin-process": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-process/-/plugin-process-2.3.0.tgz", + "integrity": "sha512-0DNj6u+9csODiV4seSxxRbnLpeGYdojlcctCuLOCgpH9X3+ckVZIEj6H7tRQ7zqWr7kSTEWnrxtAdBb0FbtrmQ==", + "license": "MIT OR Apache-2.0", + "dependencies": { + "@tauri-apps/api": "^2.6.0" + } + }, "node_modules/@tauri-apps/plugin-shell": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-shell/-/plugin-shell-2.2.1.tgz", diff --git a/frontend/package.json b/frontend/package.json index ae35fc5ea..b9a7f6ac3 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,7 +1,7 @@ { "name": "PictoPy", "private": true, - "version": "0.0.1", + "version": "1.0.0", "type": "module", "scripts": { "dev": "vite", @@ -42,6 +42,7 @@ "@tauri-apps/api": ">=2.0.0-beta.0", "@tauri-apps/plugin-dialog": "^2.2.0", "@tauri-apps/plugin-fs": "^2.2.0", + "@tauri-apps/plugin-process": "^2.3.0", "@tauri-apps/plugin-shell": "^2.2.0", "@tauri-apps/plugin-store": "^2.2.0", "@tauri-apps/plugin-updater": "^2.7.1", diff --git a/frontend/src-tauri/Cargo.lock b/frontend/src-tauri/Cargo.lock index 453d383e3..26d7bfc77 100644 --- a/frontend/src-tauri/Cargo.lock +++ b/frontend/src-tauri/Cargo.lock @@ -238,9 +238,9 @@ dependencies = [ [[package]] name = "brotli" -version = "7.0.0" +version = "8.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc97b8f16f944bba54f0433f07e30be199b6dc2bd25937444bbad560bcea29bd" +checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -249,9 +249,9 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "4.0.2" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74fa05ad7d803d413eb8380983b092cbbaf9a85f151b871360e7b00cd7060b37" +checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -343,12 +343,12 @@ dependencies = [ [[package]] name = "cargo_toml" -version = "0.21.0" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fbd1fe9db3ebf71b89060adaf7b0504c2d6a425cf061313099547e382c2e472" +checksum = "374b7c592d9c00c1f4972ea58390ac6b18cbb6ab79011f3bdc90a0b82ca06b77" dependencies = [ "serde", - "toml", + "toml 0.9.5", ] [[package]] @@ -565,15 +565,15 @@ dependencies = [ [[package]] name = "cssparser" -version = "0.27.2" +version = "0.29.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "754b69d351cdc2d8ee09ae203db831e005560fc6030da058f86ad60c92a9cb0a" +checksum = "f93d03419cb5950ccfd3daf3ff1c7a36ace64609a1a8746d493df1ca0afde0fa" dependencies = [ "cssparser-macros", "dtoa-short", - "itoa 0.4.8", + "itoa", "matches", - "phf 0.8.0", + "phf 0.10.1", "proc-macro2", "quote", "smallvec", @@ -754,9 +754,9 @@ dependencies = [ [[package]] name = "dlopen2" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1297103d2bbaea85724fcee6294c2d50b1081f9ad47d0f6f6f61eda65315a6" +checksum = "b54f373ccf864bf587a89e880fb7610f8d73f3045f13580948ccbcaff26febff" dependencies = [ "dlopen2_derive", "libc", @@ -832,7 +832,7 @@ dependencies = [ "cc", "memchr", "rustc_version", - "toml", + "toml 0.8.20", "vswhom", "winreg", ] @@ -1485,16 +1485,14 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "html5ever" -version = "0.26.0" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7" +checksum = "3b7410cae13cbc75623c98ac4cbfd1f0bedddf3227afc24f370cf0f50a44a11c" dependencies = [ "log", "mac", "markup5ever", - "proc-macro2", - "quote", - "syn 1.0.109", + "match_token", ] [[package]] @@ -1505,7 +1503,7 @@ checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" dependencies = [ "bytes", "fnv", - "itoa 1.0.15", + "itoa", ] [[package]] @@ -1555,7 +1553,7 @@ dependencies = [ "http", "http-body", "httparse", - "itoa 1.0.15", + "itoa", "pin-project-lite", "smallvec", "tokio", @@ -1851,12 +1849,6 @@ dependencies = [ "once_cell", ] -[[package]] -name = "itoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" - [[package]] name = "itoa" version = "1.0.15" @@ -1962,14 +1954,13 @@ dependencies = [ [[package]] name = "kuchikiki" -version = "0.8.2" +version = "0.8.8-speedreader" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e4755b7b995046f510a7520c42b2fed58b77bd94d5a87a8eb43d2fd126da8" +checksum = "02cb977175687f33fa4afa0c95c112b987ea1443e5a51c8f8ff27dc618270cc2" dependencies = [ "cssparser", "html5ever", - "indexmap 1.9.3", - "matches", + "indexmap 2.7.1", "selectors", ] @@ -2088,18 +2079,29 @@ checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" [[package]] name = "markup5ever" -version = "0.11.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2629bb1404f3d34c2e921f21fd34ba00b206124c81f65c50b43b6aaefeb016" +checksum = "c7a7213d12e1864c0f002f52c2923d4556935a43dec5e71355c2760e0f6e7a18" dependencies = [ "log", - "phf 0.10.1", - "phf_codegen 0.10.0", + "phf 0.11.3", + "phf_codegen 0.11.3", "string_cache", "string_cache_codegen", "tendril", ] +[[package]] +name = "match_token" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.99", +] + [[package]] name = "matches" version = "0.1.10" @@ -2156,9 +2158,9 @@ dependencies = [ [[package]] name = "muda" -version = "0.16.1" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4de14a9b5d569ca68d7c891d613b390cf5ab4f851c77aaa2f9e435555d3d9492" +checksum = "01c1738382f66ed56b3b9c8119e794a2e23148ac8ea214eda86622d4cb9d415a" dependencies = [ "crossbeam-channel", "dpi", @@ -2172,7 +2174,7 @@ dependencies = [ "png", "serde", "thiserror 2.0.12", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -2505,6 +2507,17 @@ dependencies = [ "objc2-foundation 0.3.0", ] +[[package]] +name = "objc2-security" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3126341c65c5d5728423ae95d788e1b660756486ad0592307ab87ba02d9a7268" +dependencies = [ + "bitflags 2.9.0", + "objc2 0.6.0", + "objc2-core-foundation", +] + [[package]] name = "objc2-ui-kit" version = "0.3.0" @@ -2529,6 +2542,7 @@ dependencies = [ "objc2-app-kit 0.3.0", "objc2-core-foundation", "objc2-foundation 0.3.0", + "objc2-security", ] [[package]] @@ -2670,9 +2684,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" dependencies = [ - "phf_macros 0.8.0", "phf_shared 0.8.0", - "proc-macro-hack", ] [[package]] @@ -2681,7 +2693,9 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" dependencies = [ + "phf_macros 0.10.0", "phf_shared 0.10.0", + "proc-macro-hack", ] [[package]] @@ -2706,12 +2720,12 @@ dependencies = [ [[package]] name = "phf_codegen" -version = "0.10.0" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd" +checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" dependencies = [ - "phf_generator 0.10.0", - "phf_shared 0.10.0", + "phf_generator 0.11.3", + "phf_shared 0.11.3", ] [[package]] @@ -2746,12 +2760,12 @@ dependencies = [ [[package]] name = "phf_macros" -version = "0.8.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6fde18ff429ffc8fe78e2bf7f8b7a5a5a6e2a8b58bc5a9ac69198bbda9189c" +checksum = "58fdf3184dd560f160dd73922bea2d5cd6e8f064bf4b13110abd81b03697b4e0" dependencies = [ - "phf_generator 0.8.0", - "phf_shared 0.8.0", + "phf_generator 0.10.0", + "phf_shared 0.10.0", "proc-macro-hack", "proc-macro2", "quote", @@ -2800,7 +2814,7 @@ dependencies = [ [[package]] name = "picto_py" -version = "0.0.1" +version = "1.0.0" dependencies = [ "anyhow", "arrayref", @@ -2817,6 +2831,7 @@ dependencies = [ "tauri-build", "tauri-plugin-dialog", "tauri-plugin-fs", + "tauri-plugin-process", "tauri-plugin-shell", "tauri-plugin-store", "tauri-plugin-updater", @@ -3464,22 +3479,20 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "selectors" -version = "0.22.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df320f1889ac4ba6bc0cdc9c9af7af4bd64bb927bccdf32d81140dc1f9be12fe" +checksum = "0c37578180969d00692904465fb7f6b3d50b9a2b952b87c23d0e2e5cb5013416" dependencies = [ "bitflags 1.3.2", "cssparser", "derive_more", "fxhash", "log", - "matches", "phf 0.8.0", "phf_codegen 0.8.0", "precomputed-hash", "servo_arc", "smallvec", - "thin-slice", ] [[package]] @@ -3493,9 +3506,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.218" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8dfc9d19bdbf6d17e22319da49161d5d0108e4188e8b680aef6299eed22df60" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" dependencies = [ "serde_derive", ] @@ -3513,9 +3526,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.218" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f09503e191f4e797cb8aac08e9a4a4695c5edf6a2e70e376d961ddd5c969f82b" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", @@ -3539,7 +3552,7 @@ version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ - "itoa 1.0.15", + "itoa", "memchr", "ryu", "serde", @@ -3565,6 +3578,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40734c41988f7306bb04f0ecf60ec0f3f1caa34290e4e8ea471dcd3346483b83" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -3572,7 +3594,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ "form_urlencoded", - "itoa 1.0.15", + "itoa", "ryu", "serde", ] @@ -3609,9 +3631,9 @@ dependencies = [ [[package]] name = "serialize-to-javascript" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9823f2d3b6a81d98228151fdeaf848206a7855a7a042bbf9bf870449a66cafb" +checksum = "04f3666a07a197cdb77cdf306c32be9b7f598d7060d50cfd4d5aa04bfd92f6c5" dependencies = [ "serde", "serde_json", @@ -3620,20 +3642,20 @@ dependencies = [ [[package]] name = "serialize-to-javascript-impl" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74064874e9f6a15f04c1f3cb627902d0e6b410abbf36668afa873c61889f1763" +checksum = "772ee033c0916d670af7860b6e1ef7d658a4629a6d0b4c8c3e67f09b3765b75d" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.99", ] [[package]] name = "servo_arc" -version = "0.1.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d98238b800e0d1576d8b6e3de32827c2d74bee68bb97748dcf5071fb53965432" +checksum = "d52aa42f8fdf0fed91e5ce7f23d8138441002fa31dca008acf47e6fd4721f741" dependencies = [ "nodrop", "stable_deref_trait", @@ -3883,17 +3905,18 @@ dependencies = [ "cfg-expr", "heck 0.5.0", "pkg-config", - "toml", + "toml 0.8.20", "version-compare", ] [[package]] name = "tao" -version = "0.32.8" +version = "0.34.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63c8b1020610b9138dd7b1e06cf259ae91aa05c30f3bd0d6b42a03997b92dec1" +checksum = "959469667dbcea91e5485fc48ba7dd6023face91bb0f1a14681a70f99847c3f7" dependencies = [ "bitflags 2.9.0", + "block2 0.6.0", "core-foundation", "core-graphics", "crossbeam-channel", @@ -3921,7 +3944,7 @@ dependencies = [ "unicode-segmentation", "url", "windows", - "windows-core 0.60.1", + "windows-core 0.61.2", "windows-version", "x11-dl", ] @@ -3956,17 +3979,17 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tauri" -version = "2.3.1" +version = "2.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be747b26bf28674977fac47bdf6963fd9c7578271c3fbeb25d8686de6596f35" +checksum = "d4d1d3b3dc4c101ac989fd7db77e045cc6d91a25349cd410455cb5c57d510c1c" dependencies = [ "anyhow", "bytes", + "cookie", "dirs", "dunce", "embed_plist", - "futures-util", - "getrandom 0.2.15", + "getrandom 0.3.1", "glob", "gtk", "heck 0.5.0", @@ -3980,6 +4003,8 @@ dependencies = [ "objc2 0.6.0", "objc2-app-kit 0.3.0", "objc2-foundation 0.3.0", + "objc2-ui-kit", + "objc2-web-kit", "percent-encoding", "plist", "raw-window-handle", @@ -4007,9 +4032,9 @@ dependencies = [ [[package]] name = "tauri-build" -version = "2.0.6" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51a2e96f3c0baa0581656bb58e6fdd0f7c9c31eaf6721a0c08689d938fe85f2d" +checksum = "9c432ccc9ff661803dab74c6cd78de11026a578a9307610bbc39d3c55be7943f" dependencies = [ "anyhow", "cargo_toml", @@ -4023,15 +4048,15 @@ dependencies = [ "serde_json", "tauri-utils", "tauri-winres", - "toml", + "toml 0.9.5", "walkdir", ] [[package]] name = "tauri-codegen" -version = "2.0.5" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e357ec3daf8faad1029bc7109e7f5b308ceb63b6073d110d7388923a4cce5e55" +checksum = "1ab3a62cf2e6253936a8b267c2e95839674e7439f104fa96ad0025e149d54d8a" dependencies = [ "base64 0.22.1", "brotli", @@ -4056,9 +4081,9 @@ dependencies = [ [[package]] name = "tauri-macros" -version = "2.0.5" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "447ee4dd94690d77f1422f2b57e783c654ba75c535ad6f6e727887330804fff2" +checksum = "4368ea8094e7045217edb690f493b55b30caf9f3e61f79b4c24b6db91f07995e" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -4070,9 +4095,9 @@ dependencies = [ [[package]] name = "tauri-plugin" -version = "2.0.5" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ad3021d8e60ec7672f51ecb67c5e1a514a4d7a9a5ffc9d85090739378047502" +checksum = "9946a3cede302eac0c6eb6c6070ac47b1768e326092d32efbb91f21ed58d978f" dependencies = [ "anyhow", "glob", @@ -4081,7 +4106,7 @@ dependencies = [ "serde", "serde_json", "tauri-utils", - "toml", + "toml 0.9.5", "walkdir", ] @@ -4121,11 +4146,21 @@ dependencies = [ "tauri-plugin", "tauri-utils", "thiserror 2.0.12", - "toml", + "toml 0.8.20", "url", "uuid", ] +[[package]] +name = "tauri-plugin-process" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7461c622a5ea00eb9cd9f7a08dbd3bf79484499fd5c21aa2964677f64ca651ab" +dependencies = [ + "tauri", + "tauri-plugin", +] + [[package]] name = "tauri-plugin-shell" version = "2.2.0" @@ -4197,28 +4232,34 @@ dependencies = [ [[package]] name = "tauri-runtime" -version = "2.4.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e758a405ab39e25f4d1235c5f06fe563f44b01ee18bbe38ddec5356d4f581908" +checksum = "d4cfc9ad45b487d3fded5a4731a567872a4812e9552e3964161b08edabf93846" dependencies = [ + "cookie", "dpi", "gtk", "http", "jni", + "objc2 0.6.0", + "objc2-ui-kit", + "objc2-web-kit", "raw-window-handle", "serde", "serde_json", "tauri-utils", "thiserror 2.0.12", "url", + "webkit2gtk", + "webview2-com", "windows", ] [[package]] name = "tauri-runtime-wry" -version = "2.4.1" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b2beb90decade4c71e8b09c9e4a9245837a8a97693f945b77e32baf13f51fec" +checksum = "c1fe9d48bd122ff002064e88cfcd7027090d789c4302714e68fcccba0f4b7807" dependencies = [ "gtk", "http", @@ -4243,10 +4284,11 @@ dependencies = [ [[package]] name = "tauri-utils" -version = "2.2.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "107a959dbd5ff53d89a98f6f2e3e987c611334141a43630caae1d80e79446dd6" +checksum = "41a3852fdf9a4f8fbeaa63dc3e9a85284dd6ef7200751f0bd66ceee30c93f212" dependencies = [ + "anyhow", "brotli", "cargo_metadata", "ctor", @@ -4271,7 +4313,7 @@ dependencies = [ "serde_with", "swift-rs", "thiserror 2.0.12", - "toml", + "toml 0.9.5", "url", "urlpattern", "uuid", @@ -4285,7 +4327,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56eaa45f707bedf34d19312c26d350bc0f3c59a47e58e8adbeecdc850d2c13a0" dependencies = [ "embed-resource", - "toml", + "toml 0.8.20", ] [[package]] @@ -4313,12 +4355,6 @@ dependencies = [ "utf-8", ] -[[package]] -name = "thin-slice" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c" - [[package]] name = "thiserror" version = "1.0.69" @@ -4377,7 +4413,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dad298b01a40a23aac4580b67e3dbedb7cc8402f3592d7f49469de2ea4aecdd8" dependencies = [ "deranged", - "itoa 1.0.15", + "itoa", "num-conv", "powerfmt", "serde", @@ -4485,11 +4521,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" dependencies = [ "serde", - "serde_spanned", - "toml_datetime", + "serde_spanned 0.6.8", + "toml_datetime 0.6.8", "toml_edit 0.22.24", ] +[[package]] +name = "toml" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75129e1dc5000bfbaa9fee9d1b21f974f9fbad9daec557a521ee6e080825f6e8" +dependencies = [ + "indexmap 2.7.1", + "serde", + "serde_spanned 1.0.0", + "toml_datetime 0.7.0", + "toml_parser", + "toml_writer", + "winnow 0.7.13", +] + [[package]] name = "toml_datetime" version = "0.6.8" @@ -4499,6 +4550,15 @@ dependencies = [ "serde", ] +[[package]] +name = "toml_datetime" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bade1c3e902f58d73d3f294cd7f20391c1cb2fbcb643b73566bc773971df91e3" +dependencies = [ + "serde", +] + [[package]] name = "toml_edit" version = "0.19.15" @@ -4506,7 +4566,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ "indexmap 2.7.1", - "toml_datetime", + "toml_datetime 0.6.8", "winnow 0.5.40", ] @@ -4517,7 +4577,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" dependencies = [ "indexmap 2.7.1", - "toml_datetime", + "toml_datetime 0.6.8", "winnow 0.5.40", ] @@ -4529,11 +4589,26 @@ checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" dependencies = [ "indexmap 2.7.1", "serde", - "serde_spanned", - "toml_datetime", - "winnow 0.7.3", + "serde_spanned 0.6.8", + "toml_datetime 0.6.8", + "winnow 0.7.13", +] + +[[package]] +name = "toml_parser" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b551886f449aa90d4fe2bdaa9f4a2577ad2dde302c61ecf262d80b116db95c10" +dependencies = [ + "winnow 0.7.13", ] +[[package]] +name = "toml_writer" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc842091f2def52017664b53082ecbbeb5c7731092bad69d2c63050401dfd64" + [[package]] name = "tower" version = "0.5.2" @@ -4594,9 +4669,9 @@ dependencies = [ [[package]] name = "tray-icon" -version = "0.20.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d433764348e7084bad2c5ea22c96c71b61b17afe3a11645710f533bd72b6a2b5" +checksum = "a0d92153331e7d02ec09137538996a7786fe679c629c279e82a6be762b7e6fe2" dependencies = [ "crossbeam-channel", "dirs", @@ -5051,14 +5126,14 @@ dependencies = [ [[package]] name = "webview2-com" -version = "0.36.0" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0d606f600e5272b514dbb66539dd068211cc20155be8d3958201b4b5bd79ed3" +checksum = "d4ba622a989277ef3886dd5afb3e280e3dd6d974b766118950a08f8f678ad6a4" dependencies = [ "webview2-com-macros", "webview2-com-sys", "windows", - "windows-core 0.60.1", + "windows-core 0.61.2", "windows-implement", "windows-interface", ] @@ -5076,13 +5151,13 @@ dependencies = [ [[package]] name = "webview2-com-sys" -version = "0.36.0" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfb27fccd3c27f68e9a6af1bcf48c2d82534b8675b83608a4d81446d095a17ac" +checksum = "36695906a1b53a3bf5c4289621efedac12b73eeb0b89e7e1a89b517302d5d75c" dependencies = [ "thiserror 2.0.12", "windows", - "windows-core 0.60.1", + "windows-core 0.61.2", ] [[package]] @@ -5139,12 +5214,12 @@ dependencies = [ [[package]] name = "windows" -version = "0.60.0" +version = "0.61.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddf874e74c7a99773e62b1c671427abf01a425e77c3d3fb9fb1e4883ea934529" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" dependencies = [ "windows-collections", - "windows-core 0.60.1", + "windows-core 0.61.2", "windows-future", "windows-link", "windows-numerics", @@ -5152,11 +5227,11 @@ dependencies = [ [[package]] name = "windows-collections" -version = "0.1.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5467f79cc1ba3f52ebb2ed41dbb459b8e7db636cc3429458d9a852e15bc24dec" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" dependencies = [ - "windows-core 0.60.1", + "windows-core 0.61.2", ] [[package]] @@ -5170,32 +5245,33 @@ dependencies = [ [[package]] name = "windows-core" -version = "0.60.1" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca21a92a9cae9bf4ccae5cf8368dce0837100ddf6e6d57936749e85f152f6247" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" dependencies = [ "windows-implement", "windows-interface", "windows-link", - "windows-result 0.3.1", - "windows-strings 0.3.1", + "windows-result 0.3.4", + "windows-strings 0.4.2", ] [[package]] name = "windows-future" -version = "0.1.1" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a787db4595e7eb80239b74ce8babfb1363d8e343ab072f2ffe901400c03349f0" +checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" dependencies = [ - "windows-core 0.60.1", + "windows-core 0.61.2", "windows-link", + "windows-threading", ] [[package]] name = "windows-implement" -version = "0.59.0" +version = "0.60.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83577b051e2f49a058c308f17f273b570a6a758386fc291b5f6a934dd84e48c1" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" dependencies = [ "proc-macro2", "quote", @@ -5204,9 +5280,9 @@ dependencies = [ [[package]] name = "windows-interface" -version = "0.59.0" +version = "0.59.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb26fd936d991781ea39e87c3a27285081e3c0da5ca0fcbc02d368cc6f52ff01" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" dependencies = [ "proc-macro2", "quote", @@ -5215,17 +5291,17 @@ dependencies = [ [[package]] name = "windows-link" -version = "0.1.0" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dccfd733ce2b1753b03b6d3c65edf020262ea35e20ccdf3e288043e6dd620e3" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" [[package]] name = "windows-numerics" -version = "0.1.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "005dea54e2f6499f2cee279b8f703b3cf3b5734a2d8d21867c8f44003182eeed" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" dependencies = [ - "windows-core 0.60.1", + "windows-core 0.61.2", "windows-link", ] @@ -5251,9 +5327,9 @@ dependencies = [ [[package]] name = "windows-result" -version = "0.3.1" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06374efe858fab7e4f881500e6e86ec8bc28f9462c47e5a9941a0142ad86b189" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" dependencies = [ "windows-link", ] @@ -5270,9 +5346,9 @@ dependencies = [ [[package]] name = "windows-strings" -version = "0.3.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" dependencies = [ "windows-link", ] @@ -5313,6 +5389,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.3", +] + [[package]] name = "windows-targets" version = "0.42.2" @@ -5352,13 +5437,39 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", + "windows_i686_gnullvm 0.52.6", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows-targets" +version = "0.53.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + +[[package]] +name = "windows-threading" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-version" version = "0.1.3" @@ -5386,6 +5497,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + [[package]] name = "windows_aarch64_msvc" version = "0.42.2" @@ -5404,6 +5521,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + [[package]] name = "windows_i686_gnu" version = "0.42.2" @@ -5422,12 +5545,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + [[package]] name = "windows_i686_msvc" version = "0.42.2" @@ -5446,6 +5581,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + [[package]] name = "windows_x86_64_gnu" version = "0.42.2" @@ -5464,6 +5605,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" @@ -5482,6 +5629,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + [[package]] name = "windows_x86_64_msvc" version = "0.42.2" @@ -5500,6 +5653,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + [[package]] name = "winnow" version = "0.5.40" @@ -5511,9 +5670,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.3" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7f4ea97f6f78012141bcdb6a216b2609f0979ada50b20ca5b52dde2eac2bb1" +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" dependencies = [ "memchr", ] @@ -5551,14 +5710,15 @@ checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" [[package]] name = "wry" -version = "0.50.4" +version = "0.53.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "804a7d1613bd699beccaa60f3b3c679acee21cebba1945a693f5eab95c08d1fa" +checksum = "31f0e9642a0d061f6236c54ccae64c2722a7879ad4ec7dff59bd376d446d8e90" dependencies = [ "base64 0.22.1", "block2 0.6.0", "cookie", "crossbeam-channel", + "dirs", "dpi", "dunce", "gdkx11", @@ -5588,7 +5748,7 @@ dependencies = [ "webkit2gtk-sys", "webview2-com", "windows", - "windows-core 0.60.1", + "windows-core 0.61.2", "windows-version", "x11-dl", ] @@ -5681,7 +5841,7 @@ dependencies = [ "tracing", "uds_windows", "windows-sys 0.59.0", - "winnow 0.7.3", + "winnow 0.7.13", "xdg-home", "zbus_macros", "zbus_names", @@ -5711,7 +5871,7 @@ checksum = "7be68e64bf6ce8db94f63e72f0c7eb9a60d733f7e0499e628dfab0f84d6bcb97" dependencies = [ "serde", "static_assertions", - "winnow 0.7.3", + "winnow 0.7.13", "zvariant", ] @@ -5820,7 +5980,7 @@ dependencies = [ "serde", "static_assertions", "url", - "winnow 0.7.3", + "winnow 0.7.13", "zvariant_derive", "zvariant_utils", ] @@ -5849,5 +6009,5 @@ dependencies = [ "serde", "static_assertions", "syn 2.0.99", - "winnow 0.7.3", + "winnow 0.7.13", ] diff --git a/frontend/src-tauri/Cargo.toml b/frontend/src-tauri/Cargo.toml index c8d5b3073..e39847633 100644 --- a/frontend/src-tauri/Cargo.toml +++ b/frontend/src-tauri/Cargo.toml @@ -1,17 +1,17 @@ [package] name = "picto_py" -version = "0.0.1" +version = "1.0.0" description = "An Image sorter that sorts photos based on face encodings in it." authors = ["you"] edition = "2021" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +# See more keys and their definition s at https://doc.rust-lang.org/cargo/reference/manifest.html [build-dependencies] tauri-build = { version = "2.0.6", features = [] } [dependencies] -tauri = { version = "2.3.1", features = ["protocol-asset"] } +tauri = { version = "2.3.1", features = ["protocol-asset", "devtools"] } walkdir = "2.3" serde = { version = "1.0", features = ["derive"] } serde_json = "1" @@ -20,6 +20,7 @@ image = "0.24.6" tauri-plugin-fs = "2" tauri-plugin-shell = "2" tauri-plugin-dialog = "2" +tauri-plugin-process = "2.0.0" tauri-plugin-store = { version = "2" } ring = "0.16.20" data-encoding = "2.3.2" diff --git a/frontend/src-tauri/capabilities/migrated.json b/frontend/src-tauri/capabilities/migrated.json index 98bf8f867..ac38fa8f3 100644 --- a/frontend/src-tauri/capabilities/migrated.json +++ b/frontend/src-tauri/capabilities/migrated.json @@ -76,6 +76,7 @@ "fs:allow-video-write-recursive", "fs:write-all", "fs:write-files", + "process:default", { "identifier": "fs:scope", "allow": ["**"] diff --git a/frontend/src-tauri/src/main.rs b/frontend/src-tauri/src/main.rs index 86e02d13a..b4ade21a2 100644 --- a/frontend/src-tauri/src/main.rs +++ b/frontend/src-tauri/src/main.rs @@ -18,12 +18,13 @@ fn main() { .plugin(tauri_plugin_shell::init()) .plugin(tauri_plugin_fs::init()) .plugin(tauri_plugin_dialog::init()) + .plugin(tauri_plugin_process::init()) .setup(|app| { let file_service = FileService::new(); let cache_service = CacheService::new(); let resource_path = app .path() - .resolve("resources/server", BaseDirectory::Resource)?; + .resolve("resources/backend", BaseDirectory::Resource)?; println!("Resource path: {:?}", resource_path); app.manage(file_service); app.manage(cache_service); diff --git a/frontend/src-tauri/src/services/mod.rs b/frontend/src-tauri/src/services/mod.rs index c6edec888..684f38bc2 100644 --- a/frontend/src-tauri/src/services/mod.rs +++ b/frontend/src-tauri/src/services/mod.rs @@ -963,7 +963,7 @@ pub async fn open_with(path: String) -> Result<(), String> { pub fn get_server_path(handle: tauri::AppHandle) -> Result { let resource_path = handle .path() - .resolve("resources/server", BaseDirectory::Resource) + .resolve("resources/backend", BaseDirectory::Resource) .map_err(|e| e.to_string())?; Ok(resource_path.to_string_lossy().to_string()) } diff --git a/frontend/src-tauri/tauri.conf.json b/frontend/src-tauri/tauri.conf.json index c88e55d7e..86bfa0113 100644 --- a/frontend/src-tauri/tauri.conf.json +++ b/frontend/src-tauri/tauri.conf.json @@ -22,14 +22,15 @@ "icons/icon.ico" ], "resources": { - "../../backend/dist/": "resources/server" + "../../backend/dist/": "resources/backend", + "../../sync-microservice/dist/": "resources/sync-microservice" }, "macOS": { "signingIdentity": "-" } }, "productName": "PictoPy", - "version": "0.1.1", + "version": "1.0.0", "identifier": "com.yourcompany.pictopy", "plugins": { "fs": { @@ -52,7 +53,8 @@ "minHeight": 720, "resizable": true, "fullscreen": false, - "maximized": false + "maximized": false, + "devtools": true } ], "security": { @@ -60,7 +62,7 @@ "scope": ["**"], "enable": true }, - "csp": "default-src 'self' ipc: http://ipc.localhost; img-src 'self' asset: http://asset.localhost" + "csp": "default-src 'self' ipc: http://ipc.localhost; img-src 'self' data: asset: http://asset.localhost; connect-src 'self' http://localhost:8000 ws://localhost:8000 http://localhost:8001 ws://localhost:8001" } } } diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 106a6a9f6..2c5b6bddb 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -15,6 +15,7 @@ const App: React.FC = () => { title, message: infoMessage, variant, + showCloseButton, } = useSelector((state: RootState) => state.infoDialog); return ( @@ -28,6 +29,7 @@ const App: React.FC = () => { title={title} message={infoMessage} variant={variant} + showCloseButton={showCloseButton} /> diff --git a/frontend/src/api/api-functions/health.ts b/frontend/src/api/api-functions/health.ts new file mode 100644 index 000000000..b7cf3f07d --- /dev/null +++ b/frontend/src/api/api-functions/health.ts @@ -0,0 +1,16 @@ +import { healthEndpoints } from '../apiEndpoints'; +import { apiClient, syncApiClient } from '../axiosConfig'; +import { APIResponse } from '@/types/API'; +export const getMainBackendHealthStatus = async (): Promise => { + const response = await apiClient.get( + healthEndpoints.healthCheck, + ); + return response.data; +}; +export const getSyncMicroserviceHealthStatus = + async (): Promise => { + const response = await syncApiClient.get( + healthEndpoints.healthCheck, + ); + return response.data; + }; diff --git a/frontend/src/api/api-functions/index.ts b/frontend/src/api/api-functions/index.ts index 55f583f2e..5d6f2fa8c 100644 --- a/frontend/src/api/api-functions/index.ts +++ b/frontend/src/api/api-functions/index.ts @@ -2,3 +2,5 @@ export * from './face_clusters'; export * from './images'; export * from './folders'; +export * from './user_preferences'; +export * from './health'; diff --git a/frontend/src/api/api-functions/user_preferences.ts b/frontend/src/api/api-functions/user_preferences.ts new file mode 100644 index 000000000..bc0a02af7 --- /dev/null +++ b/frontend/src/api/api-functions/user_preferences.ts @@ -0,0 +1,41 @@ +import { userPreferencesEndpoints } from '../apiEndpoints'; +import { apiClient } from '../axiosConfig'; +import { APIResponse } from '@/types/API'; + +// User Preferences Types +export interface UserPreferencesData { + YOLO_model_size: 'nano' | 'small' | 'medium'; + GPU_Acceleration: boolean; +} + +export interface GetUserPreferencesResponse extends APIResponse { + user_preferences: UserPreferencesData; +} + +export interface UpdateUserPreferencesRequest { + YOLO_model_size?: 'nano' | 'small' | 'medium'; + GPU_Acceleration?: boolean; +} + +export interface UpdateUserPreferencesResponse extends APIResponse { + user_preferences: UserPreferencesData; +} + +// API Functions +export const getUserPreferences = + async (): Promise => { + const response = await apiClient.get( + userPreferencesEndpoints.getUserPreferences, + ); + return response.data; + }; + +export const updateUserPreferences = async ( + request: UpdateUserPreferencesRequest, +): Promise => { + const response = await apiClient.put( + userPreferencesEndpoints.updateUserPreferences, + request, + ); + return response.data; +}; diff --git a/frontend/src/api/apiEndpoints.ts b/frontend/src/api/apiEndpoints.ts index 06a38c597..16851e853 100644 --- a/frontend/src/api/apiEndpoints.ts +++ b/frontend/src/api/apiEndpoints.ts @@ -16,3 +16,12 @@ export const foldersEndpoints = { deleteFolders: '/folders/delete-folders', syncFolder: '/folders/sync-folder', }; + +export const userPreferencesEndpoints = { + getUserPreferences: '/user-preferences/', + updateUserPreferences: '/user-preferences/', +}; + +export const healthEndpoints = { + healthCheck: '/health', +}; diff --git a/frontend/src/api/axiosConfig.ts b/frontend/src/api/axiosConfig.ts index dc8bc975c..bc7fc31fb 100644 --- a/frontend/src/api/axiosConfig.ts +++ b/frontend/src/api/axiosConfig.ts @@ -1,5 +1,5 @@ import axios from 'axios'; -import { BACKEND_URL } from '@/config/Backend'; +import { BACKEND_URL, SYNC_MICROSERVICE_URL } from '@/config/Backend'; // Create simple axios instance with basic configuration export const apiClient = axios.create({ @@ -10,3 +10,11 @@ export const apiClient = axios.create({ Accept: 'application/json', }, }); +export const syncApiClient = axios.create({ + baseURL: SYNC_MICROSERVICE_URL, + timeout: 10000, // 10 seconds timeout + headers: { + 'Content-Type': 'application/json', + Accept: 'application/json', + }, +}); diff --git a/frontend/src/components/Dialog/InfoDialog.tsx b/frontend/src/components/Dialog/InfoDialog.tsx index a8ae9ec4a..abbabf07a 100644 --- a/frontend/src/components/Dialog/InfoDialog.tsx +++ b/frontend/src/components/Dialog/InfoDialog.tsx @@ -18,6 +18,7 @@ export const InfoDialog: React.FC = ({ title, message, variant = 'info', + showCloseButton = true, }) => { const dispatch = useDispatch(); @@ -51,7 +52,7 @@ export const InfoDialog: React.FC = ({ if (!open) handleClose(); }} > - + {icon} @@ -62,9 +63,11 @@ export const InfoDialog: React.FC = ({ - + {showCloseButton && ( + + )} diff --git a/frontend/src/components/OnboardingSteps/OnboardingStep.tsx b/frontend/src/components/OnboardingSteps/OnboardingStep.tsx index e015bf40c..07d53a01d 100644 --- a/frontend/src/components/OnboardingSteps/OnboardingStep.tsx +++ b/frontend/src/components/OnboardingSteps/OnboardingStep.tsx @@ -6,6 +6,7 @@ import { AvatarSelectionStep } from '@/components/OnboardingSteps/AvatarSelectio import { ThemeSelectionStep } from '@/components/OnboardingSteps/ThemeSelectionStep'; import { STEPS } from '@/constants/steps'; import { UpdateStep } from '@/components/OnboardingSteps/UpdateStep'; +import { ServerCheck } from './ServerCheck'; interface OnboardingStepProps { stepIndex: number; @@ -37,6 +38,8 @@ export const OnboardingStep: React.FC = ({ return ; case STEPS.UPDATE_STEP: return ; + case STEPS.SERVER_CHECK: + return ; default: return
; } diff --git a/frontend/src/components/OnboardingSteps/ServerCheck.tsx b/frontend/src/components/OnboardingSteps/ServerCheck.tsx new file mode 100644 index 000000000..94962caa6 --- /dev/null +++ b/frontend/src/components/OnboardingSteps/ServerCheck.tsx @@ -0,0 +1,70 @@ +import { useEffect } from 'react'; +import { useDispatch } from 'react-redux'; +import { usePictoQuery } from '@/hooks/useQueryExtension'; +import { + getMainBackendHealthStatus, + getSyncMicroserviceHealthStatus, +} from '@/api/api-functions'; +import { showLoader, hideLoader } from '@/features/loaderSlice'; +import { markCompleted } from '@/features/onboardingSlice'; +import { showInfoDialog } from '@/features/infoDialogSlice'; +import { exit } from '@tauri-apps/plugin-process'; + +interface ServerCheckProps { + stepIndex: number; +} +export const ServerCheck: React.FC = ({ stepIndex }) => { + const dispatch = useDispatch(); + const { + isSuccess: mainBackendSuccess, + isLoading: mainBackendLoading, + isError: mainBackendError, + } = usePictoQuery({ + queryKey: ['clusters'], + queryFn: getMainBackendHealthStatus, + retry: 10, + retryDelay: 1000, + }); + const { + isSuccess: syncMicroserviceSuccess, + isLoading: syncMicroserviceLoading, + isError: syncMicroserviceError, + } = usePictoQuery({ + queryKey: ['syncMicroservice'], + queryFn: getSyncMicroserviceHealthStatus, + retry: 10, + retryDelay: 1000, + }); + useEffect(() => { + if (mainBackendLoading || syncMicroserviceLoading) { + dispatch(showLoader('Waiting for servers to start')); + } + if (mainBackendError || syncMicroserviceError) { + dispatch(hideLoader()); + dispatch( + showInfoDialog({ + title: 'Error', + message: + 'Failed to connect to one or more local services. Exiting...', + variant: 'error', + showCloseButton: false, + }), + ); + setTimeout(() => { + exit(1); + }, 2000); + } + if (mainBackendSuccess && syncMicroserviceSuccess) { + dispatch(hideLoader()); + dispatch(markCompleted(stepIndex)); + } + }, [ + mainBackendSuccess, + mainBackendLoading, + mainBackendError, + syncMicroserviceSuccess, + syncMicroserviceLoading, + syncMicroserviceError, + ]); + return null; +}; diff --git a/frontend/src/config/Backend.ts b/frontend/src/config/Backend.ts index 9622563e6..28b16c48f 100644 --- a/frontend/src/config/Backend.ts +++ b/frontend/src/config/Backend.ts @@ -1,2 +1,2 @@ export const BACKEND_URL = 'http://localhost:8000'; -export const IMAGE_ENDPOINT = `${BACKEND_URL}/images`; +export const SYNC_MICROSERVICE_URL = 'http://localhost:8001/api/v1'; diff --git a/frontend/src/constants/steps.ts b/frontend/src/constants/steps.ts index 5eea4c126..bc8e213ab 100644 --- a/frontend/src/constants/steps.ts +++ b/frontend/src/constants/steps.ts @@ -1,4 +1,5 @@ export const STEPS = { + SERVER_CHECK: 'serverCheck', AVATAR_SELECTION_STEP: 'avatarSelection', FOLDER_SETUP_STEP: 'folderSetup', THEME_SELECTION_STEP: 'themeSelection', diff --git a/frontend/src/features/infoDialogSlice.ts b/frontend/src/features/infoDialogSlice.ts index 23c0033c0..11be82b4f 100644 --- a/frontend/src/features/infoDialogSlice.ts +++ b/frontend/src/features/infoDialogSlice.ts @@ -6,6 +6,7 @@ const initialState: InfoDialogProps = { title: '', message: '', variant: 'info', + showCloseButton: true, }; const infoDialogSlice = createSlice({ @@ -18,18 +19,21 @@ const infoDialogSlice = createSlice({ title: string; message: string; variant?: InfoDialogVariant; + showCloseButton?: boolean; }>, ) { state.isOpen = true; state.title = action.payload.title; state.message = action.payload.message; state.variant = action.payload.variant || 'info'; + state.showCloseButton = action.payload.showCloseButton ?? true; }, hideInfoDialog(state) { state.isOpen = false; state.title = ''; state.message = ''; state.variant = 'info'; + state.showCloseButton = true; }, }, }); diff --git a/frontend/src/pages/ComingSoon/ComingSoon.tsx b/frontend/src/pages/ComingSoon/ComingSoon.tsx new file mode 100644 index 000000000..0e0616a32 --- /dev/null +++ b/frontend/src/pages/ComingSoon/ComingSoon.tsx @@ -0,0 +1,47 @@ +import { Clock, Sparkles } from 'lucide-react'; +import { Card, CardContent } from '@/components/ui/card'; +import { Badge } from '@/components/ui/badge'; + +export const ComingSoon = () => { + return ( +
+ + + {/* Icon */} +
+
+ +
+
+ +
+
+ + {/* Badge */} + + Coming Soon + + + {/* Title */} +

+ Feature in Development +

+ + {/* Message */} +

+ We're working hard to bring you something amazing. This feature will + be available in a future update. +

+ + {/* Additional Info */} +
+

+ Stay tuned for updates and new features that will enhance your + PictoPy experience! +

+
+
+
+
+ ); +}; diff --git a/frontend/src/pages/SettingsPage/Settings.tsx b/frontend/src/pages/SettingsPage/Settings.tsx index f7113ca88..3819b5729 100644 --- a/frontend/src/pages/SettingsPage/Settings.tsx +++ b/frontend/src/pages/SettingsPage/Settings.tsx @@ -5,11 +5,21 @@ import { RefreshCw, Folder, Settings as SettingsIcon, + Cpu, + Zap, + ChevronDown, } from 'lucide-react'; import FolderPicker from '@/components/FolderPicker/FolderPicker'; import { Button } from '@/components/ui/button'; import { Switch } from '@/components/ui/switch'; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from '@/components/ui/dropdown-menu'; +import { Label } from '@/components/ui/label'; import UpdateDialog from '@/components/Updater/UpdateDialog'; import { restartServer } from '@/utils/serverUtils'; @@ -26,6 +36,11 @@ import { disableAITagging, deleteFolders, } from '@/api/api-functions'; +import { + getUserPreferences, + updateUserPreferences, + UserPreferencesData, +} from '@/api/api-functions/user_preferences'; import { setFolders } from '@/features/folderSlice'; import { showInfoDialog } from '@/features/infoDialogSlice'; import { FolderDetails } from '@/types/Folder'; @@ -76,6 +91,63 @@ const Settings: React.FC = () => { autoInvalidateTags: ['folders'], }); + // User preferences state + const [userPreferences, setUserPreferences] = useState({ + YOLO_model_size: 'nano', + GPU_Acceleration: false, + }); + + // Query for user preferences + const { data: preferencesData } = usePictoQuery({ + queryKey: ['userPreferences'], + queryFn: getUserPreferences, + }); + + // Mutation for updating user preferences + const { + mutate: updatePreferencesMutate, + isSuccess: updatePreferencesSuccess, + isError: updatePreferencesError, + } = usePictoMutation({ + mutationFn: updateUserPreferences, + }); + + // Update local state when preferences data changes + useEffect(() => { + if (preferencesData?.success && preferencesData.user_preferences) { + setUserPreferences(preferencesData.user_preferences); + } + }, [preferencesData]); + + // Handle preference updates + const handlePreferenceUpdate = (updatedPreferences: UserPreferencesData) => { + setUserPreferences(updatedPreferences); + updatePreferencesMutate(updatedPreferences); + }; + + // Handle preference update success/error + useEffect(() => { + if (updatePreferencesSuccess) { + dispatch( + showInfoDialog({ + title: 'Preferences Updated', + message: 'Your preferences have been saved successfully.', + }), + ); + } + }, [updatePreferencesSuccess, dispatch]); + + useEffect(() => { + if (updatePreferencesError) { + dispatch( + showInfoDialog({ + title: 'Error', + message: 'Failed to update preferences. Please try again.', + }), + ); + } + }, [updatePreferencesError, dispatch]); + useEffect(() => { if (foldersLoading) { dispatch(showLoader('Loading folders')); @@ -243,6 +315,109 @@ const Settings: React.FC = () => { + {/* User Preferences Card */} +
+
+ +
+

+ User Preferences +

+

+ Configure AI model settings and performance options +

+
+
+ +
+ {/* YOLO Model Size Setting */} +
+
+ +

+ Choose the AI model size for object detection (larger models + are more accurate but slower) +

+
+ + + + + + + handlePreferenceUpdate({ + ...userPreferences, + YOLO_model_size: 'nano', + }) + } + > + Nano + + + handlePreferenceUpdate({ + ...userPreferences, + YOLO_model_size: 'small', + }) + } + > + Small + + + handlePreferenceUpdate({ + ...userPreferences, + YOLO_model_size: 'medium', + }) + } + > + Medium + + + +
+ + {/* GPU Acceleration Setting */} +
+
+ +

+ Enable GPU acceleration for faster AI processing (requires + compatible hardware) +

+
+
+ + + handlePreferenceUpdate({ + ...userPreferences, + GPU_Acceleration: checked, + }) + } + /> +
+
+
+
+ {/* Application Controls Card */}
diff --git a/frontend/src/routes/AppRoutes.tsx b/frontend/src/routes/AppRoutes.tsx index dc86524aa..e79a9cf90 100644 --- a/frontend/src/routes/AppRoutes.tsx +++ b/frontend/src/routes/AppRoutes.tsx @@ -7,6 +7,7 @@ import Settings from '@/pages/SettingsPage/Settings'; import { Home } from '@/pages/Home/Home'; import { AITagging } from '@/pages/AITagging/AITagging'; import { PersonImages } from '@/pages/PersonImages/PersonImages'; +import { ComingSoon } from '@/pages/ComingSoon/ComingSoon'; export const AppRoutes: React.FC = () => { return ( @@ -14,11 +15,11 @@ export const AppRoutes: React.FC = () => { } /> }> } /> - } /> + } /> } /> } /> - } /> - } /> + } /> + } /> } /> diff --git a/frontend/src/types/infoDialog.ts b/frontend/src/types/infoDialog.ts index 342654375..653a81d97 100644 --- a/frontend/src/types/infoDialog.ts +++ b/frontend/src/types/infoDialog.ts @@ -5,4 +5,5 @@ export interface InfoDialogProps { title: string; message: string; variant?: InfoDialogVariant; + showCloseButton?: boolean; } diff --git a/sync-microservice/.gitignore b/sync-microservice/.gitignore index 8e5d9d6f8..c330f3aa9 100644 --- a/sync-microservice/.gitignore +++ b/sync-microservice/.gitignore @@ -136,7 +136,8 @@ cython_debug/ images/ -dist/ +dist/* +!dist/README.md tests/inputs/PictoPy.thumbnails/ .sync-env/ \ No newline at end of file diff --git a/sync-microservice/dist/README.md b/sync-microservice/dist/README.md new file mode 100644 index 000000000..5e72c294e --- /dev/null +++ b/sync-microservice/dist/README.md @@ -0,0 +1,3 @@ +## Do not delete the "dist" folder. + +This folder is essential for the development environment to start. diff --git a/sync-microservice/main.py b/sync-microservice/main.py index 52b21b53f..db62c605d 100644 --- a/sync-microservice/main.py +++ b/sync-microservice/main.py @@ -2,6 +2,7 @@ from uvicorn import Config, Server from app.core.lifespan import lifespan from app.routes import health, watcher, folders +from fastapi.middleware.cors import CORSMiddleware # Create FastAPI app with lifespan management app = FastAPI( @@ -10,13 +11,19 @@ version="1.0.0", lifespan=lifespan, ) - +app.add_middleware( + CORSMiddleware, + allow_origins=["*"], # Allows all origins + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) # Include route modules app.include_router(health.router, prefix="/api/v1") app.include_router(watcher.router, prefix="/api/v1") app.include_router(folders.router, prefix="/api/v1") if __name__ == "__main__": - config = Config(app=app, host="0.0.0.0", port=8001, log_config=None) + config = Config(app=app, host="0.0.0.0", port=8001, log_level="info") server = Server(config) server.run()