diff --git a/Cargo.lock b/Cargo.lock index 83f9a541c7..7932ece0cf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -597,7 +597,10 @@ checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" name = "app" version = "0.1.0" dependencies = [ + "base64 0.22.1", + "image", "log", + "once_cell", "serde", "serde_json", "tauri", @@ -605,12 +608,6 @@ dependencies = [ "tauri-plugin-log", ] -[[package]] -name = "arbitrary" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db55d72333851e17d572bec876e390cd3b11eb1ef53ae821dd9f3b653d2b4569" - [[package]] name = "arbitrary" version = "1.3.2" @@ -654,9 +651,9 @@ checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] name = "arrayvec" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" dependencies = [ "serde", ] @@ -840,15 +837,14 @@ dependencies = [ "log", "nom", "num-rational", - "serde", "v_frame", ] [[package]] name = "avif-serialize" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "876c75a42f6364451a033496a14c44bffe41f5f4a8236f697391f11024e596d2" +checksum = "e335041290c43101ca215eed6f43ec437eb5a42125573f600fc3fa42b9bddd62" dependencies = [ "arrayvec", ] @@ -1060,9 +1056,9 @@ dependencies = [ [[package]] name = "bitstream-io" -version = "1.10.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e445576659fd04a57b44cbd00aa37aaa815ebefa0aa3cb677a6b5e63d883074f" +checksum = "6099cdc01846bc367c4e7dd630dc5966dccf36b652fae7a74e17b640411a91b2" [[package]] name = "bitvec" @@ -1225,12 +1221,9 @@ dependencies = [ [[package]] name = "built" -version = "0.5.2" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b9c056b9ed43aee5e064b683aa1ec783e19c6acec7559e3ae931b7490472fbe" -dependencies = [ - "cargo-lock", -] +checksum = "73848a43c5d63a1251d17adf6c2bf78aa94830e60a335a95eeea45d6ba9e1e4d" [[package]] name = "bumpalo" @@ -1372,18 +1365,6 @@ dependencies = [ "serde", ] -[[package]] -name = "cargo-lock" -version = "8.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "031718ddb8f78aa5def78a09e90defe30151d1f6c672f937af4dd916429ed996" -dependencies = [ - "semver 1.0.23", - "serde", - "toml 0.5.11", - "url", -] - [[package]] name = "cargo-platform" version = "0.1.9" @@ -4317,12 +4298,12 @@ dependencies = [ [[package]] name = "image" -version = "0.25.1" +version = "0.25.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd54d660e773627692c524beaad361aca785a4f9f5730ce91f42aabe5bce3d11" +checksum = "cd6f44aed642f18953a158afeb30206f4d50da59fbc66ecb53c66488de73563b" dependencies = [ "bytemuck", - "byteorder", + "byteorder-lite", "color_quant", "exr", "gif", @@ -4340,12 +4321,12 @@ dependencies = [ [[package]] name = "image-webp" -version = "0.1.2" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d730b085583c4d789dfd07fdcf185be59501666a90c97c40162b37e4fdad272d" +checksum = "b77d01e822461baa8409e156015a1d91735549f0f2c17691bd2d996bef238f7f" dependencies = [ "byteorder-lite", - "thiserror 1.0.63", + "quick-error", ] [[package]] @@ -4525,15 +4506,6 @@ version = "1.70.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.11.0" @@ -4887,11 +4859,11 @@ checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libfuzzer-sys" -version = "0.3.5" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcf184a4b6b274f82a5df6b357da6055d3e82272327bba281c28bbba6f1664ef" +checksum = "cf78f52d400cf2d84a3a973a78a592b4adc535739e0a5597a0da6f0c357adc75" dependencies = [ - "arbitrary 0.4.7", + "arbitrary", "cc", ] @@ -5776,13 +5748,13 @@ checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" [[package]] name = "num-derive" -version = "0.3.3" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.87", ] [[package]] @@ -6107,9 +6079,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" [[package]] name = "opaque-debug" @@ -6782,6 +6754,25 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "profiling" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afbdc74edc00b6f6a218ca6a5364d6226a259d4b8ea1af4a0ea063f27e179f4d" +dependencies = [ + "profiling-procmacros", +] + +[[package]] +name = "profiling-procmacros" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a65f2e60fbf1063868558d69c6beacf412dc755f9fc020f514b7955fc914fe30" +dependencies = [ + "quote", + "syn 2.0.87", +] + [[package]] name = "prompt_engineering" version = "0.1.0" @@ -7120,11 +7111,11 @@ dependencies = [ [[package]] name = "rav1e" -version = "0.6.6" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16c383692a5e7abd9f6d1eddb1a5e0269f859392387883361bb09e5555852ec1" +checksum = "cd87ce80a7665b1cce111f8a16c1f3929f6547ce91ade6addf4ec86a8dda5ce9" dependencies = [ - "arbitrary 0.4.7", + "arbitrary", "arg_enum_proc_macro", "arrayvec", "av1-grain", @@ -7132,7 +7123,7 @@ dependencies = [ "built", "cfg-if 1.0.0", "interpolate_name", - "itertools 0.10.5", + "itertools 0.12.1", "libc", "libfuzzer-sys", "log", @@ -7143,10 +7134,9 @@ dependencies = [ "num-traits", "once_cell", "paste", + "profiling", "rand 0.8.5", "rand_chacha 0.3.1", - "rust_hawktracer", - "rustc_version 0.4.0", "simd_helpers", "system-deps", "thiserror 1.0.63", @@ -7156,9 +7146,9 @@ dependencies = [ [[package]] name = "ravif" -version = "0.11.3" +version = "0.11.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "badc69028460108fa7e32d4aec2b0c980710d7a31a896864002c8c1fc61516ee" +checksum = "2413fd96bd0ea5cdeeb37eaf446a22e6ed7b981d792828721e74ded1980a45c6" dependencies = [ "avif-serialize", "imgref", @@ -7177,9 +7167,9 @@ checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" [[package]] name = "rayon" -version = "1.8.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" dependencies = [ "either", "rayon-core", @@ -7187,9 +7177,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.12.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" dependencies = [ "crossbeam-deque", "crossbeam-utils 0.8.20", @@ -7498,12 +7488,9 @@ dependencies = [ [[package]] name = "rgb" -version = "0.8.37" +version = "0.8.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05aaa8004b64fd573fc9d002f4e632d51ad4f026c2b5ba95fcb6c2f32c2c47d8" -dependencies = [ - "bytemuck", -] +checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a" [[package]] name = "ring" @@ -7677,28 +7664,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "rust_hawktracer" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3480a29b927f66c6e06527be7f49ef4d291a01d694ec1fe85b0de71d6b02ac1" -dependencies = [ - "rust_hawktracer_normal_macro", - "rust_hawktracer_proc_macro", -] - -[[package]] -name = "rust_hawktracer_normal_macro" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a570059949e1dcdc6f35228fa389f54c2c84dfe0c94c05022baacd56eacd2e9" - -[[package]] -name = "rust_hawktracer_proc_macro" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb626abdbed5e93f031baae60d72032f56bc964e11ac2ff65f2ba3ed98d6d3e1" - [[package]] name = "rustc-demangle" version = "0.1.24" @@ -9986,15 +9951,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "toml" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" -dependencies = [ - "serde", -] - [[package]] name = "toml" version = "0.7.8" @@ -11584,7 +11540,7 @@ version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9cc23c04387f4da0374be4533ad1208cbb091d5c11d070dfef13676ad6497164" dependencies = [ - "arbitrary 1.3.2", + "arbitrary", "crc32fast", "crossbeam-utils 0.8.20", "displaydoc", @@ -11601,7 +11557,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "775a2b471036342aa69bc5a602bc889cb0a06cda00477d0c69566757d5553d39" dependencies = [ "aes 0.8.4", - "arbitrary 1.3.2", + "arbitrary", "bzip2", "constant_time_eq 0.3.0", "crc32fast", @@ -11701,9 +11657,9 @@ dependencies = [ [[package]] name = "zune-jpeg" -version = "0.4.11" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec866b44a2a1fd6133d363f073ca1b179f438f99e7e5bfb1e33f7181facfe448" +checksum = "99a5bab8d7dedf81405c4bb1f2b83ea057643d9cb28778cea9eecddeedd2e028" dependencies = [ "zune-core", ] diff --git a/crates/desktop/src-tauri/Cargo.toml b/crates/desktop/src-tauri/Cargo.toml index 7503e8eb87..4e34dd0ef8 100644 --- a/crates/desktop/src-tauri/Cargo.toml +++ b/crates/desktop/src-tauri/Cargo.toml @@ -23,3 +23,6 @@ serde = { version = "1.0", features = ["derive"] } log = "0.4" tauri = { version = "2.2.4", features = [] } tauri-plugin-log = "2.0.0-rc" +once_cell = "1.20.3" +image = "0.25.5" +base64 = "0.22.1" diff --git a/crates/desktop/src-tauri/src/image_endpoint.rs b/crates/desktop/src-tauri/src/image_endpoint.rs new file mode 100644 index 0000000000..a40e1a590f --- /dev/null +++ b/crates/desktop/src-tauri/src/image_endpoint.rs @@ -0,0 +1,34 @@ +use std::io::Cursor; +use base64::Engine; +use base64::prelude::{BASE64_STANDARD, BASE64_URL_SAFE}; +use image::codecs::png::{CompressionType, FilterType, PngEncoder}; +use image::ImageReader; + +#[tauri::command] +pub fn infer_image(image: &str) -> Result { + println!("infer_image called; processing image..."); + + let bytes = BASE64_STANDARD.decode(image) + .map_err(|err| format!("Base64 decode error: {}", err))?; + + let image = ImageReader::new(Cursor::new(bytes)) + .with_guessed_format() + .map_err(|err| format!("Image format error: {}", err))? + .decode() + .map_err(|err| format!("Image decode error: {}", err))?; + + let rotated_image = image.rotate180(); + + let mut buffer = Vec::new(); // TODO: Preallocate, better data structure + let mut writer = Cursor::new(&mut buffer); + + let encoder = PngEncoder::new_with_quality(&mut writer, CompressionType::Fast, FilterType::Adaptive); + rotated_image.write_with_encoder(encoder) + .map_err(|err| format!("Image encoding error: {}", err))?; + + let encoded = BASE64_STANDARD.encode(&buffer); + + println!("Encoded: {:?}", encoded.split_at(10).0); + + Ok(encoded) +} diff --git a/crates/desktop/src-tauri/src/lib.rs b/crates/desktop/src-tauri/src/lib.rs index 9c3118c5d4..eb94f6a947 100644 --- a/crates/desktop/src-tauri/src/lib.rs +++ b/crates/desktop/src-tauri/src/lib.rs @@ -1,3 +1,9 @@ +mod image_endpoint; + +use std::sync::{Arc, RwLock}; +use once_cell::sync::Lazy; +use image_endpoint::infer_image; + #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { tauri::Builder::default() @@ -11,6 +17,39 @@ pub fn run() { } Ok(()) }) + .invoke_handler(tauri::generate_handler![ + my_custom_command, + test_round_trip, + infer_image, + ]) .run(tauri::generate_context!()) .expect("error while running tauri application"); } + +#[tauri::command] +fn my_custom_command() { + println!("I was invoked from JavaScript!"); +} + +static COUNTER : Lazy>> = Lazy::new(|| Arc::new(RwLock::new(0))); + +#[tauri::command] +fn test_round_trip() -> u64 { + let value : u64; + { + match COUNTER.write() { + Ok(mut counter) => { + *counter += 1; + value = *counter; + }, + Err(_e) => { + value = 0; + } + } + } + + println!("I was invoked from JavaScript! {:?}", value); + + value +} + diff --git a/crates/desktop/src-tauri/tauri.conf.json b/crates/desktop/src-tauri/tauri.conf.json index 678c10876b..309c499a91 100644 --- a/crates/desktop/src-tauri/tauri.conf.json +++ b/crates/desktop/src-tauri/tauri.conf.json @@ -2,12 +2,12 @@ "$schema": "https://schema.tauri.app/config/2.0.0-rc", "productName": "Storyteller Desktop App", "version": "0.1.0", - "identifier": "com.tauri.dev", + "identifier": "com.unique.value.thing.why", "build": { - "frontendDist": "../../frontend/storyteller-animator", - "devUrl": "http://localhost:5173", + "frontendDist": "../../../frontend/realtime/dist", + "devUrl": "http://localhost:5741", "beforeDevCommand": "npm run dev", - "beforeBuildCommand": "npm run build" + "beforeBuildCommand": "npm run build2" }, "app": { "windows": [ diff --git a/frontend/realtime/package-lock.json b/frontend/realtime/package-lock.json index 6e412b3357..32d4bdcad3 100644 --- a/frontend/realtime/package-lock.json +++ b/frontend/realtime/package-lock.json @@ -11,6 +11,7 @@ "@fortawesome/free-brands-svg-icons": "^6.6.0", "@headlessui/react": "^2.1.3", "@preact/signals-react": "^2.2.0", + "@tauri-apps/api": "^2.2.0", "@techstark/opencv-js": "^4.10.0-release.1", "@zip.js/zip.js": "^2.7.52", "konva": "^9.3.14", @@ -32,6 +33,7 @@ "@fortawesome/pro-solid-svg-icons": "^6.6.0", "@fortawesome/react-fontawesome": "^0.2.2", "@preact/signals-react-transform": "^0.4.0", + "@tauri-apps/cli": "^2.2.7", "@types/deep-equal": "^1.0.4", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", @@ -1229,6 +1231,215 @@ "url": "https://github.com/sponsors/tannerlinsley" } }, + "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==", + "license": "Apache-2.0 OR MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/tauri" + } + }, + "node_modules/@tauri-apps/cli": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.2.7.tgz", + "integrity": "sha512-ZnsS2B4BplwXP37celanNANiIy8TCYhvg5RT09n72uR/o+navFZtGpFSqljV8fy1Y4ixIPds8FrGSXJCN2BerA==", + "dev": true, + "license": "Apache-2.0 OR MIT", + "bin": { + "tauri": "tauri.js" + }, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/tauri" + }, + "optionalDependencies": { + "@tauri-apps/cli-darwin-arm64": "2.2.7", + "@tauri-apps/cli-darwin-x64": "2.2.7", + "@tauri-apps/cli-linux-arm-gnueabihf": "2.2.7", + "@tauri-apps/cli-linux-arm64-gnu": "2.2.7", + "@tauri-apps/cli-linux-arm64-musl": "2.2.7", + "@tauri-apps/cli-linux-x64-gnu": "2.2.7", + "@tauri-apps/cli-linux-x64-musl": "2.2.7", + "@tauri-apps/cli-win32-arm64-msvc": "2.2.7", + "@tauri-apps/cli-win32-ia32-msvc": "2.2.7", + "@tauri-apps/cli-win32-x64-msvc": "2.2.7" + } + }, + "node_modules/@tauri-apps/cli-darwin-arm64": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.2.7.tgz", + "integrity": "sha512-54kcpxZ3X1Rq+pPTzk3iIcjEVY4yv493uRx/80rLoAA95vAC0c//31Whz75UVddDjJfZvXlXZ3uSZ+bnCOnt0A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-darwin-x64": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.2.7.tgz", + "integrity": "sha512-Vgu2XtBWemLnarB+6LqQeLanDlRj7CeFN//H8bVVdjbNzxcSxsvbLYMBP8+3boa7eBnjDrqMImRySSgL6IrwTw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm-gnueabihf": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.2.7.tgz", + "integrity": "sha512-+Clha2iQAiK9zoY/KKW0KLHkR0k36O78YLx5Sl98tWkwI3OBZFg5H5WT1plH/4sbZIS2aLFN6dw58/JlY9Bu/g==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm64-gnu": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.2.7.tgz", + "integrity": "sha512-Z/Lp4SQe6BUEOays9BQAEum2pvZF4w9igyXijP+WbkOejZx4cDvarFJ5qXrqSLmBh7vxrdZcLwoLk9U//+yQrg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm64-musl": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.2.7.tgz", + "integrity": "sha512-+8HZ+txff/Y3YjAh80XcLXcX8kpGXVdr1P8AfjLHxHdS6QD4Md+acSxGTTNbplmHuBaSHJvuTvZf9tU1eDCTDg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-x64-gnu": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.2.7.tgz", + "integrity": "sha512-ahlSnuCnUntblp9dG7/w5ZWZOdzRFi3zl0oScgt7GF4KNAOEa7duADsxPA4/FT2hLRa0SvpqtD4IYFvCxoVv3Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-x64-musl": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.2.7.tgz", + "integrity": "sha512-+qKAWnJRSX+pjjRbKAQgTdFY8ecdcu8UdJ69i7wn3ZcRn2nMMzOO2LOMOTQV42B7/Q64D1pIpmZj9yblTMvadA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-win32-arm64-msvc": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.2.7.tgz", + "integrity": "sha512-aa86nRnrwT04u9D9fhf5JVssuAZlUCCc8AjqQjqODQjMd4BMA2+d4K9qBMpEG/1kVh95vZaNsLogjEaqSTTw4A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-win32-ia32-msvc": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.2.7.tgz", + "integrity": "sha512-EiJ5/25tLSQOSGvv+t6o3ZBfOTKB5S3vb+hHQuKbfmKdRF0XQu2YPdIi1CQw1DU97ZAE0Dq4frvnyYEKWgMzVQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-win32-x64-msvc": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.2.7.tgz", + "integrity": "sha512-ZB8Kw90j8Ld+9tCWyD2fWCYfIrzbQohJ4DJSidNwbnehlZzP7wAz6Z3xjsvUdKtQ3ibtfoeTqVInzCCEpI+pWg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/@techstark/opencv-js": { "version": "4.10.0-release.1", "resolved": "https://registry.npmjs.org/@techstark/opencv-js/-/opencv-js-4.10.0-release.1.tgz", diff --git a/frontend/realtime/package.json b/frontend/realtime/package.json index 0d96e2485c..4ae7619369 100644 --- a/frontend/realtime/package.json +++ b/frontend/realtime/package.json @@ -4,7 +4,7 @@ "version": "0.0.0", "type": "module", "scripts": { - "dev": "vite", + "dev": "echo 'realtime' && vite", "build": "tsc -b && vite build", "build2": "vite build", "lint": "eslint .", @@ -14,6 +14,7 @@ "@fortawesome/free-brands-svg-icons": "^6.6.0", "@headlessui/react": "^2.1.3", "@preact/signals-react": "^2.2.0", + "@tauri-apps/api": "^2.2.0", "@techstark/opencv-js": "^4.10.0-release.1", "@zip.js/zip.js": "^2.7.52", "konva": "^9.3.14", @@ -35,6 +36,7 @@ "@fortawesome/pro-solid-svg-icons": "^6.6.0", "@fortawesome/react-fontawesome": "^0.2.2", "@preact/signals-react-transform": "^0.4.0", + "@tauri-apps/cli": "^2.2.7", "@types/deep-equal": "^1.0.4", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", diff --git a/frontend/realtime/src/KonvaApp/RenderingPrimitives/RealTimeDrawEngine.ts b/frontend/realtime/src/KonvaApp/RenderingPrimitives/RealTimeDrawEngine.ts index 1fa768956f..29bc9f76d4 100644 --- a/frontend/realtime/src/KonvaApp/RenderingPrimitives/RealTimeDrawEngine.ts +++ b/frontend/realtime/src/KonvaApp/RenderingPrimitives/RealTimeDrawEngine.ts @@ -3,14 +3,9 @@ import { Container } from "konva/lib/Container"; import { Shape } from "konva/lib/Shape"; import { Group } from "konva/lib/Group"; -import { - // SharedWorkerRequest, - SharedWorkerResponse, -} from "../WorkerPrimitives/SharedWorkerBase"; -import { - DiffusionSharedWorkerProgressData, - DiffusionSharedWorkerResponseData, -} from "../SharedWorkers/Diffusion/DiffusionSharedWorker"; + +import { invoke } from "@tauri-apps/api/core"; + import { FileUtilities } from "../FileUtilities/FileUtilities"; import { ImageNode, VideoNode, TextNode } from "../Nodes"; @@ -274,10 +269,15 @@ export class RealTimeDrawEngine { return canvas; } - private handleNodeDragEnd = () => { + public isProcessing = false; + private handleNodeDragEnd = async () => { // Clean up any existing state + if (this.isProcessing) { + return; + } console.log("Node drag ended"); - this.render(); + this.isProcessing = true; + await this.render(); }; public addNodes(node: MediaNode) { if (node instanceof VideoNode) { @@ -379,6 +379,59 @@ export class RealTimeDrawEngine { } } + + + private async imageBitmapToBase64(imageBitmap: ImageBitmap): Promise { + // Create a temporary canvas + const canvas = document.createElement("canvas"); + canvas.width = imageBitmap.width; + canvas.height = imageBitmap.height; + + // Draw the ImageBitmap onto the canvas + const ctx = canvas.getContext("2d"); + if (!ctx) throw new Error("Failed to get 2D context"); + + ctx.drawImage(imageBitmap, 0, 0); + + // Convert to base64 + const base64String = canvas.toDataURL("image/png"); + + // Clean up + canvas.remove(); + + // Remove the data:image/png;base64, prefix if you want just the base64 string + return base64String.split(",")[1]; + } + + private async base64ToImageBitmap( + base64String: string, + ): Promise { + // Create an image element + const img = new Image(); + + // Convert base64 to data URL if it doesn't include the prefix + const dataUrl = base64String.startsWith("data:") + ? base64String + : `data:image/png;base64,${base64String}`; + + // Create a promise to handle the image loading + return new Promise((resolve, reject) => { + img.onload = async () => { + try { + const bitmap = await createImageBitmap(img); + resolve(bitmap); + } catch (error) { + reject(error); + } + }; + + img.onerror = () => reject(new Error("Failed to load image")); + + // Set the source to trigger loading + img.src = dataUrl; + }); + } + public async render() { // only pick nodes that intersect with the canvas on screen bounds to freeze. this.mediaLayerRef.draw(); @@ -399,6 +452,22 @@ export class RealTimeDrawEngine { test: false, })) as ImageBitmap; - this.previewCanvas.image(bitmap); + try { + const base64Bitmap = await this.imageBitmapToBase64(bitmap); + console.log("Sending to server"); + const base64BitmapResponse = await invoke("infer_image", { + image: base64Bitmap, + }); + console.log("RESPONSE IS"); + console.log(base64BitmapResponse); + const decoded = await this.base64ToImageBitmap( + base64BitmapResponse as string, + ); + this.previewCanvas.image(decoded); + } catch (error) { + console.error("Error during image processing:", error); + } finally { + this.isProcessing = false; + } } } diff --git a/frontend/realtime/src/components/landing/Hero.tsx b/frontend/realtime/src/components/landing/Hero.tsx index 2b290de87d..030a3e96ee 100644 --- a/frontend/realtime/src/components/landing/Hero.tsx +++ b/frontend/realtime/src/components/landing/Hero.tsx @@ -3,6 +3,8 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { Button } from "../ui"; import { faDiscord } from "@fortawesome/free-brands-svg-icons"; +import { invoke } from '@tauri-apps/api/core'; + import { useNavigate } from "react-router-dom"; interface HeroProps { @@ -72,6 +74,14 @@ const Hero = ({ onFeatureClick }: HeroProps) => { ))} +
+ +
+ +
+ +
+ {/* Creative description */}

Create stunning visual stories on our intelligent canvas. @@ -82,37 +92,6 @@ const Hero = ({ onFeatureClick }: HeroProps) => { and render beautiful movies in minutes.

- {/* Playful CTA */} -
- -
- - {/* Video showcase */} -
-
- -
-
diff --git a/frontend/realtime/yarn.lock b/frontend/realtime/yarn.lock index 6a4f57f16a..dcbace8a8d 100644 --- a/frontend/realtime/yarn.lock +++ b/frontend/realtime/yarn.lock @@ -811,6 +811,32 @@ resolved "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.10.5.tgz" integrity sha512-WlJp8CipNzBz8Q4g159uMfswYHZ8p1+xJwLBdnbBTcSSu0zVoY6i27Suw5J0Y88YBnJ9jHR8jJMH/qSuZWWfNw== +"@tauri-apps/api@^2.2.0": + version "2.2.0" + resolved "https://registry.npmjs.org/@tauri-apps/api/-/api-2.2.0.tgz" + integrity sha512-R8epOeZl1eJEl603aUMIGb4RXlhPjpgxbGVEaqY+0G5JG9vzV/clNlzTeqc+NLYXVqXcn8mb4c5b9pJIUDEyAg== + +"@tauri-apps/cli-win32-x64-msvc@2.2.7": + version "2.2.7" + resolved "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.2.7.tgz" + integrity sha512-ZB8Kw90j8Ld+9tCWyD2fWCYfIrzbQohJ4DJSidNwbnehlZzP7wAz6Z3xjsvUdKtQ3ibtfoeTqVInzCCEpI+pWg== + +"@tauri-apps/cli@^2.2.7": + version "2.2.7" + resolved "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.2.7.tgz" + integrity sha512-ZnsS2B4BplwXP37celanNANiIy8TCYhvg5RT09n72uR/o+navFZtGpFSqljV8fy1Y4ixIPds8FrGSXJCN2BerA== + optionalDependencies: + "@tauri-apps/cli-darwin-arm64" "2.2.7" + "@tauri-apps/cli-darwin-x64" "2.2.7" + "@tauri-apps/cli-linux-arm-gnueabihf" "2.2.7" + "@tauri-apps/cli-linux-arm64-gnu" "2.2.7" + "@tauri-apps/cli-linux-arm64-musl" "2.2.7" + "@tauri-apps/cli-linux-x64-gnu" "2.2.7" + "@tauri-apps/cli-linux-x64-musl" "2.2.7" + "@tauri-apps/cli-win32-arm64-msvc" "2.2.7" + "@tauri-apps/cli-win32-ia32-msvc" "2.2.7" + "@tauri-apps/cli-win32-x64-msvc" "2.2.7" + "@techstark/opencv-js@^4.10.0-release.1": version "4.10.0-release.1" resolved "https://registry.npmjs.org/@techstark/opencv-js/-/opencv-js-4.10.0-release.1.tgz" diff --git a/script/launch_realtime_desktop.sh b/script/launch_realtime_desktop.sh new file mode 100755 index 0000000000..55f0faec6a --- /dev/null +++ b/script/launch_realtime_desktop.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +# Tauri doesn't let you configure the frontend project directory statically, though they do provide an +# environment variable to pass it to the CLI. Without doing this, the tauri cli randomly walks the +# filesystem and finds the wrong frontend code. + +# TODO(bt,2025-02-13): This is not the correct way to get the root dir +root_dir=$(pwd) +export TAURI_FRONTEND_PATH="${root_dir}/frontend/realtime" + +cargo tauri dev