diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index c7532d76..07d84e1f 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -17,6 +17,17 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "aes" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + [[package]] name = "aho-corasick" version = "1.1.2" @@ -119,6 +130,12 @@ version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + [[package]] name = "bit-set" version = "0.5.3" @@ -220,6 +237,27 @@ dependencies = [ "serde", ] +[[package]] +name = "bzip2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" +dependencies = [ + "bzip2-sys", + "libc", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.11+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + [[package]] name = "cairo-rs" version = "0.15.12" @@ -260,6 +298,7 @@ version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" dependencies = [ + "jobserver", "libc", ] @@ -318,6 +357,16 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "cocoa" version = "0.24.1" @@ -364,6 +413,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + [[package]] name = "convert_case" version = "0.4.0" @@ -584,6 +639,7 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "crypto-common", + "subtle", ] [[package]] @@ -1211,6 +1267,15 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + [[package]] name = "html5ever" version = "0.25.2" @@ -1425,6 +1490,15 @@ dependencies = [ "cfb", ] +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + [[package]] name = "instant" version = "0.1.12" @@ -1495,6 +1569,15 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" +[[package]] +name = "jobserver" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" +dependencies = [ + "libc", +] + [[package]] name = "js-sys" version = "0.3.66" @@ -2012,12 +2095,35 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "password-hash" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" +dependencies = [ + "base64ct", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "pathdiff" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest", + "hmac", + "password-hash", + "sha2", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -2520,9 +2626,11 @@ dependencies = [ "darling", "reqwest", "serde_json", + "tar", "tauri", "tauri-build", "tiktoken-rs", + "zip", ] [[package]] @@ -2783,6 +2891,17 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sha2" version = "0.10.8" @@ -2925,6 +3044,12 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + [[package]] name = "syn" version = "1.0.109" @@ -4384,3 +4509,52 @@ checksum = "f4686009f71ff3e5c4dbcf1a282d0a44db3f021ba69350cd42086b3e5f1c6985" dependencies = [ "libc", ] + +[[package]] +name = "zip" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" +dependencies = [ + "aes", + "byteorder", + "bzip2", + "constant_time_eq", + "crc32fast", + "crossbeam-utils", + "flate2", + "hmac", + "pbkdf2", + "sha1", + "time", + "zstd", +] + +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "5.0.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.9+zstd.1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e16efa8a874a0481a574084d34cc26fdb3b99627480f785888deb6386506656" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 42ff99da..21a1fdc2 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -19,6 +19,8 @@ tiktoken-rs = "0.4.0" base64 = "0.21.0" reqwest = { version = "0.11.16", features = ["json"] } darling = "0.20.3" +zip = "0.6.6" +tar = "0.4.40" [features] # this feature is used for production builds or when `devPath` points to the filesystem diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index fbb7ec50..a8306d54 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -10,6 +10,7 @@ fn greet(name: &str) -> String { use serde_json::Value; use reqwest::header::{HeaderMap, HeaderName, HeaderValue}; use base64::{engine::general_purpose, Engine as _}; +use std::io::Write; use std::{time::Duration, path::Path}; use serde_json::json; use std::collections::HashMap; @@ -122,6 +123,109 @@ fn check_auth(fpath: String, auth: String) -> bool{ } +#[tauri::command] +async fn install_python(path:String) -> bool{ + //get python embeddable depending on os + let os = std::env::consts::OS; + let url; + let py_path = Path::new(&path).join("python"); + if !py_path.exists() { + std::fs::create_dir_all(&py_path).unwrap(); + } + let zip_path: std::path::PathBuf = Path::new(&path).join("python.zip"); + + println!("Path: {}", path); + if os == "windows" { + url = "https://www.python.org/ftp/python/3.11.7/python-3.11.7-embed-amd64.zip".to_string() + } + else{ + println!("OS not supported"); + return false; + } + + //download python embeddable + let mut resp = reqwest::get(&url).await.unwrap(); + let mut out = std::fs::File::create(&zip_path).unwrap(); + let mut content = Vec::new(); + while let Some(chunk) = resp.chunk().await.unwrap() { + content.extend_from_slice(&chunk); + } + out.write_all(&content).unwrap(); + + //extract python embeddable + + use zip::ZipArchive; + + if os == "windows" { + let mut zipf = ZipArchive::new(std::fs::File::open(&zip_path).unwrap()).unwrap(); + zipf.extract(&py_path).unwrap(); + } + else if os == "linux" { + let mut tarf = tar::Archive::new(std::fs::File::open(&zip_path).unwrap()); + tarf.unpack(&py_path).unwrap(); + } + else if os == "macos" { + let mut zipf = zip::ZipArchive::new(std::fs::File::open(&zip_path).unwrap()).unwrap(); + zipf.extract(&py_path).unwrap(); + } + else{ + println!("OS not supported"); + return false; + } + + let py_exec_path = py_path.join("python.exe"); + + //check python is installed + let mut py = Command::new(py_exec_path); + let output = py.arg("--version").output(); + match output { + Ok(o) => { + let res = String::from_utf8(o.stdout).unwrap(); + if !res.starts_with("Python ") { + return false + } + println!("{}", res); + return true + }, + Err(e) => { + println!("{}", e); + return false + } + } +} + +#[tauri::command] +async fn install_pip(path:String) -> bool{ + let py_path = Path::new(&path).join("python"); + let py_exec_path = py_path.join("python.exe"); + let get_pip_url = "https://bootstrap.pypa.io/get-pip.py"; + let mut resp = reqwest::get(get_pip_url).await.unwrap(); + let get_pip_path = Path::new(&path).join("get-pip.py"); + let mut out = std::fs::File::create(&get_pip_path).unwrap(); + let mut content = Vec::new(); + while let Some(chunk) = resp.chunk().await.unwrap() { + content.extend_from_slice(&chunk); + } + out.write_all(&content).unwrap(); + + let mut py = Command::new(py_exec_path); + let output = py.arg(get_pip_path).output(); + match output { + Ok(o) => { + let res = String::from_utf8(o.stdout).unwrap(); + println!("{}", res); + if !res.starts_with("Python ") { + return false + } + return true + }, + Err(e) => { + println!("{}", e); + return false + } + } +} + use std::process::Command; #[tauri::command] @@ -161,6 +265,20 @@ fn check_requirements_local() -> String{ return "success".to_string() } +#[tauri::command] +fn post_py_install(path:String){ + let py_path = Path::new(&path).join("python"); + let py_pth_path = py_path.join("python311._pth"); + //uncomment python libs + let mut py_pth = std::fs::read_to_string(&py_pth_path).unwrap(); + py_pth = py_pth.replace("#import site", "import site"); + std::fs::write(&py_pth_path, py_pth).unwrap(); + + //create "completed" file + let completed_path = py_path.join("completed.txt"); + std::fs::write(&completed_path, "python311").unwrap(); +} + #[tauri::command] fn run_server_local(){ let app_base_path = tauri::api::path::data_dir().unwrap().join("co.aiclient.risu"); @@ -226,7 +344,10 @@ fn main() { native_request, check_auth, check_requirements_local, - run_server_local + run_server_local, + install_python, + install_pip, + post_py_install ]) .run(tauri::generate_context!()) .expect("error while running tauri application"); diff --git a/src/lib/Setting/Pages/AdvancedSettings.svelte b/src/lib/Setting/Pages/AdvancedSettings.svelte index 47d5c704..f2747c4a 100644 --- a/src/lib/Setting/Pages/AdvancedSettings.svelte +++ b/src/lib/Setting/Pages/AdvancedSettings.svelte @@ -9,6 +9,7 @@ import SelectInput from "src/lib/UI/GUI/SelectInput.svelte"; import OptionInput from "src/lib/UI/GUI/OptionInput.svelte"; import Help from "src/lib/Others/Help.svelte"; + import { installPython } from "src/ts/process/models/local";