Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
41c24e0655 | ||
|
|
126f1b46d6 | ||
|
|
adfebced8e | ||
|
|
e85c861d42 | ||
|
|
beeeae082a | ||
|
|
235b3a4ce5 | ||
|
|
d554abe5d4 | ||
|
|
f93441084f | ||
|
|
06041a01e6 | ||
|
|
f22d267386 | ||
|
|
4d3e326374 | ||
|
|
87f8540424 | ||
|
|
cff41464a6 | ||
|
|
425b21b586 | ||
|
|
f3ef51f9ea | ||
|
|
51797b256e | ||
|
|
2b453660da | ||
|
|
e55bc020df | ||
|
|
1ae844259f | ||
|
|
05e64de573 | ||
|
|
61043c6ea3 | ||
|
|
8845b177be | ||
|
|
c4e591ef0c | ||
|
|
ba071987d8 | ||
|
|
62fb799775 | ||
|
|
241a9d3031 | ||
|
|
06a0a8070d | ||
|
|
e8beb2ff8c | ||
|
|
76ccbe3291 | ||
|
|
3817f208d3 | ||
|
|
a22710e1a5 | ||
|
|
e27ebc7961 | ||
|
|
cafd37c313 | ||
|
|
6be886ce4d | ||
|
|
2652897109 | ||
|
|
0cb594a1eb | ||
|
|
2d635f3f8e | ||
|
|
ea783c14de | ||
|
|
01093918da | ||
|
|
2ea9464be2 | ||
|
|
b41b4f8e17 | ||
|
|
09cf4529c0 | ||
|
|
bf035f9048 | ||
|
|
448c760339 | ||
|
|
7a55592bfd | ||
|
|
a54977d392 | ||
|
|
f4268038c5 | ||
|
|
f81a215133 | ||
|
|
b2016dcfb9 | ||
|
|
2ca80ed9dc | ||
|
|
320af54e14 | ||
|
|
391ca1db57 | ||
|
|
73de2781a9 | ||
|
|
a65bdcd882 | ||
|
|
3c5fd9ce65 | ||
|
|
d82be338fc | ||
|
|
23f762da8f | ||
|
|
8b21489453 | ||
|
|
f9a9168ad5 | ||
|
|
8cbdd22b46 | ||
|
|
f456795fb1 | ||
|
|
63d41f7d2c | ||
|
|
14474e68c2 | ||
|
|
2f44da8ac7 | ||
|
|
3d67f86a19 | ||
|
|
2913d91d0d | ||
|
|
ceb77505e1 | ||
|
|
0cad3fe7da | ||
|
|
1ced74040f | ||
|
|
c9dd545ae1 | ||
|
|
8ff91690c1 | ||
|
|
97bbe0fe07 | ||
|
|
9361634d83 | ||
|
|
7cf0363555 | ||
|
|
c2ee3b0ce1 | ||
|
|
ca6fc13171 | ||
|
|
cb1ea1f828 | ||
|
|
010e3be5dc | ||
|
|
d8dab1a66e | ||
|
|
97b236d04d | ||
|
|
15fe59cc19 | ||
|
|
89bec31540 | ||
|
|
7568a0ef86 | ||
|
|
6180222e15 | ||
|
|
6d45ce29e2 | ||
|
|
1da56d6d22 | ||
|
|
91a1c00442 | ||
|
|
3db942f1f6 | ||
|
|
2e56291649 | ||
|
|
b31badc6d1 | ||
|
|
ed399fcb21 | ||
|
|
d858c9394b | ||
|
|
a19a6599ec | ||
|
|
57c15f7c9f | ||
|
|
aa25ae8c87 | ||
|
|
c27055761e | ||
|
|
abf3024892 | ||
|
|
2182d4dde1 | ||
|
|
b632b927a3 | ||
|
|
4e2be12064 | ||
|
|
29b33cd327 | ||
|
|
032d0e1eae | ||
|
|
a3ddffeeee | ||
|
|
28a5ff2f9f | ||
|
|
1028e04e02 | ||
|
|
49c010db59 | ||
|
|
48ff60d3b8 | ||
|
|
9c5b993c4f | ||
|
|
a4aecc4d38 | ||
|
|
4d73230e84 | ||
|
|
a5a09f3e64 | ||
|
|
49894bd9b3 |
@@ -1,4 +1,4 @@
|
||||
hakari-package = "my-workspace-hack"
|
||||
hakari-package = "workspace-build-acceleration"
|
||||
|
||||
resolver = "1"
|
||||
|
||||
@@ -11,4 +11,4 @@ platforms = [
|
||||
"x86_64-pc-windows-msvc",
|
||||
]
|
||||
|
||||
exact-versions = true
|
||||
exact-versions = true
|
||||
|
||||
@@ -32,6 +32,9 @@ target/
|
||||
crates/lib/database_queries/target/
|
||||
crates/lib/sqlite_queries/target/
|
||||
|
||||
# Javascript build directories
|
||||
node_modules/
|
||||
|
||||
# Vim noise
|
||||
*.swo
|
||||
*.swp
|
||||
|
||||
@@ -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",
|
||||
@@ -22,9 +24,8 @@ members = [
|
||||
"crates/cli/production/migration-tool",
|
||||
|
||||
# Desktop apps
|
||||
"crates/desktop/src-tauri",
|
||||
"crates/desktop/ml_models",
|
||||
"crates/desktop/ml_weights_registry",
|
||||
"crates/desktop/tauri-4o",
|
||||
"crates/desktop/tauri-realtime",
|
||||
|
||||
# Shared libraries
|
||||
"crates/lib/actix_cors_configs",
|
||||
@@ -32,6 +33,7 @@ members = [
|
||||
"crates/lib/api_clients/cloud_storage",
|
||||
"crates/lib/api_clients/google_drive_common",
|
||||
"crates/lib/api_clients/google_sign_in",
|
||||
"crates/lib/api_clients/openai_sora_client",
|
||||
"crates/lib/api_clients/thumbnail_generator",
|
||||
"crates/lib/bootstrap",
|
||||
"crates/lib/bucket_paths",
|
||||
@@ -58,16 +60,20 @@ members = [
|
||||
"crates/lib/files/mimetypes",
|
||||
"crates/lib/files/videos",
|
||||
"crates/lib/idempotency",
|
||||
"crates/lib/image_algorithms",
|
||||
"crates/lib/jobs_common",
|
||||
"crates/lib/logging",
|
||||
"crates/lib/machine_learning/ml_models",
|
||||
"crates/lib/machine_learning/ml_weights_registry",
|
||||
"crates/lib/machine_learning/prompt_engineering",
|
||||
"crates/lib/markdown",
|
||||
"crates/lib/migration",
|
||||
"crates/lib/mysql_queries",
|
||||
"crates/lib/password",
|
||||
"crates/lib/prompt_engineering",
|
||||
"crates/lib/redis_common",
|
||||
"crates/lib/redis_schema",
|
||||
"crates/lib/server_environment",
|
||||
"crates/lib/shared_service_components",
|
||||
"crates/lib/sqlx_mysql_helpers",
|
||||
"crates/lib/storyteller_root",
|
||||
"crates/lib/subprocess_common",
|
||||
@@ -115,5 +121,40 @@ members = [
|
||||
|
||||
# cargo-hakari workspace hack (compilation speedup hack)
|
||||
# see usage: https://crates.io/crates/cargo-hakari
|
||||
"crates/my-workspace-hack",
|
||||
"crates/workspace-build-acceleration",
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
# Common inheritable settings for monorepo packages
|
||||
publish = false
|
||||
|
||||
[workspace.dependencies]
|
||||
# Hakari workspace hack (faster compile times)
|
||||
workspace-build-acceleration = { path = "crates/workspace-build-acceleration" }
|
||||
|
||||
# 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 = { version = "0.4.40", features = ["serde"] }
|
||||
log = "0.4.27"
|
||||
once_cell = "1.21.3"
|
||||
rand = "0.9.0"
|
||||
regex = "1.11.1"
|
||||
reqwest = { version = "0.12.15", features = ["json", "cookies"] }
|
||||
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"
|
||||
url = "2.5.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" }
|
||||
shared_service_components = { path = "crates/lib/shared_service_components" }
|
||||
openai_sora_client = { path = "crates/lib/api_clients/openai_sora_client" }
|
||||
primitives = { path = "crates/lib/data/primitives" }
|
||||
subprocess_common = { path = "crates/lib/subprocess_common" }
|
||||
|
||||
@@ -13,7 +13,7 @@ name = "composite_identifiers"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
normal = ["my-workspace-hack"]
|
||||
normal = ["workspace-build-acceleration"]
|
||||
|
||||
[dependencies]
|
||||
# Internal
|
||||
@@ -21,7 +21,7 @@ enums = { path = "../enums" }
|
||||
tokens = { path = "../tokens" }
|
||||
|
||||
# Workspace hack (faster compile times)
|
||||
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
|
||||
workspace-build-acceleration = { version = "0.1", path = "../../workspace-build-acceleration" }
|
||||
|
||||
# Serialization
|
||||
serde = "1.0.125"
|
||||
|
||||
@@ -13,13 +13,13 @@ name = "enums"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
normal = ["my-workspace-hack"]
|
||||
normal = ["workspace-build-acceleration"]
|
||||
|
||||
[dependencies]
|
||||
# Internal
|
||||
|
||||
# Workspace hack (faster compile times)
|
||||
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
|
||||
workspace-build-acceleration = { version = "0.1", path = "../../workspace-build-acceleration" }
|
||||
|
||||
# Serialization
|
||||
serde = "1.0.125"
|
||||
|
||||
@@ -40,6 +40,10 @@ pub enum InferenceJobType {
|
||||
#[serde(rename = "studio_gen2")]
|
||||
StudioGen2,
|
||||
|
||||
/// Sora GPT 4o image gen
|
||||
#[serde(rename = "image_gen_api")]
|
||||
ImageGenApi,
|
||||
|
||||
/// A job that turns "FBX" game engine files into "GLTF" files (Bevy-compatible).
|
||||
#[serde(rename = "convert_fbx_gltf")]
|
||||
ConvertFbxToGltf,
|
||||
@@ -108,6 +112,7 @@ impl InferenceJobType {
|
||||
Self::GptSovits => "gpt_sovits",
|
||||
Self::ComfyUi => "comfy_ui",
|
||||
Self::StudioGen2 => "studio_gen2",
|
||||
Self::ImageGenApi => "image_gen_api",
|
||||
Self::ConvertFbxToGltf => "convert_fbx_gltf",
|
||||
Self::MocapNet => "mocap_net",
|
||||
Self::RvcV2 => "rvc_v2",
|
||||
@@ -132,6 +137,7 @@ impl InferenceJobType {
|
||||
"gpt_sovits" => Ok(Self::GptSovits),
|
||||
"comfy_ui" => Ok(Self::ComfyUi),
|
||||
"studio_gen2" => Ok(Self::StudioGen2),
|
||||
"image_gen_api" => Ok(Self::ImageGenApi),
|
||||
"convert_fbx_gltf" => Ok(Self::ConvertFbxToGltf),
|
||||
"mocap_net" => Ok(Self::MocapNet),
|
||||
"rvc_v2" => Ok(Self::RvcV2),
|
||||
@@ -159,6 +165,7 @@ impl InferenceJobType {
|
||||
Self::GptSovits,
|
||||
Self::ComfyUi,
|
||||
Self::StudioGen2,
|
||||
Self::ImageGenApi,
|
||||
Self::ConvertFbxToGltf,
|
||||
Self::MocapNet,
|
||||
Self::RvcV2,
|
||||
@@ -197,6 +204,7 @@ mod tests {
|
||||
assert_serialization(InferenceJobType::GptSovits, "gpt_sovits");
|
||||
assert_serialization(InferenceJobType::ComfyUi, "comfy_ui");
|
||||
assert_serialization(InferenceJobType::StudioGen2, "studio_gen2");
|
||||
assert_serialization(InferenceJobType::ImageGenApi, "image_gen_api");
|
||||
assert_serialization(InferenceJobType::ConvertFbxToGltf, "convert_fbx_gltf");
|
||||
assert_serialization(InferenceJobType::MocapNet, "mocap_net");
|
||||
assert_serialization(InferenceJobType::RvcV2, "rvc_v2");
|
||||
@@ -220,6 +228,7 @@ mod tests {
|
||||
assert_eq!(InferenceJobType::GptSovits.to_str(), "gpt_sovits");
|
||||
assert_eq!(InferenceJobType::ComfyUi.to_str(), "comfy_ui");
|
||||
assert_eq!(InferenceJobType::StudioGen2.to_str(), "studio_gen2");
|
||||
assert_eq!(InferenceJobType::ImageGenApi.to_str(), "image_gen_api");
|
||||
assert_eq!(InferenceJobType::ConvertFbxToGltf.to_str(), "convert_fbx_gltf");
|
||||
assert_eq!(InferenceJobType::MocapNet.to_str(), "mocap_net");
|
||||
assert_eq!(InferenceJobType::RvcV2.to_str(), "rvc_v2");
|
||||
@@ -243,6 +252,7 @@ mod tests {
|
||||
assert_eq!(InferenceJobType::from_str("gpt_sovits").unwrap(), InferenceJobType::GptSovits);
|
||||
assert_eq!(InferenceJobType::from_str("comfy_ui").unwrap(), InferenceJobType::ComfyUi);
|
||||
assert_eq!(InferenceJobType::from_str("studio_gen2").unwrap(), InferenceJobType::StudioGen2);
|
||||
assert_eq!(InferenceJobType::from_str("image_gen_api").unwrap(), InferenceJobType::ImageGenApi);
|
||||
assert_eq!(InferenceJobType::from_str("convert_fbx_gltf").unwrap(), InferenceJobType::ConvertFbxToGltf);
|
||||
assert_eq!(InferenceJobType::from_str("mocap_net").unwrap(), InferenceJobType::MocapNet);
|
||||
assert_eq!(InferenceJobType::from_str("rvc_v2").unwrap(), InferenceJobType::RvcV2);
|
||||
@@ -261,7 +271,7 @@ mod tests {
|
||||
fn all_variants() {
|
||||
// Static check
|
||||
let mut variants = InferenceJobType::all_variants();
|
||||
assert_eq!(variants.len(), 16);
|
||||
assert_eq!(variants.len(), 17);
|
||||
assert_eq!(variants.pop_first(), Some(InferenceJobType::VideoRender));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceJobType::LivePortrait));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceJobType::FaceFusion));
|
||||
@@ -269,6 +279,7 @@ mod tests {
|
||||
assert_eq!(variants.pop_first(), Some(InferenceJobType::GptSovits));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceJobType::ComfyUi));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceJobType::StudioGen2));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceJobType::ImageGenApi));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceJobType::ConvertFbxToGltf));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceJobType::MocapNet));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceJobType::RvcV2));
|
||||
|
||||
@@ -33,6 +33,10 @@ pub enum InferenceModelType {
|
||||
#[serde(rename = "seed_vc")]
|
||||
SeedVc,
|
||||
|
||||
/// NB: This is for Sora GPT 4o image gen
|
||||
#[serde(rename = "image_gen_api")]
|
||||
ImageGenApi,
|
||||
|
||||
#[serde(rename = "tacotron2")]
|
||||
Tacotron2,
|
||||
#[serde(rename = "vits")]
|
||||
@@ -70,6 +74,7 @@ impl InferenceModelType {
|
||||
Self::VallEX => "vall_e_x",
|
||||
Self::RerenderAVideo => "rerender_a_video",
|
||||
Self::StableDiffusion => "stable_diffusion",
|
||||
Self::ImageGenApi => "image_gen_api",
|
||||
Self::SeedVc => "seed_vc",
|
||||
Self::MocapNet => "mocap_net",
|
||||
Self::StyleTTS2 => "styletts2",
|
||||
@@ -90,6 +95,7 @@ impl InferenceModelType {
|
||||
"vall_e_x" => Ok(Self::VallEX),
|
||||
"rerender_a_video" => Ok(Self::RerenderAVideo),
|
||||
"stable_diffusion" => Ok(Self::StableDiffusion),
|
||||
"image_gen_api" => Ok(Self::ImageGenApi),
|
||||
"mocap_net" => Ok(Self::MocapNet),
|
||||
"styletts2" => Ok(Self::StyleTTS2),
|
||||
"comfy_ui" => Ok(Self::ComfyUi),
|
||||
@@ -113,6 +119,7 @@ impl InferenceModelType {
|
||||
Self::VallEX,
|
||||
Self::RerenderAVideo,
|
||||
Self::StableDiffusion,
|
||||
Self::ImageGenApi,
|
||||
Self::MocapNet,
|
||||
Self::StyleTTS2,
|
||||
Self::ConvertFbxToGltf,
|
||||
@@ -140,6 +147,7 @@ mod tests {
|
||||
assert_serialization(InferenceModelType::VallEX, "vall_e_x");
|
||||
assert_serialization(InferenceModelType::RerenderAVideo, "rerender_a_video");
|
||||
assert_serialization(InferenceModelType::StableDiffusion, "stable_diffusion");
|
||||
assert_serialization(InferenceModelType::ImageGenApi, "image_gen_api");
|
||||
assert_serialization(InferenceModelType::MocapNet, "mocap_net");
|
||||
assert_serialization(InferenceModelType::ComfyUi, "comfy_ui");
|
||||
assert_serialization(InferenceModelType::StyleTTS2, "styletts2");
|
||||
@@ -159,6 +167,7 @@ mod tests {
|
||||
assert_eq!(InferenceModelType::VallEX.to_str(), "vall_e_x");
|
||||
assert_eq!(InferenceModelType::RerenderAVideo.to_str(), "rerender_a_video");
|
||||
assert_eq!(InferenceModelType::StableDiffusion.to_str(), "stable_diffusion");
|
||||
assert_eq!(InferenceModelType::ImageGenApi.to_str(), "image_gen_api");
|
||||
assert_eq!(InferenceModelType::MocapNet.to_str(), "mocap_net");
|
||||
assert_eq!(InferenceModelType::StyleTTS2.to_str(), "styletts2");
|
||||
assert_eq!(InferenceModelType::ConvertFbxToGltf.to_str(), "convert_fbx_gltf");
|
||||
@@ -176,6 +185,7 @@ mod tests {
|
||||
assert_eq!(InferenceModelType::from_str("vall_e_x").unwrap(), InferenceModelType::VallEX);
|
||||
assert_eq!(InferenceModelType::from_str("rerender_a_video").unwrap(), InferenceModelType::RerenderAVideo);
|
||||
assert_eq!(InferenceModelType::from_str("stable_diffusion").unwrap(), InferenceModelType::StableDiffusion);
|
||||
assert_eq!(InferenceModelType::from_str("image_gen_api").unwrap(), InferenceModelType::ImageGenApi);
|
||||
assert_eq!(InferenceModelType::from_str("mocap_net").unwrap(), InferenceModelType::MocapNet);
|
||||
assert_eq!(InferenceModelType::from_str("styletts2").unwrap(), InferenceModelType::StyleTTS2);
|
||||
assert_eq!(InferenceModelType::from_str("comfy_ui").unwrap(), InferenceModelType::ComfyUi);
|
||||
@@ -187,17 +197,18 @@ mod tests {
|
||||
fn all_variants() {
|
||||
// Static check
|
||||
let mut variants = InferenceModelType::all_variants();
|
||||
assert_eq!(variants.len(), 13);
|
||||
assert_eq!(variants.len(), 15);
|
||||
assert_eq!(variants.pop_first(), Some(InferenceModelType::ComfyUi));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceModelType::RvcV2));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceModelType::SadTalker));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceModelType::SeedVc));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceModelType::SoVitsSvc));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceModelType::SeedVc));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceModelType::Tacotron2));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceModelType::Vits));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceModelType::VallEX));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceModelType::RerenderAVideo));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceModelType::StableDiffusion));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceModelType::ImageGenApi));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceModelType::MocapNet));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceModelType::StyleTTS2));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceModelType::ConvertFbxToGltf));
|
||||
|
||||
@@ -57,6 +57,9 @@ pub enum MediaFileOriginModelType {
|
||||
#[serde(rename = "studio")]
|
||||
StorytellerStudio,
|
||||
|
||||
#[serde(rename = "studio_ig")]
|
||||
StorytellerStudioImageGen,
|
||||
|
||||
#[serde(rename = "vst")]
|
||||
VideoStyleTransfer,
|
||||
|
||||
@@ -93,6 +96,7 @@ impl MediaFileOriginModelType {
|
||||
Self::MocapNet => "mocap_net",
|
||||
Self::StyleTTS2 => "styletts2",
|
||||
Self::StableDiffusion15 => "stable_diffusion_1_5",
|
||||
Self::StorytellerStudioImageGen => "studio_ig",
|
||||
Self::GptSovits => "gpt_sovits",
|
||||
Self::StorytellerStudio => "studio",
|
||||
Self::VideoStyleTransfer => "vst",
|
||||
@@ -115,6 +119,7 @@ impl MediaFileOriginModelType {
|
||||
"mocap_net" => Ok(Self::MocapNet),
|
||||
"styletts2" => Ok(Self::StyleTTS2),
|
||||
"stable_diffusion_1_5" => Ok(Self::StableDiffusion15),
|
||||
"studio_ig" => Ok(Self::StorytellerStudioImageGen),
|
||||
"gpt_sovits" => Ok(Self::GptSovits),
|
||||
"studio" => Ok(Self::StorytellerStudio),
|
||||
"vst" => Ok(Self::VideoStyleTransfer),
|
||||
@@ -142,6 +147,7 @@ impl MediaFileOriginModelType {
|
||||
Self::StableDiffusion15,
|
||||
Self::GptSovits,
|
||||
Self::StorytellerStudio,
|
||||
Self::StorytellerStudioImageGen,
|
||||
Self::VideoStyleTransfer,
|
||||
Self::ComfyUi,
|
||||
Self::VallEX,
|
||||
|
||||
@@ -13,11 +13,11 @@ name = "enums_public"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
normal = ["my-workspace-hack"]
|
||||
normal = ["workspace-build-acceleration"]
|
||||
|
||||
[dependencies]
|
||||
# Workspace hack (faster compile times)
|
||||
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
|
||||
workspace-build-acceleration = { version = "0.1", path = "../../workspace-build-acceleration" }
|
||||
|
||||
# Internal
|
||||
enums = { path = "../enums" }
|
||||
|
||||
@@ -91,6 +91,10 @@ pub enum PublicInferenceJobType {
|
||||
/// Re-render a video is a video style transfer algorithm. We developed code
|
||||
/// around it, but chose to develop AnimateDiff / ComfyUI support instead.
|
||||
RerenderAVideo,
|
||||
|
||||
/// Sora GPT 4o image gen
|
||||
#[serde(rename = "image_gen_api")]
|
||||
ImageGenApi,
|
||||
}
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
@@ -119,6 +123,7 @@ impl PublicInferenceJobType {
|
||||
InferenceJobType::Unknown => Self::Unknown,
|
||||
InferenceJobType::BevyToWorkflow => Self::BevyToWorkflow,
|
||||
InferenceJobType::RerenderAVideo => Self::RerenderAVideo,
|
||||
InferenceJobType::ImageGenApi => Self::ImageGenApi,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,6 +145,7 @@ impl PublicInferenceJobType {
|
||||
Self::SeedVc => InferenceJobType::SeedVc,
|
||||
Self::SoVitsSvc => InferenceJobType::SoVitsSvc,
|
||||
Self::StableDiffusion => InferenceJobType::StableDiffusion,
|
||||
Self::ImageGenApi => InferenceJobType::ImageGenApi,
|
||||
Self::StyleTTS2 => InferenceJobType::StyleTTS2,
|
||||
Self::Tacotron2 => InferenceJobType::Tacotron2,
|
||||
Self::Unknown => InferenceJobType::Unknown,
|
||||
|
||||
@@ -64,6 +64,10 @@ pub enum PublicMediaFileModelType {
|
||||
#[serde(rename = "studio")]
|
||||
StorytellerStudio,
|
||||
|
||||
/// NB: This is GPT4o image generation
|
||||
#[serde(rename = "studio_ig")]
|
||||
StorytellerStudioImageGen,
|
||||
|
||||
#[serde(rename = "vst")]
|
||||
VideoStyleTransfer,
|
||||
|
||||
@@ -89,6 +93,7 @@ impl PublicMediaFileModelType {
|
||||
MediaFileOriginModelType::LivePortrait => Self::FaceMirror,
|
||||
MediaFileOriginModelType::SadTalker => Self::FaceAnimator,
|
||||
MediaFileOriginModelType::StyleTTS2 => Self::VoiceDesigner,
|
||||
MediaFileOriginModelType::StorytellerStudioImageGen => Self::StorytellerStudioImageGen,
|
||||
// Conserved variants
|
||||
MediaFileOriginModelType::RvcV2 => Self::RvcV2,
|
||||
MediaFileOriginModelType::SoVitsSvc => Self::SoVitsSvc,
|
||||
@@ -113,6 +118,7 @@ impl PublicMediaFileModelType {
|
||||
Self::FaceAnimator => MediaFileOriginModelType::SadTalker,
|
||||
Self::Lipsync => MediaFileOriginModelType::FaceFusion,
|
||||
Self::VoiceDesigner => MediaFileOriginModelType::StyleTTS2,
|
||||
Self::StorytellerStudioImageGen => MediaFileOriginModelType::StorytellerStudioImageGen,
|
||||
// Conserved variants
|
||||
Self::RvcV2 => MediaFileOriginModelType::RvcV2,
|
||||
Self::SoVitsSvc => MediaFileOriginModelType::SoVitsSvc,
|
||||
|
||||
@@ -13,7 +13,7 @@ name = "reusable_types"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
normal = ["my-workspace-hack"]
|
||||
normal = ["workspace-build-acceleration"]
|
||||
|
||||
[dependencies]
|
||||
|
||||
@@ -21,7 +21,7 @@ normal = ["my-workspace-hack"]
|
||||
# (none)
|
||||
|
||||
# Workspace hack (faster compile times)
|
||||
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
|
||||
workspace-build-acceleration = { version = "0.1", path = "../../workspace-build-acceleration" }
|
||||
|
||||
# External
|
||||
chrono = { version = "0.4.22", features = ["serde"] }
|
||||
|
||||
@@ -13,7 +13,7 @@ name = "tokens"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
normal = ["my-workspace-hack"]
|
||||
normal = ["workspace-build-acceleration"]
|
||||
|
||||
[dependencies]
|
||||
|
||||
@@ -21,7 +21,7 @@ normal = ["my-workspace-hack"]
|
||||
# (none)
|
||||
|
||||
# Workspace hack (faster compile times)
|
||||
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
|
||||
workspace-build-acceleration = { version = "0.1", path = "../../workspace-build-acceleration" }
|
||||
|
||||
# Serialization
|
||||
serde = "1.0.125"
|
||||
|
||||
@@ -13,7 +13,7 @@ name = "dev-database-seed"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
normal = ["my-workspace-hack"]
|
||||
normal = ["workspace-build-acceleration"]
|
||||
|
||||
[dependencies]
|
||||
# Internal
|
||||
@@ -32,7 +32,7 @@ storyteller_root = { path = "../../../lib/storyteller_root" }
|
||||
tokens = { path = "../../../_types/tokens" }
|
||||
|
||||
# Workspace hack (faster compile times)
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
workspace-build-acceleration = { version = "0.1", path = "../../../workspace-build-acceleration" }
|
||||
|
||||
# External
|
||||
log = "0.4.14"
|
||||
|
||||
@@ -13,7 +13,7 @@ name = "dev-upload-media-file"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
normal = ["my-workspace-hack"]
|
||||
normal = ["workspace-build-acceleration"]
|
||||
|
||||
[dependencies]
|
||||
# Internal
|
||||
@@ -29,7 +29,7 @@ mysql_queries = { path = "../../../lib/mysql_queries" }
|
||||
tokens = { path = "../../../_types/tokens" }
|
||||
|
||||
# Workspace hack (faster compile times)
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
workspace-build-acceleration = { version = "0.1", path = "../../../workspace-build-acceleration" }
|
||||
|
||||
# External
|
||||
clap = "4.4.8"
|
||||
|
||||
@@ -13,7 +13,7 @@ name = "scrape-test"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
normal = ["my-workspace-hack"]
|
||||
normal = ["workspace-build-acceleration"]
|
||||
|
||||
[dependencies]
|
||||
|
||||
@@ -22,7 +22,7 @@ errors = { path = "../../../lib/errors" }
|
||||
web_scrapers = { path = "../../../lib/web_scrapers" }
|
||||
|
||||
# Workspace hack (faster compile times)
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
workspace-build-acceleration = { version = "0.1", path = "../../../workspace-build-acceleration" }
|
||||
|
||||
# External
|
||||
clap = "4.4.8"
|
||||
|
||||
@@ -13,11 +13,11 @@ name = "db-backfill"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
normal = ["my-workspace-hack"]
|
||||
normal = ["workspace-build-acceleration"]
|
||||
|
||||
[dependencies]
|
||||
# Workspace hack (faster compile times)
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
workspace-build-acceleration = { version = "0.1", path = "../../../workspace-build-acceleration" }
|
||||
|
||||
# Internal
|
||||
datetimes = { path = "../../../lib/data/datetimes" }
|
||||
|
||||
@@ -13,7 +13,7 @@ name = "db-backup"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
normal = ["my-workspace-hack"]
|
||||
normal = ["workspace-build-acceleration"]
|
||||
|
||||
[dependencies]
|
||||
# Internal
|
||||
@@ -21,7 +21,7 @@ easyenv = { path = "../../../lib/easyenv" }
|
||||
errors = { path = "../../../lib/errors" }
|
||||
|
||||
# Workspace hack (faster compile times)
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
workspace-build-acceleration = { version = "0.1", path = "../../../workspace-build-acceleration" }
|
||||
|
||||
# External
|
||||
anyhow = "1.0.86"
|
||||
|
||||
@@ -13,7 +13,7 @@ name = "db-cleanup"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
normal = ["my-workspace-hack"]
|
||||
normal = ["workspace-build-acceleration"]
|
||||
|
||||
[dependencies]
|
||||
# Internal
|
||||
@@ -26,7 +26,7 @@ storyteller_root = { path = "../../../lib/storyteller_root" }
|
||||
tokens = { path = "../../../_types/tokens" }
|
||||
|
||||
# Workspace hack (faster compile times)
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
workspace-build-acceleration = { version = "0.1", path = "../../../workspace-build-acceleration" }
|
||||
|
||||
# External
|
||||
clap = "4.4.8"
|
||||
|
||||
@@ -13,7 +13,7 @@ name = "elasticsearch-cli"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
normal = ["my-workspace-hack"]
|
||||
normal = ["workspace-build-acceleration"]
|
||||
|
||||
[dependencies]
|
||||
# Internal
|
||||
@@ -29,7 +29,7 @@ storyteller_root = { path = "../../../lib/storyteller_root" }
|
||||
tokens = { path = "../../../_types/tokens" }
|
||||
|
||||
# Workspace hack (faster compile times)
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
workspace-build-acceleration = { version = "0.1", path = "../../../workspace-build-acceleration" }
|
||||
|
||||
# External
|
||||
clap = "4.4.8"
|
||||
|
||||
@@ -13,7 +13,7 @@ name = "kubectl-pod-cleanup"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
normal = ["my-workspace-hack"]
|
||||
normal = ["workspace-build-acceleration"]
|
||||
|
||||
[dependencies]
|
||||
# Internal
|
||||
@@ -22,7 +22,7 @@ easyenv = { path = "../../../lib/easyenv" }
|
||||
errors = { path = "../../../lib/errors" }
|
||||
|
||||
# Workspace hack (faster compile yytimes)
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
workspace-build-acceleration = { version = "0.1", path = "../../../workspace-build-acceleration" }
|
||||
|
||||
# External
|
||||
log = "0.4.20"
|
||||
|
||||
@@ -13,7 +13,7 @@ name = "lru-delete-models"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
normal = ["my-workspace-hack"]
|
||||
normal = ["workspace-build-acceleration"]
|
||||
|
||||
[dependencies]
|
||||
# Internal
|
||||
@@ -21,7 +21,7 @@ errors = { path = "../../../lib/errors" }
|
||||
logging = { path = "../../../lib/logging" }
|
||||
|
||||
# Workspace hack (faster compile times)
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
workspace-build-acceleration = { version = "0.1", path = "../../../workspace-build-acceleration" }
|
||||
|
||||
# External
|
||||
clap = { version = "4.4.8", features = ["derive"] }
|
||||
|
||||
@@ -13,7 +13,7 @@ name = "migration-tool"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
normal = ["my-workspace-hack"]
|
||||
normal = ["workspace-build-acceleration"]
|
||||
|
||||
[dependencies]
|
||||
# Internal
|
||||
@@ -30,7 +30,7 @@ storyteller_root = { path = "../../../lib/storyteller_root" }
|
||||
tokens = { path = "../../../_types/tokens" }
|
||||
|
||||
# Workspace hack (faster compile times)
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
workspace-build-acceleration = { version = "0.1", path = "../../../workspace-build-acceleration" }
|
||||
|
||||
# External
|
||||
clap = "4.4.8"
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
[package]
|
||||
name = "artcraft"
|
||||
version = "0.1.0"
|
||||
description = "Artcraft"
|
||||
authors = ["you"]
|
||||
license = ""
|
||||
repository = ""
|
||||
edition = "2021"
|
||||
rust-version = "1.77.2"
|
||||
publish = false
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[lib]
|
||||
name = "app_lib"
|
||||
crate-type = ["staticlib", "cdylib", "rlib"]
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build = { version = "2.1.1", features = [] }
|
||||
|
||||
[dependencies]
|
||||
# Workspace hack (faster compile times)
|
||||
workspace-build-acceleration = { workspace = true }
|
||||
|
||||
# Internal
|
||||
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 = { workspace = true }
|
||||
base64 = "0.22.1"
|
||||
bytes = "1.10"
|
||||
chrono = { workspace = true }
|
||||
const_format = "0.2.34"
|
||||
directories = "6.0.0"
|
||||
dirs = "6.0.0"
|
||||
futures = "0.3"
|
||||
image = "0.25.5"
|
||||
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 = ["unstable"] }
|
||||
tauri-plugin-log = "2.3.1"
|
||||
tempdir = "0.3.7"
|
||||
tempfile = "3.18.0"
|
||||
tokio = { version = "1.42", features = ["rt", "rt-multi-thread", "fs"] }
|
||||
tokio-util = { version = "0.7", features = ["codec"] }
|
||||
|
||||
[dev-dependencies]
|
||||
libloading = "0.8.6"
|
||||
serial_test = "3.2.0"
|
||||
assertor = "0.0.3"
|
||||
|
||||
[profile.dev]
|
||||
incremental = true # Compile your binary in smaller steps.
|
||||
|
||||
[profile.release]
|
||||
codegen-units = 1 # Allows LLVM to perform better optimization.
|
||||
lto = true # Enables link-time-optimizations.
|
||||
opt-level = 3 # `s` prioritizes small binary size. Use `3` if you prefer speed.
|
||||
panic = "abort" # Higher performance by disabling panic handlers.
|
||||
strip = true # Ensures debug symbols are removed.
|
||||
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 9.0 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 7.4 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 49 KiB |
@@ -0,0 +1,90 @@
|
||||
use std::fs::read_to_string;
|
||||
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 tauri::{AppHandle, Manager, State};
|
||||
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;
|
||||
use crate::state::app_dir::AppDataRoot;
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn image_generation_command(
|
||||
image: &str,
|
||||
prompt: &str,
|
||||
app: AppHandle,
|
||||
app_data_root: State<'_, AppDataRoot>,
|
||||
) -> 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, &app_data_root)
|
||||
.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, app_data_root: &AppDataRoot) -> AnyhowResult<()> {
|
||||
let sora_credentials = get_credentials(app_data_root)?;
|
||||
|
||||
let filename = "image.png".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(())
|
||||
}
|
||||
|
||||
fn get_credentials(app_data_root: &AppDataRoot) -> AnyhowResult<SoraCredentials> {
|
||||
let cookie_file = app_data_root.get_sora_cookie_file_path();
|
||||
|
||||
let bearer = read_to_string("/Users/bt/dev/storyteller/storyteller-rust/test_data/temp/bearer.txt")?
|
||||
.trim()
|
||||
.to_string();
|
||||
|
||||
let cookie= read_to_string(cookie_file)?
|
||||
.trim()
|
||||
.to_string();
|
||||
|
||||
let sentinel = read_to_string("/Users/bt/dev/storyteller/storyteller-rust/test_data/temp/sentinel.txt")?
|
||||
.trim()
|
||||
.to_string();
|
||||
|
||||
Ok(SoraCredentials {
|
||||
bearer_token: bearer,
|
||||
cookie: cookie,
|
||||
sentinel: Some(sentinel),
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
pub mod flip_image;
|
||||
pub mod image_generation_command;
|
||||
pub mod open_login_command;
|
||||
@@ -0,0 +1,72 @@
|
||||
use std::time::Duration;
|
||||
use log::{error, info};
|
||||
use once_cell::sync::Lazy;
|
||||
use tauri::{AppHandle, Manager, Url, WebviewUrl, WebviewWindowBuilder, WindowBuilder};
|
||||
use tokio::time::sleep_until;
|
||||
use errors::AnyhowResult;
|
||||
use crate::threads::login_thread::{LOGIN_WINDOW_NAME, SORA_LOGIN_URL};
|
||||
use crate::utils::clear_all_webview_cookies::clear_all_webview_cookies;
|
||||
|
||||
pub const START_URL_STR: &str = "https://storyteller.ai/";
|
||||
|
||||
pub static START_URL: Lazy<Url> = Lazy::new(|| {
|
||||
Url::parse(START_URL_STR).expect("URL should parse")
|
||||
});
|
||||
|
||||
pub const SORA_HOMEPAGE_URL_STR: &str = "https://sora.com/";
|
||||
|
||||
pub static SORA_HOMEPAGE_URL : Lazy<Url> = Lazy::new(|| {
|
||||
Url::parse(SORA_HOMEPAGE_URL_STR).expect("URL should parse")
|
||||
});
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn open_login_command(
|
||||
app: AppHandle,
|
||||
) -> Result<String, String> {
|
||||
info!("open_login_command called");
|
||||
|
||||
do_open_login(&app)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
error!("Error opening login: {:?}", err);
|
||||
format!("Error opening login: {:?}", err)
|
||||
})?;
|
||||
|
||||
Ok("result".to_string())
|
||||
}
|
||||
|
||||
async fn do_open_login(app: &AppHandle) -> AnyhowResult<()> {
|
||||
info!("Building login window...");
|
||||
|
||||
let url = WebviewUrl::External(START_URL.clone());
|
||||
|
||||
let window = WebviewWindowBuilder::new(app, LOGIN_WINDOW_NAME, url)
|
||||
//.user_agent(openai_sora_client::credentials::USER_AGENT)
|
||||
.always_on_top(true)
|
||||
.title("Login to OpenAI")
|
||||
.center()
|
||||
.resizable(true)
|
||||
.visible(true)
|
||||
.closable(true)
|
||||
.focused(true)
|
||||
.devtools(true)
|
||||
.build()?;
|
||||
|
||||
for (name, webview) in window.webviews() {
|
||||
if name != LOGIN_WINDOW_NAME {
|
||||
continue;
|
||||
}
|
||||
|
||||
clear_all_webview_cookies(&webview)?;
|
||||
|
||||
// NB: We're starting to get Cloudflare protection screens. Let's try to avoid.
|
||||
webview.navigate(SORA_HOMEPAGE_URL.clone())?;
|
||||
tokio::time::sleep(Duration::from_millis(100)).await;
|
||||
|
||||
webview.navigate(SORA_LOGIN_URL.clone())?;
|
||||
break;
|
||||
}
|
||||
|
||||
info!("Done.");
|
||||
Ok(())
|
||||
}
|
||||
@@ -8,6 +8,9 @@ pub enum NotificationModelType {
|
||||
TextTokenizer,
|
||||
Unet,
|
||||
Vae,
|
||||
Json,
|
||||
ClipEncoder,
|
||||
FluxModel,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize)]
|
||||
@@ -26,5 +29,17 @@ pub enum NotificationEvent<'a> {
|
||||
ModelDownloadComplete {
|
||||
model_name: &'a str,
|
||||
model_type: NotificationModelType,
|
||||
}
|
||||
},
|
||||
ModelLoading {
|
||||
model_name: String,
|
||||
model_type: NotificationModelType,
|
||||
},
|
||||
ModelInference {
|
||||
model_name: String,
|
||||
model_type: NotificationModelType,
|
||||
},
|
||||
ModelInferenceComplete {
|
||||
model_name: String,
|
||||
model_type: NotificationModelType,
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
pub mod commands;
|
||||
pub mod events;
|
||||
pub mod state;
|
||||
pub mod threads;
|
||||
pub mod transfer;
|
||||
pub mod utils;
|
||||
|
||||
use crate::commands::flip_image::flip_image;
|
||||
use crate::commands::image_generation_command::image_generation_command;
|
||||
use crate::commands::open_login_command::open_login_command;
|
||||
use crate::state::app_config::AppConfig;
|
||||
use crate::threads::login_thread::login_thread;
|
||||
|
||||
use tauri_plugin_log::Target;
|
||||
use tauri_plugin_log::TargetKind;
|
||||
|
||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||
pub fn run() {
|
||||
// NB: Tauri wants to install the logger itself, so we can't rely on the logger crate
|
||||
// until the tauri runtime begins.
|
||||
println!("Loading model config...");
|
||||
|
||||
let config = AppConfig::init()
|
||||
.expect("config should load");
|
||||
|
||||
let app_data_root = config.app_data_root.clone();
|
||||
let app_data_root2 = config.app_data_root.clone();
|
||||
|
||||
println!("Initializing backend runtime...");
|
||||
|
||||
tauri::Builder::default()
|
||||
.plugin(tauri_plugin_log::Builder::new()
|
||||
.level(log::LevelFilter::Info)
|
||||
.targets(vec![
|
||||
Target::new(TargetKind::Stdout),
|
||||
Target::new(TargetKind::LogDir { file_name: Some(app_data_root.log_file_name_str().to_string()) }),
|
||||
])
|
||||
.build())
|
||||
.setup(|app| {
|
||||
// TODO(bt): This is broken on windows
|
||||
// log_environment_details();
|
||||
|
||||
//if cfg!(debug_assertions) {
|
||||
// app.handle().plugin(
|
||||
// tauri_plugin_log::Builder::default()
|
||||
// .level(log::LevelFilter::Info)
|
||||
// .build(),
|
||||
// )?;
|
||||
//}
|
||||
let app = app.handle().clone();
|
||||
|
||||
tauri::async_runtime::spawn(login_thread(app, app_data_root2));
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.manage(config)
|
||||
.manage(app_data_root)
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
flip_image,
|
||||
image_generation_command,
|
||||
open_login_command,
|
||||
])
|
||||
.run(tauri::generate_context!("tauri.conf.json"))
|
||||
.expect("error while running tauri application");
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
|
||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||
|
||||
fn main() {
|
||||
app_lib::run();
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
use crate::state::app_dir::AppDataRoot;
|
||||
use crate::state::os_platform::OsPlatform;
|
||||
use crate::state::yaml_config::YamlConfig;
|
||||
|
||||
const DEFAULT_SD_IMAGE_WIDTH: usize = 1024;
|
||||
const DEFAULT_SD_IMAGE_HEIGHT: usize = 1024;
|
||||
|
||||
|
||||
/// A central place to configure app-wide details.
|
||||
pub struct AppConfig {
|
||||
pub image_height: usize,
|
||||
pub image_width: usize,
|
||||
pub scheduler_steps: usize,
|
||||
pub scheduler_samples: usize,
|
||||
|
||||
pub seed: Option<u64>,
|
||||
|
||||
pub cfg_scale: Option<f64>,
|
||||
|
||||
/// Root location for application data.
|
||||
pub app_data_root: AppDataRoot,
|
||||
}
|
||||
|
||||
impl AppConfig {
|
||||
|
||||
pub fn init() -> anyhow::Result<Self> {
|
||||
let yaml_configs = YamlConfig::load_from_config_file_recursive();
|
||||
|
||||
println!("Configs: {:?}", yaml_configs);
|
||||
|
||||
let os_platform = OsPlatform::get();
|
||||
|
||||
let default_data_root = match os_platform {
|
||||
OsPlatform::Linux => yaml_configs.linux_default_data_path.as_deref(),
|
||||
OsPlatform::MacOs => yaml_configs.mac_default_data_path.as_deref(),
|
||||
OsPlatform::Windows => yaml_configs.windows_default_data_path.as_deref(),
|
||||
};
|
||||
|
||||
println!("Possible user-defined data root: {:?}", default_data_root);
|
||||
|
||||
let app_data_root = match default_data_root {
|
||||
None => AppDataRoot::create_default()?,
|
||||
Some(path) => AppDataRoot::create_existing(path)?,
|
||||
};
|
||||
|
||||
println!("App data root: {:?}", app_data_root.path());
|
||||
|
||||
Ok(Self {
|
||||
image_height: yaml_configs.image_height.unwrap_or(DEFAULT_SD_IMAGE_HEIGHT),
|
||||
image_width: yaml_configs.image_width.unwrap_or(DEFAULT_SD_IMAGE_WIDTH),
|
||||
scheduler_steps: yaml_configs.scheduler_steps.unwrap_or(4),
|
||||
scheduler_samples: yaml_configs.scheduler_samples.unwrap_or(15),
|
||||
seed: yaml_configs.seed,
|
||||
cfg_scale: yaml_configs.cfg_scale,
|
||||
app_data_root,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
use crate::state::expanduser::expanduser;
|
||||
use crate::state::os_platform::OsPlatform;
|
||||
use anyhow::anyhow;
|
||||
use directories::UserDirs;
|
||||
use std::path::{Path, PathBuf};
|
||||
use chrono::{DateTime, Local};
|
||||
use tempdir::TempDir;
|
||||
use tempfile::{Builder, NamedTempFile};
|
||||
|
||||
const DEFAULT_DATA_DIR : &str = "artcraft";
|
||||
const ASSETS_SUBDIRECTORY : &str = "assets";
|
||||
const WEIGHTS_SUBDIRECTORY : &str = "weights";
|
||||
|
||||
const TEMPORARY_SUBDIRECTORY : &str = "temp";
|
||||
|
||||
/// Note: Tauri appends ".log" to the end of the filename.
|
||||
const LOG_FILE_NAME : &str = "application_debug";
|
||||
|
||||
/// The path to the application data directory, which includes "asset" and "weights" data.
|
||||
#[derive(Clone)]
|
||||
pub struct AppDataRoot {
|
||||
path: PathBuf,
|
||||
assets_dir: AppAssetsDir,
|
||||
weights_dir: AppWeightsDir,
|
||||
temp_dir: TemporaryDir,
|
||||
log_file_name: PathBuf,
|
||||
log_file_name_string: String,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AppAssetsDir {
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AppWeightsDir {
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct TemporaryDir {
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
impl AppDataRoot {
|
||||
pub fn create_default() -> anyhow::Result<Self> {
|
||||
let directory = get_default_data_dir()?;
|
||||
Self::create_existing(directory)
|
||||
}
|
||||
|
||||
pub fn create_existing<P: AsRef<Path>>(dir: P) -> anyhow::Result<Self> {
|
||||
let mut dir = dir.as_ref().to_path_buf();
|
||||
|
||||
match OsPlatform::get() {
|
||||
OsPlatform::Linux | OsPlatform::MacOs => {
|
||||
if let Some(d) = dir.as_os_str().to_str() {
|
||||
dir = expanduser(d)?;
|
||||
}
|
||||
},
|
||||
OsPlatform::Windows => {}
|
||||
}
|
||||
|
||||
if !dir.is_dir() {
|
||||
println!("Creating directory {:?}", dir);
|
||||
std::fs::create_dir_all(&dir)?;
|
||||
}
|
||||
|
||||
match dir.canonicalize() {
|
||||
Ok(d) => dir = d,
|
||||
Err(err) => {
|
||||
println!("Error canonicalizing {:?}: {}", dir, err);
|
||||
}
|
||||
}
|
||||
|
||||
let assets_dir = AppAssetsDir::create_existing(dir.join(ASSETS_SUBDIRECTORY))?;
|
||||
let weights_dir = AppWeightsDir::create_existing(dir.join(WEIGHTS_SUBDIRECTORY))?;
|
||||
let temp_dir = TemporaryDir::create_existing(dir.join(TEMPORARY_SUBDIRECTORY))?;
|
||||
let log_file_name = dir.join(LOG_FILE_NAME);
|
||||
let log_file_name_string = log_file_name
|
||||
.to_str()
|
||||
.ok_or(anyhow!("couldn't convert log path to str"))?
|
||||
.to_string();
|
||||
|
||||
Ok(Self {
|
||||
path: dir,
|
||||
assets_dir,
|
||||
weights_dir,
|
||||
temp_dir,
|
||||
log_file_name,
|
||||
log_file_name_string,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn assets_dir(&self) -> &AppAssetsDir {
|
||||
&self.assets_dir
|
||||
}
|
||||
|
||||
pub fn weights_dir(&self) -> &AppWeightsDir {
|
||||
&self.weights_dir
|
||||
}
|
||||
|
||||
pub fn temp_dir(&self) -> &TemporaryDir {
|
||||
&self.temp_dir
|
||||
}
|
||||
|
||||
pub fn path(&self) -> &Path {
|
||||
&self.path
|
||||
}
|
||||
|
||||
pub fn log_file_name(&self) -> &Path {
|
||||
&self.log_file_name
|
||||
}
|
||||
|
||||
pub fn log_file_name_str(&self) -> &str {
|
||||
&self.log_file_name_string
|
||||
}
|
||||
|
||||
pub fn get_sora_cookie_file_path(&self) -> PathBuf {
|
||||
self.path.join("sora_cookies.txt")
|
||||
}
|
||||
}
|
||||
|
||||
impl AppAssetsDir {
|
||||
pub fn create_existing<P: AsRef<Path>>(dir: P) -> anyhow::Result<Self> {
|
||||
let mut dir = dir.as_ref().to_path_buf();
|
||||
match dir.canonicalize() {
|
||||
Ok(d) => dir = d,
|
||||
Err(err) => {
|
||||
println!("Error canonicalizing {:?}: {}", dir, err);
|
||||
}
|
||||
}
|
||||
if !dir.exists() {
|
||||
println!("Creating directory {:?}", dir);
|
||||
std::fs::create_dir(&dir)?;
|
||||
}
|
||||
Ok(Self {
|
||||
path: dir,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn path(&self) -> &Path {
|
||||
&self.path
|
||||
}
|
||||
|
||||
/// Return the current date asset directory
|
||||
/// If it doesn't exist, create it.
|
||||
pub fn make_or_get_current_date_dir(&self) -> anyhow::Result<PathBuf> {
|
||||
let format: DateTime<Local> = Local::now();
|
||||
let date_directory_name = format.format("%Y-%d-%m").to_string();
|
||||
let full_path = self.path.join(date_directory_name);
|
||||
if !full_path.exists() {
|
||||
std::fs::create_dir(&full_path)?;
|
||||
}
|
||||
Ok(full_path)
|
||||
}
|
||||
}
|
||||
|
||||
impl AppWeightsDir {
|
||||
pub fn create_existing<P: AsRef<Path>>(dir: P) -> anyhow::Result<Self> {
|
||||
let mut dir = dir.as_ref().to_path_buf();
|
||||
match dir.canonicalize() {
|
||||
Ok(d) => dir = d,
|
||||
Err(err) => {
|
||||
println!("Error canonicalizing {:?}: {}", dir, err);
|
||||
}
|
||||
}
|
||||
if !dir.exists() {
|
||||
println!("Creating directory {:?}", dir);
|
||||
std::fs::create_dir(&dir)?;
|
||||
}
|
||||
Ok(Self {
|
||||
path: dir,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn path(&self) -> &Path {
|
||||
&self.path
|
||||
}
|
||||
}
|
||||
|
||||
impl TemporaryDir {
|
||||
pub fn create_existing<P: AsRef<Path>>(dir: P) -> anyhow::Result<Self> {
|
||||
let mut dir = dir.as_ref().to_path_buf();
|
||||
match dir.canonicalize() {
|
||||
Ok(d) => dir = d,
|
||||
Err(err) => {
|
||||
println!("Error canonicalizing {:?}: {}", dir, err);
|
||||
}
|
||||
}
|
||||
if !dir.exists() {
|
||||
println!("Creating directory {:?}", dir);
|
||||
std::fs::create_dir(&dir)?;
|
||||
}
|
||||
Ok(Self {
|
||||
path: dir,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn with_prefix(&self, prefix: &str) -> anyhow::Result<TempDir> {
|
||||
let tempdir = TempDir::new_in(&self.path, prefix)?;
|
||||
Ok(tempdir)
|
||||
}
|
||||
|
||||
pub fn new_named_temp_file(&self) -> anyhow::Result<NamedTempFile> {
|
||||
let tempfile = Builder::new()
|
||||
.prefix("temp_")
|
||||
.suffix(".bin")
|
||||
.tempfile_in(&self.path)?;
|
||||
Ok(tempfile)
|
||||
}
|
||||
}
|
||||
|
||||
// eg. /home/bob/artcraft, /Users/bob/artcraft, or C:\Users\Alice\artcraft
|
||||
fn get_default_data_dir() -> anyhow::Result<PathBuf> {
|
||||
Ok(UserDirs::new()
|
||||
.ok_or_else(|| anyhow!("could not determine user home directory"))?
|
||||
.home_dir()
|
||||
.join(DEFAULT_DATA_DIR))
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
use std::fs::OpenOptions;
|
||||
use std::io::Write;
|
||||
use anyhow::anyhow;
|
||||
use log::{error, info};
|
||||
use once_cell::sync::Lazy;
|
||||
use reqwest::Url;
|
||||
use tauri::{AppHandle, Manager, Webview};
|
||||
use errors::AnyhowResult;
|
||||
use crate::state::app_dir::AppDataRoot;
|
||||
use crate::utils::sora_webview_cookies::get_all_sora_cookies_as_string;
|
||||
|
||||
pub const LOGIN_WINDOW_NAME: &str = "login_window";
|
||||
|
||||
pub const SORA_LOGIN_URL_STR: &str = "https://sora.com/auth/login?callback_path=/";
|
||||
|
||||
pub static SORA_LOGIN_URL: Lazy<Url> = Lazy::new(|| {
|
||||
Url::parse(SORA_LOGIN_URL_STR).expect("URL should parse")
|
||||
});
|
||||
|
||||
pub const SORA_ROOT_URL_STR: &str = "https://sora.com/";
|
||||
|
||||
pub static SORA_ROOT_URL: Lazy<Url> = Lazy::new(|| {
|
||||
Url::parse(SORA_ROOT_URL_STR).expect("URL should parse")
|
||||
});
|
||||
|
||||
pub async fn login_thread(app: AppHandle, app_data_root: AppDataRoot) -> ! {
|
||||
loop {
|
||||
for (window_name, webview) in app.webviews() {
|
||||
if window_name == LOGIN_WINDOW_NAME {
|
||||
let result = check_login_window(&webview, &app_data_root).await;
|
||||
if let Err(err) = result {
|
||||
error!("Error checking login window: {:?}", err);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
tokio::time::sleep(std::time::Duration::from_millis(2_000)).await;
|
||||
}
|
||||
}
|
||||
|
||||
async fn check_login_window(webview: &Webview, app_data_root: &AppDataRoot) -> AnyhowResult<()> {
|
||||
clear_browsing_data_on_test_domain(webview)?;
|
||||
//keep_on_task(webview)?;
|
||||
extract_cookies_to_file(webview, app_data_root)?;
|
||||
// TODO: Other maintenance tasks ...
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn keep_on_task(webview: &Webview) -> AnyhowResult<()> {
|
||||
let url = webview.url()?;
|
||||
let hostname= url.host()
|
||||
.ok_or(anyhow!("no host in url"))?
|
||||
.to_string();
|
||||
match hostname.as_str() {
|
||||
"auth.openai.com" => {},
|
||||
"openai.com" => {},
|
||||
"sora.com" => {},
|
||||
// Third party SSO
|
||||
"accounts.google.com" => {},
|
||||
"accounts.youtube.com" => {},
|
||||
"login.live.com" => {},
|
||||
"appleid.apple.com" => {},
|
||||
_ => {
|
||||
info!("Non login hostname: {}", hostname);
|
||||
webview.navigate(SORA_LOGIN_URL.clone())?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// This is just so we have a way to clear browsing data.
|
||||
fn clear_browsing_data_on_test_domain(webview: &Webview) -> AnyhowResult<()> {
|
||||
let url = webview.url()?;
|
||||
let hostname= url.host()
|
||||
.ok_or(anyhow!("no host in url"))?
|
||||
.to_string();
|
||||
match hostname.as_str() {
|
||||
"storyteller.ai" => {
|
||||
info!("Clearing all browsing data...");
|
||||
webview.clear_all_browsing_data()?;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// TODO(bt,2025-04-07): Heuristic to detect when logged in. Only write when logged in.
|
||||
fn extract_cookies_to_file(webview: &Webview, app_data_root: &AppDataRoot) -> AnyhowResult<()> {
|
||||
let cookies = get_all_sora_cookies_as_string(webview)?;
|
||||
|
||||
let cookie_file = app_data_root.get_sora_cookie_file_path();
|
||||
|
||||
let mut file = OpenOptions::new()
|
||||
.create(true)
|
||||
.write(true)
|
||||
.truncate(true)
|
||||
.open(cookie_file)?;
|
||||
|
||||
file.write_all(cookies.as_bytes())?;
|
||||
file.flush()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
pub mod login_thread;
|
||||
@@ -0,0 +1,7 @@
|
||||
use tauri::Webview;
|
||||
use errors::AnyhowResult;
|
||||
|
||||
pub fn clear_all_webview_cookies(webview: &Webview) -> AnyhowResult<()> {
|
||||
webview.clear_all_browsing_data()?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
pub mod clear_all_webview_cookies;
|
||||
pub mod image;
|
||||
pub mod sora_webview_cookies;
|
||||
@@ -0,0 +1,26 @@
|
||||
use once_cell::sync::Lazy;
|
||||
use reqwest::Url;
|
||||
use tauri::Webview;
|
||||
use tauri::webview::Cookie;
|
||||
use errors::AnyhowResult;
|
||||
|
||||
const SORA_ROOT_COOKIE_URL_STR: &str = "https://sora.com/";
|
||||
|
||||
static SORA_ROOT_COOKIE_URL: Lazy<Url> = Lazy::new(|| {
|
||||
Url::parse(SORA_ROOT_COOKIE_URL_STR).expect("URL should parse")
|
||||
});
|
||||
|
||||
pub fn get_all_sora_cookies(webview: &Webview) -> AnyhowResult<Vec<Cookie>> {
|
||||
let cookies = webview.cookies_for_url(SORA_ROOT_COOKIE_URL.clone())?;
|
||||
Ok(cookies)
|
||||
}
|
||||
|
||||
pub fn get_all_sora_cookies_as_string(webview: &Webview) -> AnyhowResult<String> {
|
||||
let cookies = get_all_sora_cookies(webview)?;
|
||||
let cookie_string = cookies
|
||||
.iter()
|
||||
.map(|cookie| format!("{}={}", cookie.name(), cookie.value()))
|
||||
.collect::<Vec<String>>()
|
||||
.join("; ");
|
||||
Ok(cookie_string)
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"$schema": "https://schema.tauri.app/config/2.0.0-rc",
|
||||
"productName": "ArtCraft",
|
||||
"version": "0.1.0",
|
||||
"identifier": "com.unique.value.thing.why",
|
||||
"build": {
|
||||
"frontendDist": "../../../frontend/realtime/dist",
|
||||
"devUrl": "http://localhost:5174",
|
||||
"beforeDevCommand": "npm run dev",
|
||||
"beforeBuildCommand": "npm run build2"
|
||||
},
|
||||
"app": {
|
||||
"windows": [
|
||||
{
|
||||
"title": "ArtCraft",
|
||||
"width": 2400,
|
||||
"height": 1300,
|
||||
"resizable": true,
|
||||
"fullscreen": false
|
||||
}
|
||||
],
|
||||
"security": {
|
||||
"csp": null
|
||||
}
|
||||
},
|
||||
"bundle": {
|
||||
"active": true,
|
||||
"targets": "all",
|
||||
"icon": [
|
||||
"icons/32x32.png",
|
||||
"icons/128x128.png",
|
||||
"icons/128x128@2x.png",
|
||||
"icons/icon.icns",
|
||||
"icons/icon.ico"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
/target/
|
||||
/gen/schemas
|
||||
@@ -0,0 +1,4 @@
|
||||
# Don't restart the dev server on Rust changes
|
||||
crates/
|
||||
Cargo.toml
|
||||
Cargo.lock
|
||||
@@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "app"
|
||||
name = "tauri-realtime"
|
||||
version = "0.1.0"
|
||||
description = "A Tauri App"
|
||||
authors = ["you"]
|
||||
@@ -16,25 +16,30 @@ name = "app_lib"
|
||||
crate-type = ["staticlib", "cdylib", "rlib"]
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build = { version = "2.0.4", features = [] }
|
||||
tauri-build = { version = "2.1.1", features = [] }
|
||||
|
||||
[dependencies]
|
||||
|
||||
# Internal
|
||||
crockford = { path = "../../lib/data/crockford" }
|
||||
filesys = { path = "../../lib/files/filesys" }
|
||||
memory_caching = { path = "../../lib/caching/memory_caching" }
|
||||
ml_weights_registry = { path = "../ml_weights_registry" }
|
||||
ml_weights_registry = { path = "../../lib/machine_learning/ml_weights_registry" }
|
||||
primitives = { path = "../../lib/data/primitives" }
|
||||
|
||||
# Internal ML
|
||||
# TODO: Only on Windows and Linux
|
||||
#ml_models = { path = "../ml_models", optional = true }
|
||||
# Bypass cudarc issues on Windows https://github.com/coreylowman/cudarc/issues/332
|
||||
cudarc = { version = "0.13.5", features = ["std", "cublas", "cublaslt", "curand", "driver", "nvrtc", "f16", "cuda-version-from-build-system", "dynamic-linking"], default-features=false }
|
||||
|
||||
# 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"
|
||||
base64 = "0.22.1"
|
||||
bytes = "1.10"
|
||||
chrono = "0.4.40"
|
||||
const_format = "0.2.34"
|
||||
directories = "6.0.0"
|
||||
dirs = "6.0.0"
|
||||
@@ -43,14 +48,14 @@ half = { version = "2.3.1", features = ["num-traits", "use-intrinsics", "rand_di
|
||||
image = "0.25.5"
|
||||
log = "0.4"
|
||||
once_cell = "1.20.3"
|
||||
ort = { version = "1.16.2", features = ["cuda", "load-dynamic"] }
|
||||
rand = "0.8.5"
|
||||
# NB(bt,2025-03-10): default-features = false on Windows while I debug openssl / rustls
|
||||
reqwest = { version = "0.12.12", features = ["stream"], default-features = false }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
serde_yaml = "0.9"
|
||||
tauri = { version = "2.2.4", features = [] }
|
||||
tauri-plugin-log = "2"
|
||||
tauri = { version = "2.4.1", features = [] }
|
||||
tauri-plugin-log = "2.3.1"
|
||||
tempdir = "0.3.7"
|
||||
tempfile = "3.18.0"
|
||||
tokio = { version = "1.42", features = ["rt", "rt-multi-thread", "fs"] }
|
||||
@@ -59,7 +64,7 @@ tokio-util = { version = "0.7", features = ["codec"] }
|
||||
# tracing-subscriber = { version = "0.3", features = [ "env-filter", "fmt" ] }
|
||||
|
||||
[target.'cfg(not(target_os = "macos"))'.dependencies]
|
||||
ml_models = { path = "../ml_models" }
|
||||
ml_models = { path = "../../lib/machine_learning/ml_models" }
|
||||
|
||||
[dev-dependencies]
|
||||
libloading = "0.8.6"
|
||||
|
Before Width: | Height: | Size: 8.4 KiB After Width: | Height: | Size: 8.4 KiB |
@@ -0,0 +1,3 @@
|
||||
fn main() {
|
||||
tauri_build::build()
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"$schema": "../gen/schemas/desktop-schema.json",
|
||||
"identifier": "default",
|
||||
"description": "enables the default permissions",
|
||||
"windows": [
|
||||
"main"
|
||||
],
|
||||
"permissions": [
|
||||
"core:default",
|
||||
"log:default"
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 9.0 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 5.9 KiB |
|
After Width: | Height: | Size: 7.4 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 49 KiB |
@@ -0,0 +1,36 @@
|
||||
use base64::prelude::BASE64_STANDARD;
|
||||
use base64::Engine;
|
||||
use image::codecs::png::{CompressionType, FilterType, PngEncoder};
|
||||
use image::ImageReader;
|
||||
use std::io::Cursor;
|
||||
|
||||
#[tauri::command]
|
||||
pub fn flip_image(image: &str) -> Result<String, String> {
|
||||
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)
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
use log::info;
|
||||
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn inpaint_image(
|
||||
image: &str,
|
||||
mask: &str,
|
||||
prompt: String,
|
||||
) -> Result<String, String> {
|
||||
info!("inpaint_endpoint endpoint called.");
|
||||
|
||||
Ok(mask.to_string())
|
||||
}
|
||||