call 4o from desktop 2d app

This commit is contained in:
Brandon Thomas committed 2025-04-06 17:11:02 -04:00
1 parent 73de2781a9
commit 391ca1db57
21 files changed
+235 -106

No files matched your search

Generated
+62 -6
View File
@@ -463,7 +463,7 @@ dependencies = [
"getrandom 0.2.14",
"once_cell",
"version_check",
"zerocopy",
"zerocopy 0.7.33",
]
[[package]]
@@ -818,20 +818,25 @@ dependencies = [
"crockford",
"directories 6.0.0",
"dirs 6.0.0",
"errors",
"filesys",
"futures 0.3.29",
"image",
"libloading 0.8.6",
"log",
"memory_caching",
"my-workspace-hack",
"once_cell",
"openai_sora_client",
"primitives",
"rand 0.8.5",
"rand 0.9.0",
"reqwest 0.12.15",
"serde",
"serde_derive",
"serde_json",
"serde_yaml",
"serial_test",
"subprocess_common",
"tauri",
"tauri-build",
"tauri-plugin-log",
@@ -7908,9 +7913,9 @@ dependencies = [
[[package]]
name = "once_cell"
version = "1.20.3"
version = "1.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e"
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
[[package]]
name = "onig"
@@ -7963,6 +7968,7 @@ dependencies = [
"subprocess_common",
"testing",
"tokio",
"toml 0.7.8",
]
[[package]]
@@ -9220,6 +9226,17 @@ dependencies = [
"rand_core 0.6.4",
]
[[package]]
name = "rand"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"
dependencies = [
"rand_chacha 0.9.0",
"rand_core 0.9.3",
"zerocopy 0.8.24",
]
[[package]]
name = "rand_chacha"
version = "0.2.2"
@@ -9240,6 +9257,16 @@ dependencies = [
"rand_core 0.6.4",
]
[[package]]
name = "rand_chacha"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
dependencies = [
"ppv-lite86",
"rand_core 0.9.3",
]
[[package]]
name = "rand_core"
version = "0.3.1"
@@ -9273,6 +9300,15 @@ dependencies = [
"getrandom 0.2.14",
]
[[package]]
name = "rand_core"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
dependencies = [
"getrandom 0.3.1",
]
[[package]]
name = "rand_distr"
version = "0.4.3"
@@ -13166,7 +13202,7 @@ version = "1.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675"
dependencies = [
"cfg-if 0.1.10",
"cfg-if 1.0.0",
"static_assertions",
]
@@ -14688,7 +14724,16 @@ version = "0.7.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "087eca3c1eaf8c47b94d02790dd086cd594b912d2043d4de4bfdd466b3befb7c"
dependencies = [
"zerocopy-derive",
"zerocopy-derive 0.7.33",
]
[[package]]
name = "zerocopy"
version = "0.8.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879"
dependencies = [
"zerocopy-derive 0.8.24",
]
[[package]]
@@ -14702,6 +14747,17 @@ dependencies = [
"syn 2.0.87",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.87",
]
[[package]]
name = "zerofrom"
version = "0.1.5"
+18 -4
View File
@@ -1,6 +1,8 @@
[workspace]
resolver = "2"
# This block defines the workspace members.
# When we add a library or binary crate, it needs an entry here.
members = [
# Types: common strongly-typed tokens, ids, payloads, etc.
"crates/_types/composite_identifiers",
@@ -122,21 +124,33 @@ members = [
]
[workspace.package]
# Common inheritable settings for monorepo packages
publish = false
[workspace.dependencies]
# Hakari workspace hack (faster compile times)
my-workspace-hack = { path = "crates/my-workspace-hack" }
# Internal libs
errors = { path = "crates/lib/errors" }
# External libs
# Centrally pinned versions so that we can uniformly upgrade/downgrade versions across the workspace
# If a crate needs to use an older/newer version, the dependency should be managed in that crate's own Cargo.toml
anyhow = "1.0.97"
chrono = "0.4.40"
log = "0.4.27"
once_cell = "1.21.3"
rand = "0.9.0"
reqwest = { version = "0.12.15", features = ["json", "cookies"] }
serde = "1.0.219"
serde = { version = "1.0.219", features = ["derive"] }
serde_derive = "1.0.219"
serde_json = "1.0.140"
serde_yaml = "0.9.1"
toml = "0.7.4"
# Internal libs
crockford = { path = "crates/lib/data/crockford" }
errors = { path = "crates/lib/errors" }
filesys = { path = "crates/lib/files/filesys" }
memory_caching = { path = "crates/lib/caching/memory_caching" }
openai_sora_client = { path = "crates/lib/api_clients/openai_sora_client" }
primitives = { path = "crates/lib/data/primitives" }
subprocess_common = { path = "crates/lib/subprocess_common" }
+19 -13
View File
@@ -19,32 +19,38 @@ crate-type = ["staticlib", "cdylib", "rlib"]
tauri-build = { version = "2.1.1", features = [] }
[dependencies]
# Workspace hack (faster compile times)
my-workspace-hack = { workspace = true }
# Internal
crockford = { path = "../../lib/data/crockford" }
filesys = { path = "../../lib/files/filesys" }
memory_caching = { path = "../../lib/caching/memory_caching" }
primitives = { path = "../../lib/data/primitives" }
crockford = { workspace = true }
errors = { workspace = true }
filesys = { workspace = true }
memory_caching = { workspace = true }
openai_sora_client = { workspace = true }
primitives = { workspace = true }
subprocess_common = { workspace = true }
# External
#openssl = { version = "0.10", features = ["vendored"] }
# NB(bt,2025-03-10): default-features = false on Windows while I debug openssl / rustls
anyhow = "1.0"
anyhow = { workspace = true }
base64 = "0.22.1"
bytes = "1.10"
chrono = "0.4.40"
chrono = { workspace = true }
const_format = "0.2.34"
directories = "6.0.0"
dirs = "6.0.0"
futures = "0.3"
image = "0.25.5"
log = "0.4"
once_cell = "1.20.3"
rand = "0.8.5"
reqwest = { version = "0.12.12", features = ["stream"], default-features = false }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
serde_yaml = "0.9"
log = { workspace = true }
once_cell = { workspace = true }
rand = { workspace = true }
reqwest = { workspace = true, features = ["multipart", "stream"], default-features = false }
serde = { workspace = true }
serde_derive = { workspace = true }
serde_json = { workspace = true }
serde_yaml = { workspace = true }
tauri = { version = "2.4.1", features = [] }
tauri-plugin-log = "2.3.1"
tempdir = "0.3.7"
@@ -0,0 +1,59 @@
use base64::prelude::BASE64_STANDARD;
use errors::AnyhowResult;
use base64::Engine;
use image::codecs::png::{CompressionType, FilterType, PngEncoder};
use image::{DynamicImage, ImageReader};
use std::io::Cursor;
use log::{error, info};
use openai_sora_client::credentials::SoraCredentials;
use openai_sora_client::image_gen::common::{ImageSize, NumImages};
use openai_sora_client::image_gen::sora_image_gen_remix::{sora_image_gen_remix, SoraImageGenRemixRequest};
use openai_sora_client::upload::upload_media_from_bytes::sora_media_upload_from_bytes;
use openai_sora_client::upload::upload_media_from_file::SoraMediaUploadRequest;
#[tauri::command]
pub async fn image_generation_command(image: &str, prompt: &str) -> Result<String, String> {
info!("image_generation_command called; processing image...");
let bytes = BASE64_STANDARD.decode(image)
.map_err(|err| format!("Base64 decode error: {}", err))?;
generate_image(bytes, prompt)
.await
.map_err(|err| {
error!("error: {:?}", err);
"there was an error".to_string()
})?;
Ok("success".to_string())
}
pub async fn generate_image(file_bytes: Vec<u8>, prompt: &str) -> AnyhowResult<()> {
let sora_credentials = SoraCredentials::from_toml_file("credentials.toml")?;
let filename = "credentials.toml".to_string();
let response= sora_media_upload_from_bytes(file_bytes, filename, &sora_credentials)
.await
.map_err(|err| {
error!("Failed to upload image to Sora: {:?}", err);
err
})?;
let sora_media_tokens = vec![response.id];
let response = sora_image_gen_remix(SoraImageGenRemixRequest {
prompt: prompt.to_string(),
num_images: NumImages::One,
image_size: ImageSize::Square,
sora_media_tokens: sora_media_tokens.clone(),
credentials: &sora_credentials,
}).await
.map_err(|err| {
error!("Failed to call Sora image generation: {:?}", err);
err
})?;
println!(">> TASK ID: {:?} ", response.task_id);
Ok(())
}
@@ -0,0 +1,2 @@
pub mod flip_image;
pub mod image_generation_command;
@@ -1 +0,0 @@
pub mod flip_image;
+4 -2
View File
@@ -1,10 +1,11 @@
pub mod endpoints;
pub mod events;
pub mod state;
pub mod transfer;
pub mod utils;
pub mod commands;
use crate::endpoints::flip_image::flip_image;
use crate::commands::flip_image::flip_image;
use crate::commands::image_generation_command::image_generation_command;
use crate::state::app_config::AppConfig;
use tauri_plugin_log::Target;
@@ -54,6 +55,7 @@ pub fn run() {
.manage(app_data_root)
.invoke_handler(tauri::generate_handler![
flip_image,
image_generation_command,
])
.run(tauri::generate_context!("tauri.conf.json"))
.expect("error while running tauri application");
@@ -29,6 +29,7 @@ serde = { workspace = true }
serde_derive = { workspace = true }
serde_json = { workspace = true }
tokio = { version = "1.38.0", features = ["macros"] }
toml = { workspace = true }
[dev-dependencies]
testing = { path = "../../testing" }
@@ -1,9 +1,12 @@
use std::path::Path;
use reqwest::RequestBuilder;
use serde_derive::Deserialize;
use errors::AnyhowResult;
// NB: It appears that the sentinel may require a matching user agent.
pub (crate) const USER_AGENT : &str = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36";
#[derive(Clone)]
#[derive(Clone, Deserialize)]
pub struct SoraCredentials {
pub bearer_token: String,
pub cookie: String,
@@ -26,6 +29,12 @@ impl SoraCredentials {
Ok(Self { bearer_token: bearer, cookie, sentinel })
}
pub fn from_toml_file<P: AsRef<Path>>(filename: P) -> AnyhowResult<Self> {
let contents = std::fs::read_to_string(filename)?;
let credentials = toml::from_str(&contents)?;
Ok(credentials)
}
pub fn add_credential_headers_to_request(&self, request: RequestBuilder) -> RequestBuilder {
let bearer_header = self.authorization_header_value();
@@ -10,7 +10,7 @@ pub struct SoraMediaUploadRequest<'a> {
/// Upload bytes.
/// The underlying reqwest lib needs to own the bytes, so we can't pass as a reference.
pub async fn sora_media_upload_from_bytes<P: AsRef<Path>>(bytes: Vec<u8>, file_name: String, creds: &SoraCredentials) -> AnyhowResult<SoraMediaUploadResponse> {
pub async fn sora_media_upload_from_bytes(bytes: Vec<u8>, file_name: String, creds: &SoraCredentials) -> AnyhowResult<SoraMediaUploadResponse> {
let file_path = PathBuf::from(&file_name);
// TODO: Read file magic bytes first, then fall back to this.
@@ -293,11 +293,6 @@ pub async fn enqueue_studio_image_generation_handler(
let mut sora_media_tokens = Vec::with_capacity(files_to_upload.len());
for file_path in files_to_upload {
let scene_media_upload_request = SoraMediaUploadRequest {
file_path: scene_media_path.to_string_lossy().to_string(),
credentials: &sora_credentials,
};
let sora_upload_response = sora_media_upload_from_file(file_path, &sora_credentials)
.await
.map_err(|err| {
-10
View File
@@ -4544,8 +4544,6 @@
},
"node_modules/npm/node_modules/@isaacs/cliui/node_modules/string-width": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
"integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
"dev": true,
"inBundle": true,
"license": "MIT",
@@ -5286,8 +5284,6 @@
},
"node_modules/npm/node_modules/cross-spawn/node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
"dev": true,
"inBundle": true,
"license": "ISC",
@@ -5336,8 +5332,6 @@
},
"node_modules/npm/node_modules/debug/node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true,
"inBundle": true,
"license": "MIT"
@@ -7164,8 +7158,6 @@
},
"node_modules/npm/node_modules/wrap-ansi-cjs/node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"inBundle": true,
"license": "MIT",
@@ -7203,8 +7195,6 @@
},
"node_modules/npm/node_modules/wrap-ansi/node_modules/string-width": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
"integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
"dev": true,
"inBundle": true,
"license": "MIT",
+6
View File
@@ -341,9 +341,15 @@ export class Engine {
});
uiEvents.toolbarMain.SAVE.onClick(async (/*event*/) => {
console.log('save clicked');
await this.realTimeDrawEngine.saveOutput();
});
uiEvents.toolbarMain.GENERATE.onClick(async (/*event*/) => {
console.log('generate clicked');
await this.realTimeDrawEngine.generateImage();
});
uiEvents.toolbarMain.SELECT.onClick(() => {
console.log("Toolbar Main >> Select");
this.setAppMode(AppModes.SELECT);
@@ -67,11 +67,8 @@ export class RealTimeDrawEngine {
public captureCanvas: Konva.Rect;
public backgroundRasterRect: Konva.Image;
public previewCanvas: Konva.Image;
public videoLoadingCanvas: VideoNode | undefined;
public fps: number = 24;
@@ -79,6 +76,8 @@ export class RealTimeDrawEngine {
public currentPrompt: string;
public currentStrength: number;
public lastRenderedBitmap: ImageBitmap | undefined;
// Paint Color
// paint Brush Size
// has to exit out of paint mode when shape or image are used.
@@ -910,6 +909,22 @@ export class RealTimeDrawEngine {
});
}
public async generateImage() {
if (!this.lastRenderedBitmap) {
console.error("No rendered bitmap available to generate from");
return;
}
const base64Bitmap = await this.imageBitmapToBase64(this.lastRenderedBitmap);
//const base64Bitmap = await EncodeImageBitmapToBase64(this.outputBitmap);
const generateResponse = await invoke("image_generation_command", {
image: base64Bitmap,
prompt: this.currentPrompt,
});
}
public async render() {
// only pick nodes that intersect wi th the canvas on screen bounds to freeze.
if (this.isProcessing) {
@@ -939,42 +954,23 @@ export class RealTimeDrawEngine {
test: false,
})) as ImageBitmap;
// Test code
if (false) {
this.outputBitmap = bitmap;
this.previewCanvas.image(bitmap);
const base64Bitmap = await this.imageBitmapToBase64(bitmap);
console.log(this.currentStrength);
await this.client?.generateImage({
image: base64Bitmap,
prompt: this.currentPrompt,
strength: this.currentStrength,
guidance_scale: 2,
num_inference_steps: 4,
height: 1024,
width: 1024,
lora_strength: 1.0,
});
this.isProcessing = false
return;
}
this.lastRenderedBitmap = bitmap;
try {
const base64Bitmap = await this.imageBitmapToBase64(bitmap);
//const base64Bitmap = await this.imageBitmapToBase64(bitmap);
const base64BitmapResponse = await invoke("infer_image", {
image: base64Bitmap,
prompt: this.currentPrompt,
strength: this.currentStrength * 100,
});
//const base64BitmapResponse = await invoke("image_generation_command", {
// image: base64Bitmap,
// prompt: this.currentPrompt,
//});
//console.log(base64BitmapResponse);
const decoded = await DecodeBase64ToImage(
base64BitmapResponse as string,
);
////console.log(base64BitmapResponse);
//const decoded = await DecodeBase64ToImage(
// base64BitmapResponse as string,
//);
this.outputBitmap = decoded;
this.previewCanvas.image(decoded);
//this.outputBitmap = decoded;
//this.previewCanvas.image(decoded);
} catch (error) {
console.error("Error during image processing:", error);
} finally {
@@ -63,7 +63,6 @@ export const KonvaRootComponent = ({
openAddImage={appUiContext.openAddImage}
openAddVideo={appUiContext.openAddVideo}
/>
<SignaledPromptSlider />
<SignaledPromptText />
<SignaledToolbarMain
layoutSignal={layoutContext.signal}
@@ -3,6 +3,9 @@ import { useRef } from "react";
import { ResizeType, Textarea } from "~/components/ui";
import { dispatchUiEvents } from "~/signals";
import { promptText } from "~/signals/uiEvents/promptSettings";
import { invoke } from '@tauri-apps/api/core';
import { dispatchers } from "~/signals/uiEvents/toolbarMain";
import { ToolbarMainButtonNames } from "~/components/features/ToolbarMain/enum";
export const SignaledPromptText = ({}) => {
const textAreaRef = useRef<HTMLTextAreaElement>(null);
@@ -35,6 +38,10 @@ export const SignaledPromptText = ({}) => {
spellCheck={false}
forceBlurOnOutsideClick={true}
/>
<button
onClick={dispatchers[ToolbarMainButtonNames.GENERATE]}
style={{backgroundColor:"#ff0000", color: "#00ff00"}}
>Submit</button>
</div>
);
};
@@ -16,4 +16,7 @@ export enum ToolbarMainButtonNames {
PREVIEW = "PREVIEW",
DOWNLOAD = "DOWNLOAD",
BACKGROUND = "BACKGROUND",
// 4o generation
GENERATE = "GENERATE",
}
@@ -18,8 +18,8 @@ export const ToolbarTopLeft = () => {
const tabs: TabItem[] = [
{ id: "realtime", label: "Sketch" },
{ id: "edit", label: "Edit" },
{ id: "generate", label: "Generate" },
//{ id: "edit", label: "Edit" },
//{ id: "generate", label: "Generate" },
// { id: "video", label: "Video" },
];
@@ -3,8 +3,6 @@ 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 {
@@ -74,14 +72,6 @@ const Hero = ({ onFeatureClick }: HeroProps) => {
))}
</div>
<br />
<Button onClick={() => invoke("my_custom_command")}>Test Backend Call: Custom command</Button>
<br />
<Button onClick={() => invoke("test_round_trip")}>Test Backend Call: Round trip</Button>
<br />
<Button onClick={() => invoke("infer_image")}>Test Backend Call: Image</Button>
<br />
{/* Creative description */}
<p className="mx-auto mb-12 max-w-2xl text-xl leading-relaxed text-gray-600">
Create stunning visual stories on our intelligent canvas.
+11 -16
View File
@@ -744,15 +744,10 @@
resolved "https://registry.npmjs.org/@remix-run/router/-/router-1.19.1.tgz"
integrity sha512-S45oynt/WH19bHbIXjtli6QmwNYvaz+vtnubvNpNDvUOoA/OWh6j1OikIP3G+v5GHdxyC6EXoChG3HgYGEUfcg==
"@rollup/rollup-linux-x64-gnu@4.24.0":
"@rollup/rollup-darwin-arm64@4.24.0":
version "4.24.0"
resolved "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.24.0.tgz"
integrity sha512-ZXFk7M72R0YYFN5q13niV0B7G8/5dcQ9JDp8keJSfr3GoZeXEoMHP/HlvqROA3OMbMdfr19IjCeNAnPUG93b6A==
"@rollup/rollup-linux-x64-musl@4.24.0":
version "4.24.0"
resolved "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.24.0.tgz"
integrity sha512-w1i+L7kAXZNdYl+vFvzSZy8Y1arS7vMgIy8wusXJzRrPyof5LAb02KGr1PD2EkRcl73kHulIID0M501lN+vobQ==
resolved "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.24.0.tgz"
integrity sha512-bIv+X9xeSs1XCk6DVvkO+S/z8/2AMt/2lMqdQbMrmVpgFvXlmde9mLcbQpztXm1tajC3raFDqegsH18HQPMYtA==
"@sigstore/bundle@^2.3.2":
version "2.3.2"
@@ -824,15 +819,10 @@
resolved "https://registry.npmjs.org/@tauri-apps/api/-/api-2.2.0.tgz"
integrity sha512-R8epOeZl1eJEl603aUMIGb4RXlhPjpgxbGVEaqY+0G5JG9vzV/clNlzTeqc+NLYXVqXcn8mb4c5b9pJIUDEyAg==
"@tauri-apps/cli-linux-x64-gnu@2.4.0":
"@tauri-apps/cli-darwin-arm64@2.4.0":
version "2.4.0"
resolved "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.4.0.tgz"
integrity sha512-ebRmV2HLIVms1KlNNueQCp3OrXBv6cimU3mYEh5NbZ8dH88f2sF46dFCyPq8Qr/Zti4qPEaAArVG7RYFjfECPw==
"@tauri-apps/cli-linux-x64-musl@2.4.0":
version "2.4.0"
resolved "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.4.0.tgz"
integrity sha512-FOp2cBFyq5LnUr3he95Z99PQm3nCSJv2GZNeH7UqmUpeHwdcYuhBERU7C+8VDJJPR98Q5fkcoV00Pc4nw0v5KQ==
resolved "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.4.0.tgz"
integrity sha512-MVzYrahJBgDyzUJ2gNEU8H+0oCVEucN115+CVorFnidHcJ6DtDRMCaKLkpjOZNfJyag1WQ25fu7imvZSe0mz/g==
"@tauri-apps/cli@^2.4.0":
version "2.4.0"
@@ -2096,6 +2086,11 @@ fs-minipass@^3.0.0, fs-minipass@^3.0.3:
dependencies:
minipass "^7.0.3"
fsevents@~2.3.2, fsevents@~2.3.3:
version "2.3.3"
resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz"
integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
function-bind@^1.1.2:
version "1.1.2"
resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz"