mirror of
https://github.com/storytold/artcraft.git
synced 2026-10-30 23:35:54 -04:00
Compare commits
24
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d181688d94 | ||
|
|
569622bcc0 | ||
|
|
7aad79d16b | ||
|
|
d70f8ac41e | ||
|
|
7097144e19 | ||
|
|
709af560a5 | ||
|
|
0f1cf93252 | ||
|
|
4a10581e9a | ||
|
|
447a70b890 | ||
|
|
f4e998d945 | ||
|
|
a954859ac2 | ||
|
|
2d8e835401 | ||
|
|
c23380af90 | ||
|
|
c34f75d071 | ||
|
|
8a886e9033 | ||
|
|
3101df8211 | ||
|
|
a4c264ebbf | ||
|
|
3d807fdeb2 | ||
|
|
b3a62cce64 | ||
|
|
42ccc25e4d | ||
|
|
6595518b35 | ||
|
|
618cbc8f0e | ||
|
|
b31a152c1a | ||
|
|
0e2169b902 |
+1
-1
@@ -48,7 +48,7 @@
|
||||
"name": "maybe_creator_anonymous_visitor_token: tokens::tokens::anonymous_visitor_tracking::AnonymousVisitorTrackingToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"flags": "MULTIPLE_KEY | BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
|
||||
Generated
+237
-2821
File diff suppressed because it is too large
Load Diff
+44
-29
@@ -4,13 +4,6 @@ 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",
|
||||
"crates/_types/enums",
|
||||
"crates/_types/enums_public",
|
||||
"crates/_types/reusable_types", # TODO(bt, 2022-12-21): Deprecate
|
||||
"crates/_types/tokens",
|
||||
|
||||
# CLI tools for operations, etc.
|
||||
"crates/cli/devenv/dev-database-seed",
|
||||
"crates/cli/devenv/dev-upload-media-file",
|
||||
@@ -39,6 +32,7 @@ members = [
|
||||
"crates/lib/api_clients/thumbnail_generator",
|
||||
"crates/lib/bootstrap",
|
||||
"crates/lib/bucket_paths",
|
||||
"crates/lib/build_metadata",
|
||||
"crates/lib/caching/memory_caching",
|
||||
"crates/lib/caching/memory_store",
|
||||
"crates/lib/caching/redis_caching",
|
||||
@@ -52,7 +46,6 @@ members = [
|
||||
"crates/lib/deprecated/http_server_common", # TODO(bt, 2023-03-20): Move useful pieces to actix_helpers
|
||||
"crates/lib/dimensions",
|
||||
"crates/lib/easyenv", # NB: Vendored version of https://github.com/echelon/easyenv.rs that we'll improve.
|
||||
"crates/lib/elasticsearch_schema",
|
||||
"crates/lib/email_sender",
|
||||
"crates/lib/errors",
|
||||
"crates/lib/files/archives",
|
||||
@@ -68,15 +61,11 @@ members = [
|
||||
"crates/lib/jobs_common",
|
||||
"crates/lib/jwt_light",
|
||||
"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/redis_common",
|
||||
"crates/lib/redis_schema",
|
||||
"crates/lib/server_environment",
|
||||
"crates/lib/shared_service_components",
|
||||
"crates/lib/sqlx_mysql_helpers",
|
||||
@@ -88,7 +77,21 @@ members = [
|
||||
"crates/lib/user_input_common",
|
||||
"crates/lib/web_scrapers",
|
||||
#"crates/lib/api_clients/fakeyou_client",
|
||||
#"crates/lib/sqlite_queries",
|
||||
#"crates/lib/machine_learning/ml_models",
|
||||
|
||||
# Schema (database): queries, database layouts, Redis keys, etc.
|
||||
"crates/schema/database/elasticsearch_schema",
|
||||
"crates/schema/database/mysql_queries",
|
||||
"crates/schema/database/redis_common",
|
||||
"crates/schema/database/redis_schema",
|
||||
#"crates/schema/database/sqlite_queries",
|
||||
|
||||
# Schema (public): common strongly-typed tokens, ids, payloads, etc.
|
||||
"crates/schema/public/composite_identifiers",
|
||||
"crates/schema/public/enums",
|
||||
"crates/schema/public/enums_public",
|
||||
"crates/schema/public/reusable_types", # TODO(bt, 2022-12-21): Deprecate
|
||||
"crates/schema/public/tokens",
|
||||
|
||||
# Services: API servers, jobs, workers, etc.
|
||||
"crates/service/job/analytics_job",
|
||||
@@ -109,19 +112,20 @@ members = [
|
||||
"crates/service/plugins/user_traits_component",
|
||||
|
||||
# Vendored code
|
||||
"crates/vendor/candle/candle-core",
|
||||
"crates/vendor/candle/candle-datasets",
|
||||
"crates/vendor/candle/candle-examples",
|
||||
"crates/vendor/candle/candle-flash-attn",
|
||||
"crates/vendor/candle/candle-kernels",
|
||||
"crates/vendor/candle/candle-metal-kernels",
|
||||
"crates/vendor/candle/candle-nn",
|
||||
"crates/vendor/candle/candle-onnx",
|
||||
"crates/vendor/candle/candle-pyo3",
|
||||
"crates/vendor/candle/candle-transformers",
|
||||
"crates/vendor/candle/tensor-tools",
|
||||
"crates/vendor/limitation",
|
||||
"crates/vendor/tauri-plugin-http",
|
||||
# NB(bt,2025-05-25): Too many failures on Mac. Disable for now.
|
||||
#"crates/vendor/candle/candle-core",
|
||||
#"crates/vendor/candle/candle-datasets",
|
||||
#"crates/vendor/candle/candle-examples",
|
||||
#"crates/vendor/candle/candle-flash-attn",
|
||||
#"crates/vendor/candle/candle-kernels",
|
||||
#"crates/vendor/candle/candle-metal-kernels",
|
||||
#"crates/vendor/candle/candle-nn",
|
||||
#"crates/vendor/candle/candle-onnx",
|
||||
#"crates/vendor/candle/candle-pyo3",
|
||||
#"crates/vendor/candle/candle-transformers",
|
||||
#"crates/vendor/candle/tensor-tools",
|
||||
# NB(bt,2023-12-12): Newrelic keeps breaking with upgrades. Kill for now.
|
||||
#"crates/vendor/newrelic-telemetry-sdk-rust",
|
||||
|
||||
@@ -161,6 +165,16 @@ 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
|
||||
actix = "0.13.5"
|
||||
actix-cors = "0.6.4" # TODO(bt): Carefully upgrade this. CORS broke last time.
|
||||
actix-http = "3.7.0"
|
||||
actix-multipart = "0.6.2"
|
||||
actix-rt = "2.10.0"
|
||||
actix-service = "2.0.3"
|
||||
actix-utils = "3.0.1"
|
||||
actix-web = "4.7.0" # TODO(bt): We're behind and need to bump versions.
|
||||
actix-web-actors = "4.3.1+deprecated"
|
||||
actix-web-lab = "0.20.2"
|
||||
anyhow = "1.0.98"
|
||||
base64 = "0.22.1"
|
||||
chrono = { version = "0.4.41", features = ["serde"] }
|
||||
@@ -176,18 +190,19 @@ 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"
|
||||
serde_yaml = "0.9.34+deprecated"
|
||||
sha3 = "0.10.8"
|
||||
tauri = { version = "2.4.1", features = ["unstable", "devtools"] } # NB: "devtools" prevents App Store distribution
|
||||
thiserror = "2.0.12"
|
||||
tokio = { version = "1.45.0", features = ["macros"] }
|
||||
tokio = { version = "1.45.1", features = ["macros"] }
|
||||
toml = "0.8.22"
|
||||
url = { version = "2.5.4", features = ["serde"] }
|
||||
|
||||
# Internal libs
|
||||
build_metadata = { path = "crates/lib/build_metadata" }
|
||||
crockford = { path = "crates/lib/data/crockford" }
|
||||
enums = { path = "crates/_types/enums" }
|
||||
enums_public = { path = "crates/_types/enums_public" }
|
||||
enums = { path = "crates/schema/public/enums" }
|
||||
enums_public = { path = "crates/schema/public/enums_public" }
|
||||
errors = { path = "crates/lib/errors" }
|
||||
fal_client = { path = "crates/lib/api_clients/fal_client" }
|
||||
filesys = { path = "crates/lib/files/filesys" }
|
||||
@@ -202,4 +217,4 @@ primitives = { path = "crates/lib/data/primitives" }
|
||||
shared_service_components = { path = "crates/lib/shared_service_components" }
|
||||
storyteller_client = { path = "crates/lib/api_clients/storyteller_client" }
|
||||
subprocess_common = { path = "crates/lib/subprocess_common" }
|
||||
tokens = { path = "crates/_types/tokens" }
|
||||
tokens = { path = "crates/schema/public/tokens" }
|
||||
|
||||
@@ -16,23 +16,23 @@ path = "src/main.rs"
|
||||
normal = ["workspace-build-acceleration"]
|
||||
|
||||
[dependencies]
|
||||
# Workspace hack (faster compile times)
|
||||
workspace-build-acceleration = { workspace = true }
|
||||
|
||||
# Internal
|
||||
bucket_paths = { path = "../../../lib/bucket_paths" }
|
||||
cloud_storage = { path = "../../../lib/api_clients/cloud_storage" }
|
||||
config = { path = "../../../lib/deprecated/config" }
|
||||
easyenv = { path = "../../../lib/easyenv" }
|
||||
enums = { path = "../../../_types/enums" }
|
||||
enums = { path = "../../../schema/public/enums" }
|
||||
errors = { path = "../../../lib/errors" }
|
||||
filesys = { path = "../../../lib/files/filesys" }
|
||||
hashing = { path = "../../../lib/files/hashing" }
|
||||
idempotency = { path = "../../../lib/idempotency" }
|
||||
mimetypes = { path = "../../../lib/files/mimetypes" }
|
||||
mysql_queries = { path = "../../../lib/mysql_queries" }
|
||||
mysql_queries = { path = "../../../schema/database/mysql_queries" }
|
||||
storyteller_root = { path = "../../../lib/storyteller_root" }
|
||||
tokens = { path = "../../../_types/tokens" }
|
||||
|
||||
# Workspace hack (faster compile times)
|
||||
workspace-build-acceleration = { version = "0.1", path = "../../../workspace-build-acceleration" }
|
||||
tokens = { path = "../../../schema/public/tokens" }
|
||||
|
||||
# External
|
||||
log = "0.4.14"
|
||||
|
||||
@@ -16,20 +16,20 @@ path = "src/main.rs"
|
||||
normal = ["workspace-build-acceleration"]
|
||||
|
||||
[dependencies]
|
||||
# Workspace hack (faster compile times)
|
||||
workspace-build-acceleration = { workspace = true }
|
||||
|
||||
# Internal
|
||||
bucket_paths = { path = "../../../lib/bucket_paths" }
|
||||
cloud_storage = { path = "../../../lib/api_clients/cloud_storage" }
|
||||
config = { path = "../../../lib/deprecated/config" }
|
||||
easyenv = { path = "../../../lib/easyenv" }
|
||||
enums = { path = "../../../_types/enums" }
|
||||
enums = { path = "../../../schema/public/enums" }
|
||||
errors = { path = "../../../lib/errors" }
|
||||
filesys = { path = "../../../lib/files/filesys" }
|
||||
mimetypes = { path = "../../../lib/files/mimetypes" }
|
||||
mysql_queries = { path = "../../../lib/mysql_queries" }
|
||||
tokens = { path = "../../../_types/tokens" }
|
||||
|
||||
# Workspace hack (faster compile times)
|
||||
workspace-build-acceleration = { version = "0.1", path = "../../../workspace-build-acceleration" }
|
||||
mysql_queries = { path = "../../../schema/database/mysql_queries" }
|
||||
tokens = { path = "../../../schema/public/tokens" }
|
||||
|
||||
# External
|
||||
clap = "4.4.8"
|
||||
|
||||
@@ -16,14 +16,13 @@ path = "src/main.rs"
|
||||
normal = ["workspace-build-acceleration"]
|
||||
|
||||
[dependencies]
|
||||
# Workspace hack (faster compile times)
|
||||
workspace-build-acceleration = { workspace = true }
|
||||
|
||||
# Internal
|
||||
errors = { path = "../../../lib/errors" }
|
||||
web_scrapers = { path = "../../../lib/web_scrapers" }
|
||||
|
||||
# Workspace hack (faster compile times)
|
||||
workspace-build-acceleration = { version = "0.1", path = "../../../workspace-build-acceleration" }
|
||||
|
||||
# External
|
||||
clap = "4.4.8"
|
||||
tokio = { version = "1.38.0", features = ["macros"] }
|
||||
|
||||
@@ -17,15 +17,15 @@ normal = ["workspace-build-acceleration"]
|
||||
|
||||
[dependencies]
|
||||
# Workspace hack (faster compile times)
|
||||
workspace-build-acceleration = { version = "0.1", path = "../../../workspace-build-acceleration" }
|
||||
workspace-build-acceleration = { workspace = true }
|
||||
|
||||
# Internal
|
||||
datetimes = { path = "../../../lib/data/datetimes" }
|
||||
easyenv = { path = "../../../lib/easyenv" }
|
||||
enums = { path = "../../../_types/enums" }
|
||||
enums = { path = "../../../schema/public/enums" }
|
||||
errors = { path = "../../../lib/errors" }
|
||||
mysql_queries = { path = "../../../lib/mysql_queries" }
|
||||
tokens = { path = "../../../_types/tokens" }
|
||||
mysql_queries = { path = "../../../schema/database/mysql_queries" }
|
||||
tokens = { path = "../../../schema/public/tokens" }
|
||||
|
||||
# External
|
||||
anyhow = "1.0.86"
|
||||
|
||||
@@ -16,20 +16,16 @@ path = "src/main.rs"
|
||||
normal = ["workspace-build-acceleration"]
|
||||
|
||||
[dependencies]
|
||||
# Workspace hack (faster compile times)
|
||||
workspace-build-acceleration = { workspace = true }
|
||||
|
||||
# Internal
|
||||
easyenv = { path = "../../../lib/easyenv" }
|
||||
errors = { path = "../../../lib/errors" }
|
||||
|
||||
# Workspace hack (faster compile times)
|
||||
workspace-build-acceleration = { version = "0.1", path = "../../../workspace-build-acceleration" }
|
||||
|
||||
# External
|
||||
anyhow = "1.0.86"
|
||||
# TODO/NB: Commenting out clap4 as it prevents windows builds
|
||||
# NB: clap4 = { package = "clap", version = "4.0" }
|
||||
dotenv = "0.15.0"
|
||||
log = "0.4.14"
|
||||
|
||||
# Serialization
|
||||
serde = "1.0.125"
|
||||
serde_derive = "1.0.125"
|
||||
|
||||
@@ -16,17 +16,17 @@ path = "src/main.rs"
|
||||
normal = ["workspace-build-acceleration"]
|
||||
|
||||
[dependencies]
|
||||
# Workspace hack (faster compile times)
|
||||
workspace-build-acceleration = { workspace = true }
|
||||
|
||||
# Internal
|
||||
bucket_paths = { path = "../../../lib/bucket_paths" }
|
||||
easyenv = { path = "../../../lib/easyenv" }
|
||||
enums = { path = "../../../_types/enums" }
|
||||
enums = { path = "../../../schema/public/enums" }
|
||||
errors = { path = "../../../lib/errors" }
|
||||
mysql_queries = { path = "../../../lib/mysql_queries" }
|
||||
mysql_queries = { path = "../../../schema/database/mysql_queries" }
|
||||
storyteller_root = { path = "../../../lib/storyteller_root" }
|
||||
tokens = { path = "../../../_types/tokens" }
|
||||
|
||||
# Workspace hack (faster compile times)
|
||||
workspace-build-acceleration = { version = "0.1", path = "../../../workspace-build-acceleration" }
|
||||
tokens = { path = "../../../schema/public/tokens" }
|
||||
|
||||
# External
|
||||
clap = "4.4.8"
|
||||
|
||||
@@ -16,20 +16,20 @@ path = "src/main.rs"
|
||||
normal = ["workspace-build-acceleration"]
|
||||
|
||||
[dependencies]
|
||||
# Workspace hack (faster compile times)
|
||||
workspace-build-acceleration = { workspace = true }
|
||||
|
||||
# Internal
|
||||
bucket_paths = { path = "../../../lib/bucket_paths" }
|
||||
config = { path = "../../../lib/deprecated/config" }
|
||||
easyenv = { path = "../../../lib/easyenv" }
|
||||
elasticsearch_schema = { path = "../../../lib/elasticsearch_schema" }
|
||||
enums = { path = "../../../_types/enums" }
|
||||
elasticsearch_schema = { path = "../../../schema/database/elasticsearch_schema" }
|
||||
enums = { path = "../../../schema/public/enums" }
|
||||
errors = { path = "../../../lib/errors" }
|
||||
mysql_queries = { path = "../../../lib/mysql_queries" }
|
||||
mysql_queries = { path = "../../../schema/database/mysql_queries" }
|
||||
primitives = { path = "../../../lib/data/primitives" }
|
||||
storyteller_root = { path = "../../../lib/storyteller_root" }
|
||||
tokens = { path = "../../../_types/tokens" }
|
||||
|
||||
# Workspace hack (faster compile times)
|
||||
workspace-build-acceleration = { version = "0.1", path = "../../../workspace-build-acceleration" }
|
||||
tokens = { path = "../../../schema/public/tokens" }
|
||||
|
||||
# External
|
||||
clap = "4.4.8"
|
||||
|
||||
@@ -16,14 +16,14 @@ path = "src/main.rs"
|
||||
normal = ["workspace-build-acceleration"]
|
||||
|
||||
[dependencies]
|
||||
# Workspace hack (faster compile yytimes)
|
||||
workspace-build-acceleration = { workspace = true }
|
||||
|
||||
# Internal
|
||||
config = { path = "../../../lib/deprecated/config" }
|
||||
easyenv = { path = "../../../lib/easyenv" }
|
||||
errors = { path = "../../../lib/errors" }
|
||||
|
||||
# Workspace hack (faster compile yytimes)
|
||||
workspace-build-acceleration = { version = "0.1", path = "../../../workspace-build-acceleration" }
|
||||
|
||||
# External
|
||||
log = "0.4.20"
|
||||
once_cell = "1.18.0"
|
||||
|
||||
@@ -16,13 +16,13 @@ path = "src/main.rs"
|
||||
normal = ["workspace-build-acceleration"]
|
||||
|
||||
[dependencies]
|
||||
# Workspace hack (faster compile times)
|
||||
workspace-build-acceleration = { workspace = true }
|
||||
|
||||
# Internal
|
||||
errors = { path = "../../../lib/errors" }
|
||||
logging = { path = "../../../lib/logging" }
|
||||
|
||||
# Workspace hack (faster compile times)
|
||||
workspace-build-acceleration = { version = "0.1", path = "../../../workspace-build-acceleration" }
|
||||
|
||||
# External
|
||||
clap = { version = "4.4.8", features = ["derive"] }
|
||||
walkdir = "2.4.0"
|
||||
|
||||
@@ -16,21 +16,21 @@ path = "src/main.rs"
|
||||
normal = ["workspace-build-acceleration"]
|
||||
|
||||
[dependencies]
|
||||
# Workspace hack (faster compile times)
|
||||
workspace-build-acceleration = { workspace = true }
|
||||
|
||||
# Internal
|
||||
bucket_paths = { path = "../../../lib/bucket_paths" }
|
||||
cloud_storage = { path = "../../../lib/api_clients/cloud_storage" }
|
||||
config = { path = "../../../lib/deprecated/config" }
|
||||
easyenv = { path = "../../../lib/easyenv" }
|
||||
enums = { path = "../../../_types/enums" }
|
||||
enums = { path = "../../../schema/public/enums" }
|
||||
errors = { path = "../../../lib/errors" }
|
||||
filesys = { path = "../../../lib/files/filesys" }
|
||||
hashing = { path = "../../../lib/files/hashing" }
|
||||
mysql_queries = { path = "../../../lib/mysql_queries" }
|
||||
mysql_queries = { path = "../../../schema/database/mysql_queries" }
|
||||
storyteller_root = { path = "../../../lib/storyteller_root" }
|
||||
tokens = { path = "../../../_types/tokens" }
|
||||
|
||||
# Workspace hack (faster compile times)
|
||||
workspace-build-acceleration = { version = "0.1", path = "../../../workspace-build-acceleration" }
|
||||
tokens = { path = "../../../schema/public/tokens" }
|
||||
|
||||
# External
|
||||
clap = "4.4.8"
|
||||
|
||||
@@ -23,17 +23,15 @@ tauri-build = { version = "2.1.1", features = [] }
|
||||
workspace-build-acceleration = { workspace = true }
|
||||
|
||||
# Internal
|
||||
crockford = { workspace = true }
|
||||
build_metadata = { workspace = true }
|
||||
errors = { workspace = true }
|
||||
fal_client = { workspace = true }
|
||||
filesys = { workspace = true }
|
||||
memory_caching = { workspace = true }
|
||||
memory_store = { workspace = true }
|
||||
mimetypes = { workspace = true }
|
||||
openai_sora_client = { workspace = true }
|
||||
primitives = { workspace = true }
|
||||
storyteller_client = { workspace = true }
|
||||
subprocess_common = { workspace = true }
|
||||
tokens = { workspace = true }
|
||||
|
||||
# External
|
||||
@@ -41,7 +39,6 @@ anyhow = { workspace = true }
|
||||
base64 = { workspace = true }
|
||||
bytes = "1.10"
|
||||
chrono = { workspace = true }
|
||||
const_format = "0.2.34"
|
||||
directories = "6.0.0"
|
||||
dirs = "6.0.0"
|
||||
futures = "0.3"
|
||||
@@ -54,7 +51,6 @@ reqwest = { workspace = true, features = ["multipart", "stream"], default-featur
|
||||
serde = { workspace = true }
|
||||
serde_derive = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
serde_yaml = { workspace = true }
|
||||
tauri = { workspace = true }
|
||||
tauri-plugin-log = "2.3.1"
|
||||
tauri-plugin-upload = "2.2.1"
|
||||
@@ -73,9 +69,7 @@ discord-rich-presence = { git = "https://github.com/vionya/discord-rich-presence
|
||||
tauri-plugin-dialog = "2"
|
||||
|
||||
[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.
|
||||
|
||||
@@ -6,6 +6,9 @@ use std::str::FromStr;
|
||||
pub type CommandResult<SuccessPayload, ErrType, ErrPayload> =
|
||||
Result<CommandSuccessResponseWrapper<SuccessPayload>, CommandErrorResponseWrapper<ErrType, ErrPayload>>;
|
||||
|
||||
/// Easy to use infallible response.
|
||||
pub type InfallibleResponse<SuccessPayload> = CommandSuccessResponseWrapper<SuccessPayload>;
|
||||
|
||||
/// No inner payloads for this type. Just strings as messages.
|
||||
pub type SimpleCommandResult = CommandResult<(), (), ()>;
|
||||
|
||||
|
||||
+196
@@ -0,0 +1,196 @@
|
||||
use crate::core::commands::command_response_wrapper::{CommandErrorResponseWrapper, CommandErrorStatus, CommandResult, SerializeMarker};
|
||||
use crate::core::commands::enqueue::image::handle_fal::handle_fal;
|
||||
use crate::core::commands::enqueue::image::handle_sora::handle_sora;
|
||||
use crate::core::commands::enqueue::image::internal_image_error::InternalImageError;
|
||||
use crate::core::events::sendable_event_trait::SendableEvent;
|
||||
use crate::core::state::data_dir::app_data_root::AppDataRoot;
|
||||
use crate::core::state::data_dir::trait_data_subdir::DataSubdir;
|
||||
use crate::core::utils::download_media_file_to_temp_dir::download_media_file_to_temp_dir;
|
||||
use crate::core::utils::get_url_file_extension::get_url_file_extension;
|
||||
use crate::core::utils::save_base64_image_to_temp_dir::save_base64_image_to_temp_dir;
|
||||
use crate::core::utils::simple_http_download::simple_http_download;
|
||||
use crate::core::utils::simple_http_download_to_tempfile::simple_http_download_to_tempfile;
|
||||
use crate::services::fal::state::fal_credential_manager::FalCredentialManager;
|
||||
use crate::services::fal::state::fal_task_queue::FalTaskQueue;
|
||||
use crate::services::sora::events::sora_image_enqueue_failure_event::SoraImageEnqueueFailureEvent;
|
||||
use crate::services::sora::events::sora_image_enqueue_success_event::SoraImageEnqueueSuccessEvent;
|
||||
use crate::services::sora::state::read_sora_credentials_from_disk::read_sora_credentials_from_disk;
|
||||
use crate::services::sora::state::sora_credential_holder::SoraCredentialHolder;
|
||||
use crate::services::sora::state::sora_credential_manager::SoraCredentialManager;
|
||||
use crate::services::sora::state::sora_task_queue::SoraTaskQueue;
|
||||
use crate::services::storyteller::state::storyteller_credential_manager::StorytellerCredentialManager;
|
||||
use anyhow::anyhow;
|
||||
use base64::prelude::BASE64_STANDARD;
|
||||
use base64::{DecodeError, Engine};
|
||||
use errors::{AnyhowError, AnyhowResult};
|
||||
use fal_client::error::fal_error_plus::FalErrorPlus;
|
||||
use fal_client::requests::image_gen::enqueue_flux_pro_ultra_text_to_image::{enqueue_flux_pro_ultra_text_to_image, FluxProUltraTextToImageArgs};
|
||||
use fal_client::requests::image_gen::enqueue_recraft3_text_to_image::{enqueue_recraft3_text_to_image, Recraft3TextToImageArgs};
|
||||
use fal_client::requests::remove_background_rembg::remove_background_rembg;
|
||||
use filesys::file_read_bytes::file_read_bytes;
|
||||
use image::codecs::png::{CompressionType, FilterType, PngEncoder};
|
||||
use image::{DynamicImage, EncodableLayout, ImageReader};
|
||||
use log::{debug, error, info, warn};
|
||||
use mimetypes::mimetype_info::mimetype_info::MimetypeInfo;
|
||||
use openai_sora_client::credentials::SoraCredentials;
|
||||
use openai_sora_client::creds::credential_migration::CredentialMigrationRef;
|
||||
use openai_sora_client::recipes::image_remix_with_session_auto_renew::{image_remix_with_session_auto_renew, ImageRemixAutoRenewRequest};
|
||||
use openai_sora_client::recipes::image_upload_from_file_with_session_auto_renew::{image_upload_from_file_with_session_auto_renew, ImageUploadFromFileAutoRenewRequest};
|
||||
use openai_sora_client::recipes::maybe_upgrade_or_renew_session::maybe_upgrade_or_renew_session;
|
||||
use openai_sora_client::requests::image_gen::common::{ImageSize, NumImages};
|
||||
use openai_sora_client::requests::image_gen::sora_image_gen_remix::{sora_image_gen_remix, SoraImageGenRemixRequest};
|
||||
use openai_sora_client::requests::upload::upload_media_from_bytes::sora_media_upload_from_bytes;
|
||||
use openai_sora_client::requests::upload::upload_media_from_file::sora_media_upload_from_file;
|
||||
use openai_sora_client::sora_error::SoraError;
|
||||
use reqwest::Url;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::fs::read_to_string;
|
||||
use std::io::{Cursor, Read, Write};
|
||||
use std::ops::Add;
|
||||
use std::path::PathBuf;
|
||||
use std::time::Duration;
|
||||
use storyteller_client::error::api_error::ApiError;
|
||||
use storyteller_client::error::api_error::ApiError::InternalServerError;
|
||||
use storyteller_client::media_files::get_media_file::{get_media_file, GetMediaFileSuccessResponse};
|
||||
use storyteller_client::media_files::upload_image_media_file_from_file::upload_image_media_file_from_file;
|
||||
use storyteller_client::utils::api_host::ApiHost;
|
||||
use tauri::{AppHandle, Emitter, Manager, State};
|
||||
use tempfile::NamedTempFile;
|
||||
use tokens::tokens::media_files::MediaFileToken;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct EnqueueTextToImageRequest {
|
||||
/// Text prompt for the image generation. Required.
|
||||
pub prompt: Option<String>,
|
||||
|
||||
/// The model to use.
|
||||
pub model: Option<EnqueueTextToImageModel>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Copy, Clone)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum EnqueueTextToImageModel {
|
||||
#[serde(rename = "flux_pro_ultra")]
|
||||
FluxProUltra,
|
||||
#[serde(rename = "gpt_image_1")]
|
||||
GptImage1,
|
||||
#[serde(rename = "recraft_3")]
|
||||
Recraft3,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct EnqueueTextToImageSuccessResponse {
|
||||
}
|
||||
|
||||
impl SerializeMarker for EnqueueTextToImageSuccessResponse {}
|
||||
|
||||
#[derive(Serialize, Debug)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum EnqueueTextToImageErrorType {
|
||||
/// Caller didn't specify a model
|
||||
ModelNotSpecified,
|
||||
/// Generic server error
|
||||
ServerError,
|
||||
/// No Fal API key available
|
||||
NeedsFalApiKey,
|
||||
/// Fal had an API error
|
||||
FalError,
|
||||
}
|
||||
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn enqueue_text_to_image_command(
|
||||
request: EnqueueTextToImageRequest,
|
||||
app_data_root: State<'_, AppDataRoot>,
|
||||
fal_creds_manager: State<'_, FalCredentialManager>,
|
||||
storyteller_creds_manager: State<'_, StorytellerCredentialManager>,
|
||||
fal_task_queue: State<'_, FalTaskQueue>,
|
||||
sora_creds_manager: State<'_, SoraCredentialManager>,
|
||||
sora_task_queue: State<'_, SoraTaskQueue>,
|
||||
) -> CommandResult<EnqueueTextToImageSuccessResponse, EnqueueTextToImageErrorType, ()> {
|
||||
|
||||
info!("enqueue_text_to_image called");
|
||||
|
||||
let result = handle_request(
|
||||
request,
|
||||
&app_data_root,
|
||||
&fal_creds_manager,
|
||||
&storyteller_creds_manager,
|
||||
&fal_task_queue,
|
||||
&sora_creds_manager,
|
||||
&sora_task_queue,
|
||||
).await;
|
||||
|
||||
match result {
|
||||
Err(err) => {
|
||||
error!("error: {:?}", err);
|
||||
|
||||
//let event = SoraImageEnqueueFailureEvent {};
|
||||
//let result = event.send(&app);
|
||||
//if let Err(err) = result {
|
||||
// error!("Failed to emit event: {:?}", err);
|
||||
//}
|
||||
|
||||
let mut status = CommandErrorStatus::ServerError;
|
||||
let mut error_type = EnqueueTextToImageErrorType::ServerError;
|
||||
let mut error_message = "A server error occurred. Please try again. If it continues, please tell our staff about the problem.";
|
||||
|
||||
match err {
|
||||
InternalImageError::NoModelSpecified => {
|
||||
status = CommandErrorStatus::BadRequest;
|
||||
error_type = EnqueueTextToImageErrorType::ModelNotSpecified;
|
||||
error_message = "No model specified for image generation";
|
||||
}
|
||||
InternalImageError::NeedsFalApiKey => {
|
||||
status = CommandErrorStatus::Unauthorized;
|
||||
error_type = EnqueueTextToImageErrorType::NeedsFalApiKey;
|
||||
error_message = "You need to set a FAL api key";
|
||||
},
|
||||
_ => {}, // Fall-through
|
||||
}
|
||||
|
||||
Err(CommandErrorResponseWrapper {
|
||||
status,
|
||||
error_message: Some(error_message.to_string()),
|
||||
error_type: Some(error_type),
|
||||
error_details: None,
|
||||
})
|
||||
}
|
||||
Ok(result) => {
|
||||
//let event = SoraImageEnqueueSuccessEvent {};
|
||||
//let result = event.send(&app);
|
||||
//if let Err(err) = result {
|
||||
// error!("Failed to emit event: {:?}", err);
|
||||
//}
|
||||
|
||||
Ok(EnqueueTextToImageSuccessResponse {
|
||||
}.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub async fn handle_request(
|
||||
request: EnqueueTextToImageRequest,
|
||||
app_data_root: &AppDataRoot,
|
||||
fal_creds_manager: &FalCredentialManager,
|
||||
storyteller_creds_manager: &StorytellerCredentialManager,
|
||||
fal_task_queue: &FalTaskQueue,
|
||||
sora_creds_manager: &SoraCredentialManager,
|
||||
sora_task_queue: &SoraTaskQueue,
|
||||
) -> Result<(), InternalImageError> {
|
||||
|
||||
match request.model {
|
||||
None => {
|
||||
return Err(InternalImageError::NoModelSpecified);
|
||||
}
|
||||
Some(EnqueueTextToImageModel::FluxProUltra) | Some(EnqueueTextToImageModel::Recraft3) => {
|
||||
handle_fal(request, fal_creds_manager, fal_task_queue).await?;
|
||||
},
|
||||
Some(EnqueueTextToImageModel::GptImage1) => {
|
||||
handle_sora(request, sora_creds_manager, sora_task_queue).await?;
|
||||
}
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
use crate::core::commands::enqueue::image::enqueue_text_to_image_command::{EnqueueTextToImageModel, EnqueueTextToImageRequest};
|
||||
use crate::core::commands::enqueue::image::internal_image_error::InternalImageError;
|
||||
use crate::core::state::data_dir::app_data_root::AppDataRoot;
|
||||
use crate::services::fal::state::fal_credential_manager::FalCredentialManager;
|
||||
use crate::services::fal::state::fal_task_queue::FalTaskQueue;
|
||||
use crate::services::sora::state::sora_credential_manager::SoraCredentialManager;
|
||||
use crate::services::sora::state::sora_task_queue::SoraTaskQueue;
|
||||
use crate::services::storyteller::state::storyteller_credential_manager::StorytellerCredentialManager;
|
||||
use anyhow::anyhow;
|
||||
use fal_client::requests::image_gen::enqueue_flux_pro_ultra_text_to_image::{enqueue_flux_pro_ultra_text_to_image, FluxProUltraTextToImageArgs};
|
||||
use fal_client::requests::image_gen::enqueue_recraft3_text_to_image::{enqueue_recraft3_text_to_image, Recraft3TextToImageArgs};
|
||||
use log::{error, info, warn};
|
||||
|
||||
pub async fn handle_fal(
|
||||
request: EnqueueTextToImageRequest,
|
||||
fal_creds_manager: &FalCredentialManager,
|
||||
fal_task_queue: &FalTaskQueue,
|
||||
) -> Result<(), InternalImageError> {
|
||||
|
||||
let api_key = fal_creds_manager.get_key_required()
|
||||
.map_err(|err| {
|
||||
error!("EnqueueTextToImage FAL api key required: {:?}", err);
|
||||
InternalImageError::NeedsFalApiKey
|
||||
})?;
|
||||
|
||||
let prompt = request.prompt.as_deref().unwrap_or("");
|
||||
|
||||
let result = match request.model {
|
||||
None => {
|
||||
return Err(InternalImageError::NoModelSpecified);
|
||||
}
|
||||
Some(EnqueueTextToImageModel::GptImage1) => {
|
||||
return Err(InternalImageError::AnyhowError(anyhow!("wrong logic: fal is handling sora images")));
|
||||
}
|
||||
Some(EnqueueTextToImageModel::FluxProUltra) => {
|
||||
info!("enqueue Flux Pro Ultra text-to-image with prompt: {}", prompt);
|
||||
enqueue_flux_pro_ultra_text_to_image(FluxProUltraTextToImageArgs {
|
||||
prompt,
|
||||
api_key: &api_key,
|
||||
}).await
|
||||
}
|
||||
Some(EnqueueTextToImageModel::Recraft3) => {
|
||||
info!("enqueue Recraft v3 text-to-image with prompt: {}", prompt);
|
||||
enqueue_recraft3_text_to_image(Recraft3TextToImageArgs {
|
||||
prompt,
|
||||
api_key: &api_key,
|
||||
}).await
|
||||
}
|
||||
};
|
||||
|
||||
match result {
|
||||
Ok(enqueued) => {
|
||||
info!("Successfully enqueued text to image");
|
||||
|
||||
if let Err(err) = fal_task_queue.insert(&enqueued) {
|
||||
error!("Failed to enqueue task: {:?}", err);
|
||||
return Err(InternalImageError::AnyhowError(anyhow!("Failed to enqueue task: {:?}", err)));
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
error!("Failed to enqueue text to image: {:?}", err);
|
||||
return Err(InternalImageError::FalError(err));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
use crate::core::commands::enqueue::image::enqueue_text_to_image_command::{EnqueueTextToImageModel, EnqueueTextToImageRequest};
|
||||
use crate::core::commands::enqueue::image::internal_image_error::InternalImageError;
|
||||
use crate::core::state::data_dir::app_data_root::AppDataRoot;
|
||||
use crate::services::fal::state::fal_credential_manager::FalCredentialManager;
|
||||
use crate::services::fal::state::fal_task_queue::FalTaskQueue;
|
||||
use crate::services::sora::state::sora_credential_manager::SoraCredentialManager;
|
||||
use crate::services::sora::state::sora_task_queue::SoraTaskQueue;
|
||||
use crate::services::storyteller::state::storyteller_credential_manager::StorytellerCredentialManager;
|
||||
use anyhow::anyhow;
|
||||
use fal_client::requests::image_gen::enqueue_flux_pro_ultra_text_to_image::{enqueue_flux_pro_ultra_text_to_image, FluxProUltraTextToImageArgs};
|
||||
use fal_client::requests::image_gen::enqueue_recraft3_text_to_image::{enqueue_recraft3_text_to_image, Recraft3TextToImageArgs};
|
||||
use log::{error, info, warn};
|
||||
use openai_sora_client::creds::sora_credential_set::SoraCredentialSet;
|
||||
use openai_sora_client::recipes::image_remix_with_session_auto_renew::{image_remix_with_session_auto_renew, ImageRemixAutoRenewRequest};
|
||||
use openai_sora_client::recipes::maybe_upgrade_or_renew_session::maybe_upgrade_or_renew_session;
|
||||
use openai_sora_client::recipes::simple_image_gen_with_session_auto_renew::{simple_image_gen_with_session_auto_renew, SimpleImageGenAutoRenewRequest};
|
||||
use openai_sora_client::requests::image_gen::common::{ImageSize, NumImages, SoraImageGenResponse};
|
||||
use openai_sora_client::sora_error::SoraError;
|
||||
use std::time::Duration;
|
||||
|
||||
const SORA_SIMPLE_IMAGE_GEN_TIMEOUT : Duration = Duration::from_millis(1000 * 30); // 30 seconds
|
||||
|
||||
pub async fn handle_sora(
|
||||
request: EnqueueTextToImageRequest,
|
||||
sora_creds_manager: &SoraCredentialManager,
|
||||
sora_task_queue: &SoraTaskQueue,
|
||||
) -> Result<(), InternalImageError> {
|
||||
|
||||
let mut creds = sora_creds_manager
|
||||
.get_credentials_required()
|
||||
.map_err(|err| {
|
||||
error!("EnqueueTextToImage Sora creds required: {:?}", err);
|
||||
InternalImageError::NeedsFalApiKey
|
||||
})?;
|
||||
|
||||
let credential_updated = maybe_upgrade_or_renew_session(&mut creds)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
error!("Failed to upgrade or renew session: {:?}", err);
|
||||
err
|
||||
})?;
|
||||
|
||||
if credential_updated {
|
||||
info!("Storing updated credentials");
|
||||
sora_creds_manager.set_credentials(&creds)?;
|
||||
}
|
||||
|
||||
let prompt = request.prompt.as_deref().unwrap_or("");
|
||||
|
||||
let result =
|
||||
simple_image_gen_with_session_auto_renew(SimpleImageGenAutoRenewRequest {
|
||||
prompt: prompt.to_string(),
|
||||
num_images: NumImages::One,
|
||||
image_size: ImageSize::Square,
|
||||
credentials: &creds,
|
||||
request_timeout: Some(SORA_SIMPLE_IMAGE_GEN_TIMEOUT),
|
||||
}).await;
|
||||
|
||||
let (response, maybe_new_creds) =
|
||||
match result {
|
||||
Ok((response, maybe_new_creds)) => (response, maybe_new_creds),
|
||||
Err(err) => {
|
||||
return Err(InternalImageError::SoraError(err));
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(new_creds) = maybe_new_creds {
|
||||
info!("Storing updated credentials.");
|
||||
sora_creds_manager.set_credentials(&new_creds)?;
|
||||
}
|
||||
|
||||
info!("New Sora Task ID: {:?} ", response.task_id);
|
||||
|
||||
sora_task_queue.insert(&response.task_id)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
use base64::DecodeError;
|
||||
use errors::AnyhowError;
|
||||
use fal_client::error::fal_error_plus::FalErrorPlus;
|
||||
use openai_sora_client::sora_error::SoraError;
|
||||
use storyteller_client::error::api_error::ApiError;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum InternalImageError {
|
||||
NoModelSpecified,
|
||||
NeedsFalApiKey,
|
||||
NeedsSoraCredentials,
|
||||
FalError(FalErrorPlus),
|
||||
SoraError(SoraError),
|
||||
AnyhowError(AnyhowError),
|
||||
StorytellerApiError(ApiError),
|
||||
DecodeError(DecodeError),
|
||||
IoError(std::io::Error),
|
||||
}
|
||||
|
||||
impl From<AnyhowError> for InternalImageError {
|
||||
fn from(value: AnyhowError) -> Self {
|
||||
Self::AnyhowError(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FalErrorPlus> for InternalImageError {
|
||||
fn from(value: FalErrorPlus) -> Self {
|
||||
Self::FalError(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SoraError> for InternalImageError {
|
||||
fn from(value: SoraError) -> Self {
|
||||
Self::SoraError(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ApiError> for InternalImageError {
|
||||
fn from(value: ApiError) -> Self {
|
||||
Self::StorytellerApiError(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DecodeError> for InternalImageError {
|
||||
fn from(value: DecodeError) -> Self {
|
||||
Self::DecodeError(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for InternalImageError {
|
||||
fn from(value: std::io::Error) -> Self {
|
||||
Self::IoError(value)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
pub mod enqueue_text_to_image_command;
|
||||
pub mod handle_fal;
|
||||
pub mod handle_sora;
|
||||
pub mod internal_image_error;
|
||||
@@ -0,0 +1 @@
|
||||
pub mod image;
|
||||
@@ -0,0 +1,39 @@
|
||||
use crate::core::commands::command_response_wrapper::{CommandResult, InfallibleResponse, SerializeMarker};
|
||||
use crate::core::state::os_platform::OsPlatform;
|
||||
use crate::services::fal::commands::fal_background_removal_command::FalBackgroundRemovalSuccessResponse;
|
||||
use base64::prelude::BASE64_STANDARD;
|
||||
use base64::Engine;
|
||||
use chrono::{DateTime, Utc};
|
||||
use image::codecs::png::{CompressionType, FilterType, PngEncoder};
|
||||
use image::ImageReader;
|
||||
use log::info;
|
||||
use serde_derive::Serialize;
|
||||
use std::io::Cursor;
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct BuildInfoResponse {
|
||||
pub build_timestamp: DateTime<Utc>,
|
||||
pub git_commit_id: Option<String>,
|
||||
pub git_commit_short_id: Option<String>,
|
||||
pub git_commit_timestamp: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
impl SerializeMarker for BuildInfoResponse {}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn get_build_info_command() -> InfallibleResponse<BuildInfoResponse> {
|
||||
info!("get_build_info_command called...");
|
||||
|
||||
let build_timestamp = build_metadata::build_timestamp();
|
||||
let git_commit_id = build_metadata::git_commit_id();
|
||||
let git_commit_short_id = build_metadata::git_commit_short_id();
|
||||
let git_commit_timestamp = build_metadata::git_commit_timestamp();
|
||||
|
||||
BuildInfoResponse {
|
||||
build_timestamp,
|
||||
git_commit_id: git_commit_id.map(|s| s.to_string()),
|
||||
git_commit_short_id: git_commit_short_id.map(|s| s.to_string()),
|
||||
git_commit_timestamp,
|
||||
}.into()
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
pub mod app_preferences;
|
||||
pub mod command_response_wrapper;
|
||||
pub mod enqueue;
|
||||
pub mod flip_image;
|
||||
pub mod get_build_info_command;
|
||||
pub mod platform_info_command;
|
||||
|
||||
@@ -5,7 +5,9 @@ use tauri::Manager;
|
||||
|
||||
use crate::core::commands::app_preferences::get_app_preferences_command::get_app_preferences_command;
|
||||
use crate::core::commands::app_preferences::update_app_preference_command::update_app_preferences_command;
|
||||
use crate::core::commands::enqueue::image::enqueue_text_to_image_command::enqueue_text_to_image_command;
|
||||
use crate::core::commands::flip_image::flip_image;
|
||||
use crate::core::commands::get_build_info_command::get_build_info_command;
|
||||
use crate::core::commands::platform_info_command::platform_info_command;
|
||||
use crate::core::state::app_preferences::app_preferences_manager::load_app_preferences_or_default;
|
||||
use crate::core::state::data_dir::app_data_root::AppDataRoot;
|
||||
@@ -159,11 +161,13 @@ pub fn run() {
|
||||
.manage(storyteller_creds_manager_3)
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
check_sora_session_command,
|
||||
enqueue_text_to_image_command,
|
||||
fal_background_removal_command,
|
||||
fal_hunyuan_image_to_3d_command,
|
||||
fal_kling_image_to_video_command,
|
||||
flip_image,
|
||||
get_app_preferences_command,
|
||||
get_build_info_command,
|
||||
get_fal_api_key_command,
|
||||
open_sora_login_command,
|
||||
platform_info_command,
|
||||
|
||||
@@ -19,7 +19,7 @@ use anyhow::anyhow;
|
||||
use base64::prelude::BASE64_STANDARD;
|
||||
use base64::{DecodeError, Engine};
|
||||
use errors::{AnyhowError, AnyhowResult};
|
||||
use fal_client::fal_error_plus::FalErrorPlus;
|
||||
use fal_client::error::fal_error_plus::FalErrorPlus;
|
||||
use fal_client::requests::remove_background_rembg::remove_background_rembg;
|
||||
use filesys::file_read_bytes::file_read_bytes;
|
||||
use image::codecs::png::{CompressionType, FilterType, PngEncoder};
|
||||
|
||||
+1
-2
@@ -20,9 +20,8 @@ use anyhow::anyhow;
|
||||
use base64::prelude::BASE64_STANDARD;
|
||||
use base64::{DecodeError, Engine};
|
||||
use errors::{AnyhowError, AnyhowResult};
|
||||
use fal_client::fal_error_plus::FalErrorPlus;
|
||||
use fal_client::error::fal_error_plus::FalErrorPlus;
|
||||
use fal_client::requests::enqueue_hunyuan2_image_to_3d::{enqueue_hunyuan2_image_to_3d, Hunyuan2Args};
|
||||
use fal_client::requests::enqueue_kling_16_image_to_video::{enqueue_kling_16_image_to_video, Kling16Args, Kling16Duration};
|
||||
use fal_client::requests::remove_background_rembg::remove_background_rembg;
|
||||
use filesys::file_read_bytes::file_read_bytes;
|
||||
use image::codecs::png::{CompressionType, FilterType, PngEncoder};
|
||||
|
||||
+8
-2
@@ -20,8 +20,8 @@ use anyhow::anyhow;
|
||||
use base64::prelude::BASE64_STANDARD;
|
||||
use base64::{DecodeError, Engine};
|
||||
use errors::{AnyhowError, AnyhowResult};
|
||||
use fal_client::fal_error_plus::FalErrorPlus;
|
||||
use fal_client::requests::enqueue_kling_16_image_to_video::{enqueue_kling_16_image_to_video, Kling16Args, Kling16Duration};
|
||||
use fal_client::error::fal_error_plus::FalErrorPlus;
|
||||
use fal_client::requests::video_gen::enqueue_kling_16_image_to_video::{enqueue_kling_16_image_to_video, Kling16Args, Kling16Duration};
|
||||
use fal_client::requests::remove_background_rembg::remove_background_rembg;
|
||||
use filesys::file_read_bytes::file_read_bytes;
|
||||
use image::codecs::png::{CompressionType, FilterType, PngEncoder};
|
||||
@@ -57,10 +57,15 @@ use tokens::tokens::media_files::MediaFileToken;
|
||||
#[derive(Deserialize)]
|
||||
pub struct FalKlingImageToVideoRequest {
|
||||
/// Image media file; the image to remove the background from.
|
||||
/// This must be supplied **OR** the `base64_image`.
|
||||
pub image_media_token: Option<MediaFileToken>,
|
||||
|
||||
/// Base64-encoded image
|
||||
/// This must be supplied **OR** the `image_media_token`.
|
||||
pub base64_image: Option<String>,
|
||||
|
||||
/// Optional: Text prompt.
|
||||
pub prompt: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug)]
|
||||
@@ -209,6 +214,7 @@ pub async fn image_to_video(
|
||||
image_path: filename,
|
||||
api_key: &api_key,
|
||||
duration: Kling16Duration::Default,
|
||||
prompt: request.prompt.as_deref().unwrap_or(""),
|
||||
}).await?;
|
||||
|
||||
if let Err(err) = fal_task_queue.insert(&enqueued) {
|
||||
|
||||
@@ -9,8 +9,8 @@ use crate::services::sora::events::sora_image_generation_failed_event::SoraImage
|
||||
use crate::services::sora::state::sora_credential_manager::SoraCredentialManager;
|
||||
use crate::services::storyteller::state::storyteller_credential_manager::StorytellerCredentialManager;
|
||||
use errors::AnyhowResult;
|
||||
use fal_client::error::fal_error_plus::FalErrorPlus;
|
||||
use fal_client::export::queue::Status;
|
||||
use fal_client::fal_error_plus::FalErrorPlus;
|
||||
use fal_client::model::fal_request_id::FalRequestId;
|
||||
use fal_client::utils::queue_status_checker::QueueStatusChecker;
|
||||
use log::{error, info, warn};
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
{"default":{"identifier":"default","description":"enables the default permissions","local":true,"windows":["main"],"permissions":["core:default","log:default"]}}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -9,7 +9,6 @@ authors = [
|
||||
publish = false
|
||||
|
||||
[lib]
|
||||
# NB: Public "errors" crate is name-squatted, so we're fine to use this internally.
|
||||
name = "actix_cors_configs"
|
||||
path = "src/lib.rs"
|
||||
|
||||
@@ -17,22 +16,21 @@ path = "src/lib.rs"
|
||||
normal = ["workspace-build-acceleration"]
|
||||
|
||||
[dependencies]
|
||||
# Internal
|
||||
#errors = { path = "../../lib/errors" }
|
||||
reusable_types = { path = "../../_types/reusable_types" }
|
||||
|
||||
# Workspace hack (faster compile times)
|
||||
workspace-build-acceleration = { version = "0.1", path = "../../workspace-build-acceleration" }
|
||||
workspace-build-acceleration = { workspace = true }
|
||||
|
||||
# Internal
|
||||
reusable_types = { path = "../../schema/public/reusable_types" }
|
||||
|
||||
# External
|
||||
log = "0.4.14"
|
||||
log = { workspace = true }
|
||||
|
||||
# Actix
|
||||
actix-cors = "0.6.4"
|
||||
actix-http = "3.7.0"
|
||||
actix-web = "4.7.0"
|
||||
url = { version = "2.5.0", features = [] }
|
||||
actix-cors = { workspace = true }
|
||||
actix-http = { workspace = true }
|
||||
actix-web = { workspace = true }
|
||||
url = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
actix-rt = "2.10.0"
|
||||
actix-rt = { workspace = true }
|
||||
speculoos = "0.11.0" # Fluent assertions
|
||||
|
||||
@@ -17,18 +17,16 @@ path = "src/lib.rs"
|
||||
normal = ["workspace-build-acceleration"]
|
||||
|
||||
[dependencies]
|
||||
# Internal
|
||||
errors = { path = "../../lib/errors" }
|
||||
|
||||
# Workspace hack (faster compile times)
|
||||
workspace-build-acceleration = { version = "0.1", path = "../../workspace-build-acceleration" }
|
||||
workspace-build-acceleration = { workspace = true }
|
||||
|
||||
# Internal
|
||||
errors = { workspace = true }
|
||||
|
||||
# Actix
|
||||
actix-http = "3.7.0"
|
||||
actix-rt = "2.10.0"
|
||||
actix-service = "2.0.2"
|
||||
actix-utils = "3.0.1"
|
||||
actix-web = "4.7.0"
|
||||
actix-http = { workspace = true }
|
||||
actix-service = { workspace = true }
|
||||
actix-web = { workspace = true }
|
||||
|
||||
# IPv4 and v6 CIDRs (crate has few dependencies)
|
||||
cidr-utils = "0.5.11"
|
||||
@@ -38,8 +36,8 @@ num-traits = "0.2.17" # for cidr-utils
|
||||
futures-util = "0.3.29"
|
||||
|
||||
# Serialization
|
||||
serde = "1.0.125"
|
||||
serde_json = "1.0.108"
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
# None yet
|
||||
|
||||
@@ -14,9 +14,9 @@ path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
# Internal
|
||||
enums = { path = "../../../_types/enums" }
|
||||
enums = { path = "../../../schema/public/enums" }
|
||||
errors = { path = "../../errors" }
|
||||
tokens = { path = "../../../_types/tokens" }
|
||||
tokens = { path = "../../../schema/public/tokens" }
|
||||
|
||||
# External
|
||||
bytes = "1.3"
|
||||
|
||||
@@ -22,7 +22,6 @@ errors = { workspace = true }
|
||||
|
||||
# External
|
||||
anyhow = { workspace = true }
|
||||
chrono = { workspace = true }
|
||||
fal = { version = "0.3.6", features = ["endpoints"] }
|
||||
futures = { workspace = true }
|
||||
reqwest = { workspace = true }
|
||||
@@ -32,4 +31,3 @@ url = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
testing = { path = "../../testing" }
|
||||
filesys = { path = "../../files/filesys" }
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
use crate::error::fal_error_plus::FalErrorPlus;
|
||||
|
||||
/// Better classify the `fal::FalError` into a more user-friendly `FalErrorPlus`.
|
||||
pub fn classify_fal_error(err: fal::FalError) -> FalErrorPlus {
|
||||
match err {
|
||||
fal::FalError::RequestError(_) => FalErrorPlus::FalError(err),
|
||||
fal::FalError::ImageError(_) => FalErrorPlus::FalError(err),
|
||||
fal::FalError::SerializeError(_) => FalErrorPlus::FalError(err),
|
||||
fal::FalError::StreamError(_) => FalErrorPlus::FalError(err),
|
||||
fal::FalError::Other(ref inner) => {
|
||||
if inner.contains("Invalid Key Authorization header format") {
|
||||
FalErrorPlus::FalApiKeyError(inner.to_string())
|
||||
} else if inner.contains("No user found for Key ID and Secret") {
|
||||
FalErrorPlus::FalApiKeyError(inner.to_string())
|
||||
} else {
|
||||
FalErrorPlus::FalError(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
-1
@@ -1,3 +1,4 @@
|
||||
use crate::error::classify_fal_error::classify_fal_error;
|
||||
use std::error::Error;
|
||||
use std::fmt::{Display, Formatter};
|
||||
|
||||
@@ -6,6 +7,8 @@ use std::fmt::{Display, Formatter};
|
||||
pub enum FalErrorPlus {
|
||||
/// An error arising in the `fal` crate.
|
||||
FalError(fal::FalError),
|
||||
/// The fal API key is invalid.
|
||||
FalApiKeyError(String),
|
||||
/// Another error we didn't handle.
|
||||
AnyhowError(anyhow::Error),
|
||||
/// URL parse errors.
|
||||
@@ -18,6 +21,7 @@ impl Display for FalErrorPlus {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::FalError(err) => write!(f, "FalErrorPlus::FalError: {:?}", err),
|
||||
Self::FalApiKeyError(reason) => write!(f, "FalErrorPlus::FalApiKeyError: {}", reason),
|
||||
Self::AnyhowError(err) => write!(f, "FalErrorPlus::AnyhowError: {:?}", err),
|
||||
Self::UrlParseError(err) => write!(f, "FalErrorPlus::UrlParseError: {:?}", err),
|
||||
Self::UnhandledEndpoint(endpoint) => write!(f, "FalErrorPlus::UnhandledEndpoint: {:?}", endpoint),
|
||||
@@ -29,7 +33,7 @@ impl Error for FalErrorPlus {}
|
||||
|
||||
impl From<fal::FalError> for FalErrorPlus {
|
||||
fn from(err: fal::FalError) -> Self {
|
||||
FalErrorPlus::FalError(err)
|
||||
classify_fal_error(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
pub mod classify_fal_error;
|
||||
pub mod fal_error_plus;
|
||||
@@ -8,7 +8,7 @@ pub mod export {
|
||||
}
|
||||
|
||||
pub mod creds;
|
||||
pub mod fal_error_plus;
|
||||
pub mod error;
|
||||
pub mod model;
|
||||
pub mod requests;
|
||||
pub mod utils;
|
||||
|
||||
@@ -1,29 +1,46 @@
|
||||
use fal::queue::Queue;
|
||||
use serde::de::DeserializeOwned;
|
||||
|
||||
// TODO(bt,2025-05-26): A macro to define these + tests.
|
||||
|
||||
const FLUX_PRO_ULTRA_TEXT_TO_IMAGE: &str = "fal-ai/flux-pro/v1.1-ultra";
|
||||
|
||||
const HUNYUAN_3D_2_BASE: &str = "fal-ai/hunyuan3d/v2";
|
||||
|
||||
const KLING16_IMAGE_TO_VIDEO: &str = "fal-ai/kling-video/v1.6/pro/image-to-video";
|
||||
|
||||
const MINIMAX_IMAGE_TO_VIDEO: &str = "fal-ai/minimax/image-to-video";
|
||||
|
||||
const RECRAFT_V3_TEXT_TO_IMAGE: &str = "fal-ai/recraft-v3";
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum FalEndpoint {
|
||||
Kling16ImageToVideo,
|
||||
FluxProUltraTextToImage,
|
||||
Hunyuan3d2Base,
|
||||
Kling16ImageToVideo,
|
||||
Minimax01ImageToVideo,
|
||||
RecraftV3TextToImage,
|
||||
Other(String),
|
||||
}
|
||||
|
||||
impl FalEndpoint {
|
||||
pub fn from_queue_response<R: DeserializeOwned>(queue: &Queue<R>) -> Self {
|
||||
match queue.endpoint.as_str() {
|
||||
FLUX_PRO_ULTRA_TEXT_TO_IMAGE => FalEndpoint::FluxProUltraTextToImage,
|
||||
HUNYUAN_3D_2_BASE => FalEndpoint::Hunyuan3d2Base,
|
||||
KLING16_IMAGE_TO_VIDEO => FalEndpoint::Kling16ImageToVideo,
|
||||
MINIMAX_IMAGE_TO_VIDEO => FalEndpoint::Minimax01ImageToVideo,
|
||||
RECRAFT_V3_TEXT_TO_IMAGE => FalEndpoint::RecraftV3TextToImage,
|
||||
_ => FalEndpoint::Other(queue.endpoint.clone()),
|
||||
}
|
||||
}
|
||||
pub fn url(&self) -> &str {
|
||||
match self {
|
||||
Self::FluxProUltraTextToImage => FLUX_PRO_ULTRA_TEXT_TO_IMAGE,
|
||||
Self::Hunyuan3d2Base => HUNYUAN_3D_2_BASE,
|
||||
Self::Kling16ImageToVideo => KLING16_IMAGE_TO_VIDEO,
|
||||
Self::Minimax01ImageToVideo => MINIMAX_IMAGE_TO_VIDEO,
|
||||
Self::RecraftV3TextToImage => RECRAFT_V3_TEXT_TO_IMAGE,
|
||||
Self::Other(url) => url,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::creds::fal_api_key::FalApiKey;
|
||||
use crate::fal_error_plus::FalErrorPlus;
|
||||
use crate::error::classify_fal_error::classify_fal_error;
|
||||
use crate::error::fal_error_plus::FalErrorPlus;
|
||||
use crate::model::enqueued_request::EnqueuedRequest;
|
||||
use fal::endpoints::fal_ai::hunyuan3d::v2::v2;
|
||||
use fal::endpoints::fal_ai::hunyuan3d::v2::Hunyuan3DInput;
|
||||
@@ -16,12 +17,6 @@ pub struct Hunyuan2Args<'a, P: AsRef<Path>> {
|
||||
pub async fn enqueue_hunyuan2_image_to_3d<P: AsRef<Path>>(args: Hunyuan2Args<'_, P>) -> Result<EnqueuedRequest, FalErrorPlus> {
|
||||
let image_url = file_to_base64_url(args.image_path)?;
|
||||
|
||||
/*
|
||||
TODO: Handle error messages -
|
||||
FalError(FalError(Other("{\"detail\": \"Invalid Key Authorization header format. Expected '<key_id>:<key_secret>'.\"}")))
|
||||
FalError(FalError(Other("{\"detail\": \"No user found for Key ID and Secret\"}")))
|
||||
*/
|
||||
|
||||
let request = Hunyuan3DInput {
|
||||
input_image_url: image_url,
|
||||
textured_mesh: Some(true),
|
||||
@@ -34,7 +29,12 @@ pub async fn enqueue_hunyuan2_image_to_3d<P: AsRef<Path>>(args: Hunyuan2Args<'_,
|
||||
let result = v2(request)
|
||||
.with_api_key(&args.api_key.0)
|
||||
.queue()
|
||||
.await?;
|
||||
.await;
|
||||
|
||||
let result = match result {
|
||||
Ok(result) => result,
|
||||
Err(err) => return Err(classify_fal_error(err)),
|
||||
};
|
||||
|
||||
Ok(EnqueuedRequest::from_queue_response(&result)?)
|
||||
}
|
||||
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
use crate::creds::fal_api_key::FalApiKey;
|
||||
use crate::error::classify_fal_error::classify_fal_error;
|
||||
use crate::error::fal_error_plus::FalErrorPlus;
|
||||
use crate::model::enqueued_request::EnqueuedRequest;
|
||||
use fal::endpoints::fal_ai::flux_pro::v1_1_ultra::v1_1_ultra;
|
||||
use fal::endpoints::fal_ai::flux_pro::v1_1_ultra::FluxProUltraTextToImageInput;
|
||||
use futures::StreamExt;
|
||||
use std::io::Write;
|
||||
|
||||
pub struct FluxProUltraTextToImageArgs<'a> {
|
||||
pub prompt: &'a str,
|
||||
pub api_key: &'a FalApiKey,
|
||||
// TODO: Size parameter
|
||||
}
|
||||
|
||||
pub async fn enqueue_flux_pro_ultra_text_to_image(args: FluxProUltraTextToImageArgs<'_>) -> Result<EnqueuedRequest, FalErrorPlus> {
|
||||
let request = FluxProUltraTextToImageInput {
|
||||
prompt: args.prompt.to_string(),
|
||||
safety_tolerance: Some("5".to_string()), // 1 is most strict, 5 is most permissive
|
||||
enable_safety_checker: Some(false),
|
||||
num_images: Some(1), // Default is 1
|
||||
output_format: Some("png".to_string()),
|
||||
raw: Some(true), // Generate less processed, more natural-looking images. Default is false.
|
||||
aspect_ratio: None, // Default is "16:9"
|
||||
seed: None,
|
||||
sync_mode: None, // Synchronous / slow
|
||||
};
|
||||
|
||||
let result = v1_1_ultra(request)
|
||||
.with_api_key(&args.api_key.0)
|
||||
.queue()
|
||||
.await;
|
||||
|
||||
let result = match result {
|
||||
Ok(result) => result,
|
||||
Err(err) => return Err(classify_fal_error(err)),
|
||||
};
|
||||
|
||||
Ok(EnqueuedRequest::from_queue_response(&result)?)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::creds::fal_api_key::FalApiKey;
|
||||
use crate::requests::image_gen::enqueue_flux_pro_ultra_text_to_image::{enqueue_flux_pro_ultra_text_to_image, FluxProUltraTextToImageArgs};
|
||||
use errors::AnyhowResult;
|
||||
use std::fs::read_to_string;
|
||||
|
||||
#[tokio::test]
|
||||
#[ignore]
|
||||
async fn test_flux_pro() -> AnyhowResult<()> {
|
||||
// XXX: Don't commit secrets!
|
||||
let secret = read_to_string("/Users/bt/Artcraft/credentials/fal_api_key.txt")?;
|
||||
|
||||
let api_key = FalApiKey::from_str(&secret);
|
||||
|
||||
let args = FluxProUltraTextToImageArgs {
|
||||
prompt: "a corgi smiles at the camera, inside retro video game store, lots of sci-fi props from Cowboy Bebop, photorealistic",
|
||||
api_key: &api_key,
|
||||
};
|
||||
|
||||
let result = enqueue_flux_pro_ultra_text_to_image(args).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
use crate::creds::fal_api_key::FalApiKey;
|
||||
use crate::error::classify_fal_error::classify_fal_error;
|
||||
use crate::error::fal_error_plus::FalErrorPlus;
|
||||
use crate::model::enqueued_request::EnqueuedRequest;
|
||||
use fal::endpoints::fal_ai::recraft_v3::recraft_v3;
|
||||
use fal::endpoints::fal_ai::recraft_v3::ImageSizeProperty;
|
||||
use fal::endpoints::fal_ai::recraft_v3::TextToImageInput;
|
||||
use futures::StreamExt;
|
||||
use std::io::Write;
|
||||
|
||||
pub struct Recraft3TextToImageArgs<'a> {
|
||||
pub prompt: &'a str,
|
||||
pub api_key: &'a FalApiKey,
|
||||
// TODO: Size parameter
|
||||
}
|
||||
|
||||
pub async fn enqueue_recraft3_text_to_image(args: Recraft3TextToImageArgs<'_>) -> Result<EnqueuedRequest, FalErrorPlus> {
|
||||
let request = TextToImageInput {
|
||||
image_size: Some(ImageSizeProperty::SquareHd),
|
||||
prompt: args.prompt.to_string(),
|
||||
style: None, // eg. "realistic_image"
|
||||
style_id: None, // LoRA.
|
||||
colors: None, // Preferable colors. We can offer this later.
|
||||
};
|
||||
|
||||
let result = recraft_v3(request)
|
||||
.with_api_key(&args.api_key.0)
|
||||
.queue()
|
||||
.await;
|
||||
|
||||
let result = match result {
|
||||
Ok(result) => result,
|
||||
Err(err) => return Err(classify_fal_error(err)),
|
||||
};
|
||||
|
||||
Ok(EnqueuedRequest::from_queue_response(&result)?)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::creds::fal_api_key::FalApiKey;
|
||||
use crate::requests::image_gen::enqueue_recraft3_text_to_image::{enqueue_recraft3_text_to_image, Recraft3TextToImageArgs};
|
||||
use errors::AnyhowResult;
|
||||
use std::fs::read_to_string;
|
||||
|
||||
#[tokio::test]
|
||||
#[ignore]
|
||||
async fn test_recraft3() -> AnyhowResult<()> {
|
||||
// XXX: Don't commit secrets!
|
||||
let secret = read_to_string("/Users/bt/Artcraft/credentials/fal_api_key.txt")?;
|
||||
|
||||
let api_key = FalApiKey::from_str(&secret);
|
||||
|
||||
let args = Recraft3TextToImageArgs {
|
||||
prompt: "a corgi looks out over the water",
|
||||
api_key: &api_key,
|
||||
};
|
||||
|
||||
let result = enqueue_recraft3_text_to_image(args).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
pub mod enqueue_flux_pro_ultra_text_to_image;
|
||||
pub mod enqueue_recraft3_text_to_image;
|
||||
@@ -1,3 +1,4 @@
|
||||
pub mod enqueue_hunyuan2_image_to_3d;
|
||||
pub mod enqueue_kling_16_image_to_video;
|
||||
pub mod remove_background_rembg;
|
||||
pub mod remove_background_rembg;
|
||||
pub mod video_gen;
|
||||
pub mod image_gen;
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::creds::fal_api_key::FalApiKey;
|
||||
use crate::fal_error_plus::FalErrorPlus;
|
||||
use crate::error::classify_fal_error::classify_fal_error;
|
||||
use crate::error::fal_error_plus::FalErrorPlus;
|
||||
use fal::endpoints::fal_ai::imageutils::rembg::RemoveBackgroundInput;
|
||||
use fal::prelude::fal_ai::imageutils::rembg::rembg;
|
||||
use fal::prelude::*;
|
||||
@@ -21,12 +22,6 @@ pub struct RemBgResponse {
|
||||
pub async fn remove_background_rembg<P: AsRef<Path>>(image_path: P, api_key: &FalApiKey) -> Result<RemBgResponse, FalErrorPlus> {
|
||||
let image_url = file_to_base64_url(image_path)?;
|
||||
|
||||
/*
|
||||
TODO: Handle error messages -
|
||||
FalError(FalError(Other("{\"detail\": \"Invalid Key Authorization header format. Expected '<key_id>:<key_secret>'.\"}")))
|
||||
FalError(FalError(Other("{\"detail\": \"No user found for Key ID and Secret\"}")))
|
||||
*/
|
||||
|
||||
let request = RemoveBackgroundInput {
|
||||
image_url,
|
||||
crop_to_bbox: None,
|
||||
@@ -36,7 +31,12 @@ pub async fn remove_background_rembg<P: AsRef<Path>>(image_path: P, api_key: &Fa
|
||||
let result = rembg(request)
|
||||
.with_api_key(&api_key.0)
|
||||
.queue()
|
||||
.await?;
|
||||
.await;
|
||||
|
||||
let result = match result {
|
||||
Ok(result) => result,
|
||||
Err(err) => return Err(classify_fal_error(err)),
|
||||
};
|
||||
|
||||
let mut stream = result.stream(true).await?;
|
||||
|
||||
|
||||
+12
-11
@@ -1,15 +1,16 @@
|
||||
use crate::creds::fal_api_key::FalApiKey;
|
||||
use crate::fal_error_plus::FalErrorPlus;
|
||||
use crate::error::classify_fal_error::classify_fal_error;
|
||||
use crate::error::fal_error_plus::FalErrorPlus;
|
||||
use crate::model::enqueued_request::EnqueuedRequest;
|
||||
use fal::endpoints::fal_ai::kling_video::v1_6::pro::image_to_video::{image_to_video, ProImageToVideoRequest};
|
||||
use fal_client::file_to_base64_url::file_to_base64_url;
|
||||
use futures::StreamExt;
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
use url::Url;
|
||||
|
||||
pub struct Kling16Args<'a, P: AsRef<Path>> {
|
||||
pub image_path: P,
|
||||
pub prompt: &'a str,
|
||||
pub api_key: &'a FalApiKey,
|
||||
pub duration: Kling16Duration,
|
||||
}
|
||||
@@ -24,12 +25,6 @@ pub enum Kling16Duration {
|
||||
pub async fn enqueue_kling_16_image_to_video<P: AsRef<Path>>(args: Kling16Args<'_, P>) -> Result<EnqueuedRequest, FalErrorPlus> {
|
||||
let image_url = file_to_base64_url(args.image_path)?;
|
||||
|
||||
/*
|
||||
TODO: Handle error messages -
|
||||
FalError(FalError(Other("{\"detail\": \"Invalid Key Authorization header format. Expected '<key_id>:<key_secret>'.\"}")))
|
||||
FalError(FalError(Other("{\"detail\": \"No user found for Key ID and Secret\"}")))
|
||||
*/
|
||||
|
||||
let duration = match args.duration{
|
||||
Kling16Duration::Default => None,
|
||||
Kling16Duration::FiveSeconds => Some("5".to_string()), // Gross...
|
||||
@@ -38,7 +33,7 @@ pub async fn enqueue_kling_16_image_to_video<P: AsRef<Path>>(args: Kling16Args<'
|
||||
|
||||
let request = ProImageToVideoRequest {
|
||||
image_url,
|
||||
prompt: "".to_string(),
|
||||
prompt: args.prompt.to_string(),
|
||||
aspect_ratio: None,
|
||||
cfg_scale: None,
|
||||
duration,
|
||||
@@ -49,7 +44,12 @@ pub async fn enqueue_kling_16_image_to_video<P: AsRef<Path>>(args: Kling16Args<'
|
||||
let result = image_to_video(request)
|
||||
.with_api_key(&args.api_key.0)
|
||||
.queue()
|
||||
.await?;
|
||||
.await;
|
||||
|
||||
let result = match result {
|
||||
Ok(result) => result,
|
||||
Err(err) => return Err(classify_fal_error(err)),
|
||||
};
|
||||
|
||||
Ok(EnqueuedRequest::from_queue_response(&result)?)
|
||||
}
|
||||
@@ -57,7 +57,7 @@ pub async fn enqueue_kling_16_image_to_video<P: AsRef<Path>>(args: Kling16Args<'
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::creds::fal_api_key::FalApiKey;
|
||||
use crate::requests::enqueue_kling_16_image_to_video::{enqueue_kling_16_image_to_video, Kling16Args, Kling16Duration};
|
||||
use crate::requests::video_gen::enqueue_kling_16_image_to_video::{enqueue_kling_16_image_to_video, Kling16Args, Kling16Duration};
|
||||
use errors::AnyhowResult;
|
||||
use std::fs::read_to_string;
|
||||
use testing::test_file_path::test_file_path;
|
||||
@@ -74,6 +74,7 @@ mod tests {
|
||||
|
||||
let args = Kling16Args {
|
||||
image_path: image,
|
||||
prompt: "a corgi looks out over the water",
|
||||
api_key: &api_key,
|
||||
duration: Kling16Duration::Default,
|
||||
};
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
use crate::creds::fal_api_key::FalApiKey;
|
||||
use crate::error::classify_fal_error::classify_fal_error;
|
||||
use crate::error::fal_error_plus::FalErrorPlus;
|
||||
use crate::model::enqueued_request::EnqueuedRequest;
|
||||
use fal::endpoints::fal_ai::minimax::image_to_video::image_to_video;
|
||||
use fal::endpoints::fal_ai::minimax::image_to_video::VideoOutput;
|
||||
use fal::endpoints::fal_ai::minimax::image_to_video::ImageToVideoRequest;
|
||||
use fal_client::file_to_base64_url::file_to_base64_url;
|
||||
use futures::StreamExt;
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
|
||||
pub struct Minimax01Args<'a, P: AsRef<Path>> {
|
||||
pub image_path: P,
|
||||
pub prompt: &'a str,
|
||||
pub api_key: &'a FalApiKey,
|
||||
}
|
||||
|
||||
pub async fn enqueue_minimax_01_image_to_video<P: AsRef<Path>>(args: Minimax01Args<'_, P>) -> Result<EnqueuedRequest, FalErrorPlus> {
|
||||
let image_url = file_to_base64_url(args.image_path)?;
|
||||
|
||||
let request = ImageToVideoRequest {
|
||||
image_url,
|
||||
prompt: args.prompt.to_string(),
|
||||
prompt_optimizer: None,
|
||||
};
|
||||
|
||||
let result = image_to_video(request)
|
||||
.with_api_key(&args.api_key.0)
|
||||
.queue()
|
||||
.await;
|
||||
|
||||
let result = match result {
|
||||
Ok(result) => result,
|
||||
Err(err) => return Err(classify_fal_error(err)),
|
||||
};
|
||||
|
||||
Ok(EnqueuedRequest::from_queue_response(&result)?)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::creds::fal_api_key::FalApiKey;
|
||||
use errors::AnyhowResult;
|
||||
use std::fs::read_to_string;
|
||||
use testing::test_file_path::test_file_path;
|
||||
use crate::requests::video_gen::enqueue_minimax_01_image_to_video::{enqueue_minimax_01_image_to_video, Minimax01Args};
|
||||
|
||||
#[tokio::test]
|
||||
#[ignore]
|
||||
async fn test_minimax_video() -> AnyhowResult<()> {
|
||||
let image = test_file_path("test_data/image/juno.jpg")?;
|
||||
|
||||
// XXX: Don't commit secrets!
|
||||
let secret = read_to_string("/Users/bt/Artcraft/credentials/fal_api_key.txt")?;
|
||||
|
||||
let api_key = FalApiKey::from_str(&secret);
|
||||
|
||||
let args = Minimax01Args {
|
||||
image_path: image,
|
||||
prompt: "a dog jumps into the water",
|
||||
api_key: &api_key,
|
||||
};
|
||||
|
||||
let result = enqueue_minimax_01_image_to_video(args).await?;
|
||||
|
||||
println!("Request ID: {:?}", result.request_id);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
pub mod enqueue_kling_16_image_to_video;
|
||||
pub mod enqueue_minimax_01_image_to_video;
|
||||
@@ -1,9 +1,13 @@
|
||||
use crate::creds::fal_api_key::FalApiKey;
|
||||
use crate::fal_error_plus::FalErrorPlus;
|
||||
use crate::error::fal_error_plus::FalErrorPlus;
|
||||
use crate::model::enqueued_request::EnqueuedRequest;
|
||||
use crate::model::fal_endpoint::FalEndpoint;
|
||||
use anyhow::anyhow;
|
||||
use fal::endpoints::fal_ai::flux_pro::v1_1_ultra::Output;
|
||||
use fal::endpoints::fal_ai::hunyuan3d::v2::ObjectOutput;
|
||||
use fal::endpoints::fal_ai::kling_video::v1_6::pro::effects::I2VOutput;
|
||||
use fal::endpoints::fal_ai::minimax::image_to_video::VideoOutput;
|
||||
use fal::endpoints::fal_ai::recraft_v3::TextToImageOutput;
|
||||
use fal::prelude::QueueResponse;
|
||||
use fal::queue::{Queue, QueueStatus};
|
||||
use reqwest::Client;
|
||||
@@ -20,6 +24,11 @@ impl QueueStatusChecker {
|
||||
|
||||
pub async fn check_status(&self, request: &EnqueuedRequest) -> Result<QueueStatus, FalErrorPlus> {
|
||||
match &request.fal_endpoint {
|
||||
FalEndpoint::FluxProUltraTextToImage => {
|
||||
let queue = self.make_queue::<Output>(&request);
|
||||
let status = queue.status(false).await?;
|
||||
Ok(status)
|
||||
}
|
||||
FalEndpoint::Hunyuan3d2Base => {
|
||||
let queue = self.make_queue::<ObjectOutput>(&request);
|
||||
let status = queue.status(false).await?;
|
||||
@@ -30,6 +39,16 @@ impl QueueStatusChecker {
|
||||
let status = queue.status(false).await?;
|
||||
Ok(status)
|
||||
}
|
||||
FalEndpoint::Minimax01ImageToVideo => {
|
||||
let queue = self.make_queue::<VideoOutput>(&request); // Assuming Minimax uses the same output type
|
||||
let status = queue.status(false).await?;
|
||||
Ok(status)
|
||||
}
|
||||
FalEndpoint::RecraftV3TextToImage => {
|
||||
let queue = self.make_queue::<TextToImageOutput>(&request);
|
||||
let status = queue.status(false).await?;
|
||||
Ok(status)
|
||||
}
|
||||
FalEndpoint::Other(endpoint) => {
|
||||
Err(FalErrorPlus::UnhandledEndpoint(format!("Unsupported endpoint: {}", endpoint)))
|
||||
}
|
||||
@@ -38,15 +57,35 @@ impl QueueStatusChecker {
|
||||
|
||||
pub async fn get_download_url(&self, request: &EnqueuedRequest) -> Result<String, FalErrorPlus> {
|
||||
match &request.fal_endpoint {
|
||||
FalEndpoint::FluxProUltraTextToImage => {
|
||||
let queue = self.make_queue::<Output>(&request);
|
||||
let response = queue.response().await?;
|
||||
// TODO(bt,2025-05-26): Handle multiple images
|
||||
Ok(response.images.first()
|
||||
.ok_or_else(|| FalErrorPlus::AnyhowError(anyhow!("No images returned")))?
|
||||
.url.clone())
|
||||
}
|
||||
FalEndpoint::Hunyuan3d2Base => {
|
||||
let queue = self.make_queue::<ObjectOutput>(&request);
|
||||
let status = queue.response().await?;
|
||||
Ok(status.model_mesh.url)
|
||||
let response = queue.response().await?;
|
||||
Ok(response.model_mesh.url)
|
||||
}
|
||||
FalEndpoint::Kling16ImageToVideo => {
|
||||
let queue = self.make_queue::<I2VOutput>(&request);
|
||||
let status = queue.response().await?;
|
||||
Ok(status.video.url)
|
||||
let response = queue.response().await?;
|
||||
Ok(response.video.url)
|
||||
}
|
||||
FalEndpoint::Minimax01ImageToVideo => {
|
||||
let queue = self.make_queue::<VideoOutput>(&request); // Assuming Minimax uses the same output type
|
||||
let response = queue.response().await?;
|
||||
Ok(response.video.url)
|
||||
}
|
||||
FalEndpoint::RecraftV3TextToImage => {
|
||||
let queue = self.make_queue::<TextToImageOutput>(&request);
|
||||
let response = queue.response().await?;
|
||||
Ok(response.images.first()
|
||||
.ok_or_else(|| FalErrorPlus::AnyhowError(anyhow!("No images returned")))?
|
||||
.url.clone())
|
||||
}
|
||||
FalEndpoint::Other(endpoint) => {
|
||||
Err(FalErrorPlus::UnhandledEndpoint(format!("Unsupported endpoint: {}", endpoint)))
|
||||
|
||||
@@ -17,17 +17,14 @@ path = "src/lib.rs"
|
||||
workspace-build-acceleration = { workspace = true }
|
||||
|
||||
# Internal
|
||||
crockford = { path = "../../data/crockford" }
|
||||
errors = { path = "../../errors" }
|
||||
idempotency = { path = "../../idempotency" }
|
||||
subprocess_common = { path = "../../subprocess_common" }
|
||||
|
||||
# External
|
||||
anyhow = { workspace = true }
|
||||
base64 = { workspace = true }
|
||||
chrono = { workspace = true}
|
||||
cookie = { workspace = true }
|
||||
hex-literal = { workspace = true }
|
||||
log = { workspace = true }
|
||||
once_cell= { workspace = true }
|
||||
rand = { workspace = true }
|
||||
@@ -42,4 +39,3 @@ toml = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
testing = { path = "../../testing" }
|
||||
filesys = { path = "../../files/filesys" }
|
||||
@@ -4,4 +4,5 @@ pub mod image_upload_from_file_with_session_auto_renew;
|
||||
pub mod list_sora_task_status_with_session_auto_renew;
|
||||
pub mod maybe_refresh_credentials_on_sora_error;
|
||||
pub mod maybe_upgrade_or_renew_session;
|
||||
pub mod simple_image_gen_with_session_auto_renew;
|
||||
pub mod wait_for_image_gen_status;
|
||||
+146
@@ -0,0 +1,146 @@
|
||||
use crate::creds::credential_migration::CredentialMigrationRef;
|
||||
use crate::creds::sora_credential_set::SoraCredentialSet;
|
||||
use crate::creds::sora_jwt_bearer_token::SoraJwtBearerToken;
|
||||
use crate::creds::sora_sentinel::SoraSentinel;
|
||||
use crate::requests::bearer::generate::generate_bearer_with_cookie;
|
||||
use crate::requests::image_gen::common::{ImageSize, NumImages, SoraImageGenResponse};
|
||||
use crate::requests::image_gen::sora_image_gen_remix::{sora_image_gen_remix, SoraImageGenRemixRequest};
|
||||
use crate::requests::image_gen::sora_image_gen_simple::{sora_image_gen_simple, SoraImageGenSimpleRequest};
|
||||
use crate::requests::image_gen::{image_gen_http_request, SoraImageGenError};
|
||||
use crate::requests::sentinel_refresh::generate::token::generate_token;
|
||||
use crate::sora_error::SoraError;
|
||||
use anyhow::anyhow;
|
||||
use errors::AnyhowResult;
|
||||
use log::{info, warn};
|
||||
use std::time::Duration;
|
||||
|
||||
pub struct SimpleImageGenAutoRenewRequest<'a> {
|
||||
pub prompt: String,
|
||||
pub num_images: NumImages,
|
||||
pub image_size: ImageSize,
|
||||
pub credentials: &'a SoraCredentialSet,
|
||||
/// This function can try several different requests. This is the timeout for *individual* requests.
|
||||
pub request_timeout: Option<Duration>,
|
||||
}
|
||||
|
||||
/// Image request with retry and session auto-renewal.
|
||||
/// If a new sora credential is returned, replace the old one with the new one.
|
||||
pub async fn simple_image_gen_with_session_auto_renew(request: SimpleImageGenAutoRenewRequest<'_>) -> Result<(SoraImageGenResponse, Option<SoraCredentialSet>), SoraError> {
|
||||
let result = sora_image_gen_simple(SoraImageGenSimpleRequest {
|
||||
prompt: request.prompt.clone(), // NB: Clone because used again
|
||||
num_images: request.num_images,
|
||||
image_size: request.image_size,
|
||||
credentials: CredentialMigrationRef::New(request.credentials),
|
||||
request_timeout: request.request_timeout,
|
||||
}).await;
|
||||
|
||||
let err = match result {
|
||||
Ok(response) => return Ok((response, None)),
|
||||
Err(err) => err,
|
||||
};
|
||||
|
||||
warn!("Image generation failed: {:?}", err);
|
||||
|
||||
let mut refresh_jwt = false;
|
||||
let mut refresh_sentinel = false;
|
||||
|
||||
match err {
|
||||
// We'll fail these requests...
|
||||
SoraImageGenError::TooManyConcurrentTasks(_) => {
|
||||
return Err(SoraError::TooManyConcurrentTasks);
|
||||
}
|
||||
SoraImageGenError::GenericError(err) => {
|
||||
return Err(SoraError::OtherBadStatus(anyhow!("image gen failed with GenericError: {:?}", err)))
|
||||
}
|
||||
SoraImageGenError::NetworkError(err) => {
|
||||
// TODO: The underlying type should be a reqwest::Error.
|
||||
return Err(SoraError::OtherBadStatus(anyhow!("network error: {:?}", err)))
|
||||
}
|
||||
SoraImageGenError::UsernameRequired(_err) => {
|
||||
return Err(SoraError::SoraUsernameNotYetCreated)
|
||||
}
|
||||
|
||||
// We'll retry these requests...
|
||||
|
||||
SoraImageGenError::SentinelBlock(err) => {
|
||||
warn!("Image generation failed due to sentinel block error: {:?}", err);
|
||||
refresh_sentinel = true;
|
||||
}
|
||||
SoraImageGenError::TokenExpired(err) => {
|
||||
warn!("Image generation failed due to token expired error: {:?}", err);
|
||||
refresh_sentinel = true; // TODO: Not sure what this error is, actually.
|
||||
refresh_jwt = true;
|
||||
}
|
||||
SoraImageGenError::InvalidJwt(err) => {
|
||||
warn!("Image generation failed due to invalid jwt error: {:?}", err);
|
||||
refresh_jwt = true;
|
||||
}
|
||||
}
|
||||
|
||||
let mut new_bearer = None;
|
||||
|
||||
if refresh_jwt {
|
||||
info!("Generating new JWT bearer token...");
|
||||
let cookies = request.credentials.cookies.as_str();
|
||||
let response = generate_bearer_with_cookie(cookies).await;
|
||||
match response {
|
||||
Err(err) => {
|
||||
return Err(SoraError::OtherBadStatus(anyhow!("failed to generate new JWT bearer token: {:?}", err)))
|
||||
}
|
||||
Ok(bearer) => {
|
||||
match SoraJwtBearerToken::new(bearer) {
|
||||
Err(err) => {
|
||||
return Err(SoraError::OtherBadStatus(anyhow!("Failed to parse new JWT bearer token: {:?}", err)));
|
||||
}
|
||||
Ok(bearer) => new_bearer = Some(bearer),
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
let mut new_sentinel = None;
|
||||
|
||||
if refresh_sentinel {
|
||||
info!("Generating new sentinel...");
|
||||
let response = generate_token().await;
|
||||
match response {
|
||||
Err(err) => {
|
||||
return Err(SoraError::OtherBadStatus(anyhow!("failed to generate new sentinel: {:?}", err)))
|
||||
}
|
||||
Ok(sentinel) => new_sentinel = Some(SoraSentinel::new(sentinel)),
|
||||
}
|
||||
}
|
||||
|
||||
let mut new_creds = request.credentials.clone();
|
||||
|
||||
if let Some(bearer) = new_bearer {
|
||||
new_creds.jwt_bearer_token = Some(bearer);
|
||||
}
|
||||
|
||||
if let Some(sentinel) = new_sentinel {
|
||||
new_creds.sora_sentinel = Some(sentinel);
|
||||
}
|
||||
|
||||
// Now try again...
|
||||
|
||||
let result = sora_image_gen_simple(SoraImageGenSimpleRequest {
|
||||
prompt: request.prompt,
|
||||
num_images: request.num_images,
|
||||
image_size: request.image_size,
|
||||
credentials: CredentialMigrationRef::New(&new_creds),
|
||||
request_timeout: request.request_timeout,
|
||||
}).await;
|
||||
|
||||
match result {
|
||||
Ok(response) => Ok((response, Some(new_creds))),
|
||||
Err(err) => match err {
|
||||
image_gen_http_request::SoraImageGenError::TooManyConcurrentTasks(err) => {
|
||||
Err(SoraError::TooManyConcurrentTasks)
|
||||
}
|
||||
_ => {
|
||||
warn!("Image gen failed again: {:?}", err);
|
||||
Err(SoraError::OtherBadStatus(anyhow!("image gen failed again: {:?}", err)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
use crate::creds::credential_migration::CredentialMigrationRef;
|
||||
use crate::requests::image_gen::common::{ImageSize, NumImages, SoraImageGenResponse};
|
||||
use crate::requests::image_gen::image_gen_http_request::{image_gen_http_request, OperationType, RawSoraImageGenRequest, VideoGenType};
|
||||
use errors::AnyhowResult;
|
||||
use crate::requests::image_gen::SoraImageGenError;
|
||||
use std::time::Duration;
|
||||
|
||||
pub struct SoraImageGenSimpleRequest<'a> {
|
||||
@@ -12,7 +12,7 @@ pub struct SoraImageGenSimpleRequest<'a> {
|
||||
pub request_timeout: Option<Duration>,
|
||||
}
|
||||
|
||||
pub async fn sora_image_gen_simple(args: SoraImageGenSimpleRequest<'_>) -> AnyhowResult<SoraImageGenResponse> {
|
||||
pub async fn sora_image_gen_simple(args: SoraImageGenSimpleRequest<'_>) -> Result<SoraImageGenResponse, SoraImageGenError> {
|
||||
let sora_request = RawSoraImageGenRequest {
|
||||
r#type: VideoGenType::ImageGen,
|
||||
operation: OperationType::SimpleCompose,
|
||||
|
||||
@@ -17,7 +17,7 @@ normal = ["workspace-build-acceleration"]
|
||||
|
||||
[dependencies]
|
||||
# Workspace hack (faster compile times)
|
||||
workspace-build-acceleration = { version = "0.1", path = "../../workspace-build-acceleration" }
|
||||
workspace-build-acceleration = { workspace = true }
|
||||
|
||||
# Internal
|
||||
crockford = { path = "../data/crockford" }
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
[package]
|
||||
name = "build_metadata"
|
||||
resolver = "2" # NB: Required by `build-info`
|
||||
edition = "2024"
|
||||
version = "0.0.1"
|
||||
authors = [
|
||||
"Brandon Thomas <bt@brand.io>",
|
||||
"Brandon Thomas <echelon@gmail.com>",
|
||||
]
|
||||
publish = false
|
||||
|
||||
[lib]
|
||||
name = "build_metadata"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
normal = ["workspace-build-acceleration"]
|
||||
|
||||
[dependencies]
|
||||
# Workspace hack (faster compile times)
|
||||
workspace-build-acceleration = { workspace = true }
|
||||
|
||||
# Internal
|
||||
# (None yet)
|
||||
|
||||
# External
|
||||
build-info = "0.0.40"
|
||||
|
||||
[dev-dependencies]
|
||||
# None yet
|
||||
|
||||
[build-dependencies]
|
||||
build-info-build = "0.0.40"
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
|
||||
fn main() {
|
||||
// Tell Cargo that if the given file changes, to rerun this build script.
|
||||
// TODO: Use this to test the GIT_SHA, etc. files that CI dumps into the working directory
|
||||
// println!("cargo::rerun-if-changed=Cargo.toml");
|
||||
|
||||
// Make build info available in the main crate sources.
|
||||
build_info_build::build_script();
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
use std::ops::Deref;
|
||||
use build_info::chrono::{DateTime, Utc};
|
||||
|
||||
build_info::build_info!(fn version);
|
||||
|
||||
pub fn build_timestamp() -> DateTime<Utc> {
|
||||
version().timestamp
|
||||
}
|
||||
|
||||
pub fn git_commit_id() -> Option<&'static str> {
|
||||
version().version_control
|
||||
.as_ref()
|
||||
.map(|vc| vc.git())
|
||||
.flatten()
|
||||
.map(|git| git.commit_id.deref())
|
||||
}
|
||||
|
||||
pub fn git_commit_short_id() -> Option<&'static str> {
|
||||
version().version_control
|
||||
.as_ref()
|
||||
.map(|vc| vc.git())
|
||||
.flatten()
|
||||
.map(|git| git.commit_short_id.deref())
|
||||
}
|
||||
|
||||
pub fn git_commit_timestamp() -> Option<DateTime<Utc>> {
|
||||
version().version_control
|
||||
.as_ref()
|
||||
.map(|vc| vc.git())
|
||||
.flatten()
|
||||
.map(|git| git.commit_timestamp)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::git_commit_id;
|
||||
|
||||
#[test]
|
||||
#[ignore] // Run manually for testing, not in CI
|
||||
fn test_git_commit_id() {
|
||||
assert_eq!(git_commit_id(), None);
|
||||
}
|
||||
}
|
||||
@@ -16,32 +16,28 @@ path = "src/lib.rs"
|
||||
normal = ["workspace-build-acceleration"]
|
||||
|
||||
[dependencies]
|
||||
# Workspace hack (faster compile times)
|
||||
workspace-build-acceleration = { workspace = true }
|
||||
|
||||
# Internal
|
||||
errors = { path = "../../errors" }
|
||||
|
||||
# Workspace hack (faster compile times)
|
||||
workspace-build-acceleration = { version = "0.1", path = "../../../workspace-build-acceleration" }
|
||||
errors = { workspace = true }
|
||||
|
||||
# External
|
||||
anyhow = "1.0.86"
|
||||
base64 = "0.22.1"
|
||||
log = "0.4.14"
|
||||
once_cell = "1.18.0"
|
||||
log = { workspace = true }
|
||||
once_cell = { workspace = true }
|
||||
regex = "1.5.4"
|
||||
|
||||
# Web
|
||||
actix-http = "3.7.0"
|
||||
actix-web = "4.7.0"
|
||||
actix-http = { workspace = true }
|
||||
actix-web = { workspace = true }
|
||||
|
||||
# Language
|
||||
language-tags = "0.3.2" # Parsing single tags richly
|
||||
#accept-language = "2.0.0" # Parsing many tags poorly
|
||||
|
||||
# Serialization
|
||||
serde = "1.0.125"
|
||||
serde_derive = "1.0.125"
|
||||
serde_json = "1.0.108"
|
||||
serde = { workspace = true }
|
||||
serde_derive = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
actix-rt = "2.10.0"
|
||||
# (None yet)
|
||||
@@ -18,10 +18,10 @@ normal = ["workspace-build-acceleration"]
|
||||
|
||||
[dependencies]
|
||||
# Workspace hack (faster compile times)
|
||||
workspace-build-acceleration = { version = "0.1", path = "../../workspace-build-acceleration" }
|
||||
workspace-build-acceleration = { workspace = true }
|
||||
|
||||
# Internal
|
||||
errors = { path = "../errors" }
|
||||
# (None Yet)
|
||||
|
||||
# External
|
||||
# (None Yet)
|
||||
|
||||
@@ -17,13 +17,13 @@ path = "src/lib.rs"
|
||||
normal = ["workspace-build-acceleration"]
|
||||
|
||||
[dependencies]
|
||||
# cargo-hakari workspace hack (faster compile times)
|
||||
workspace-build-acceleration = { workspace = true }
|
||||
|
||||
# NB: This is one of the most central crates in the monorepo and everything depends on it.
|
||||
# Consider the dependencies here wisely.
|
||||
# Ideally we have almost nothing as a dependency of this crate.
|
||||
anyhow = "1.0.86"
|
||||
|
||||
# Workspace hack (faster compile times)
|
||||
workspace-build-acceleration = { version = "0.1", path = "../../workspace-build-acceleration" }
|
||||
anyhow = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
# None yet
|
||||
|
||||
@@ -26,4 +26,3 @@ mimetypes = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
testing = { path = "../../testing" }
|
||||
filesys = { path = "../../files/filesys" }
|
||||
|
||||
@@ -19,16 +19,15 @@ path = "src/lib.rs"
|
||||
normal = ["workspace-build-acceleration"]
|
||||
|
||||
[dependencies]
|
||||
# Workspace hack (faster compile times)
|
||||
workspace-build-acceleration = { workspace = true }
|
||||
|
||||
# Internal
|
||||
errors = { path = "../errors" }
|
||||
redis_common = { path = "../redis_common" }
|
||||
|
||||
# Workspace hack (faster compile times)
|
||||
workspace-build-acceleration = { version = "0.1", path = "../../workspace-build-acceleration" }
|
||||
errors = { workspace = true }
|
||||
redis_common = { path = "../../schema/database/redis_common" }
|
||||
|
||||
# External
|
||||
anyhow = "1.0.86"
|
||||
anyhow = { workspace = true }
|
||||
chrono = { version = "0.4.22", features = ["serde"] }
|
||||
log = "0.4.14"
|
||||
r2d2_redis = "0.14.0"
|
||||
|
||||
@@ -32,8 +32,8 @@ primitives = { path = "../../data/primitives" }
|
||||
cudarc = "0.13.7"
|
||||
|
||||
# External
|
||||
anyhow = "1.0"
|
||||
base64 = "0.22.1"
|
||||
anyhow = { workspace = true }
|
||||
base64 = { workspace = true }
|
||||
bytes = "1.10"
|
||||
candle-core = { path = "../../../vendor/candle/candle-core", features = ["cuda"] }
|
||||
candle-nn = { path = "../../../vendor/candle/candle-nn", features = ["cuda"] }
|
||||
|
||||
@@ -20,11 +20,11 @@ normal = ["workspace-build-acceleration"]
|
||||
# Internal
|
||||
bucket_paths = { path = "../../lib/bucket_paths" }
|
||||
cloud_storage = { path = "../../lib/api_clients/cloud_storage" }
|
||||
enums = { path = "../../_types/enums" }
|
||||
enums = { path = "../../schema/public/enums" }
|
||||
errors = { path = "../../lib/errors" }
|
||||
jobs_common = { path = "../../lib/jobs_common" }
|
||||
mysql_queries = { path = "../../lib/mysql_queries" }
|
||||
tokens = { path = "../../_types/tokens" }
|
||||
mysql_queries = { path = "../../schema/database/mysql_queries" }
|
||||
tokens = { path = "../../schema/public/tokens" }
|
||||
|
||||
# External
|
||||
anyhow = "1.0.86"
|
||||
|
||||
@@ -16,12 +16,12 @@ path = "src/lib.rs"
|
||||
normal = ["workspace-build-acceleration"]
|
||||
|
||||
[dependencies]
|
||||
# cargo-hakari workspace hack (faster compile times)
|
||||
workspace-build-acceleration = { workspace = true }
|
||||
|
||||
# Internal
|
||||
# (None yet)
|
||||
|
||||
# Workspace hack (faster compile times)
|
||||
workspace-build-acceleration = { version = "0.1", path = "../../workspace-build-acceleration" }
|
||||
|
||||
# External
|
||||
# (None yet)
|
||||
|
||||
|
||||
@@ -16,14 +16,13 @@ path = "src/lib.rs"
|
||||
normal = ["workspace-build-acceleration"]
|
||||
|
||||
[dependencies]
|
||||
# Workspace hack (faster compile times)
|
||||
workspace-build-acceleration = { workspace = true }
|
||||
|
||||
# Internal
|
||||
actix_helpers = { path = "../actix_helpers" }
|
||||
reusable_types = { path = "../../_types/reusable_types" }
|
||||
|
||||
# Workspace hack (faster compile times)
|
||||
workspace-build-acceleration = { version = "0.1", path = "../../workspace-build-acceleration" }
|
||||
reusable_types = { path = "../../schema/public/reusable_types" }
|
||||
|
||||
# External
|
||||
actix-web = "4.7.0"
|
||||
anyhow = "1.0.86"
|
||||
actix-web = { workspace = true }
|
||||
anyhow = { workspace = true }
|
||||
|
||||
@@ -17,7 +17,7 @@ normal = ["workspace-build-acceleration"]
|
||||
|
||||
[dependencies]
|
||||
# Internal
|
||||
enums = { path = "../../_types/enums" }
|
||||
enums = { path = "../../schema/public/enums" }
|
||||
errors = { path = "../../lib/errors" }
|
||||
|
||||
# Workspace hack (faster compile times)
|
||||
|
||||
+6
-7
@@ -16,13 +16,13 @@ path = "src/lib.rs"
|
||||
normal = ["workspace-build-acceleration"]
|
||||
|
||||
[dependencies]
|
||||
# Internal
|
||||
enums = { path = "../../_types/enums" }
|
||||
errors = { path = "../errors" }
|
||||
tokens = { path = "../../_types/tokens" }
|
||||
|
||||
# Workspace hack (faster compile times)
|
||||
workspace-build-acceleration = { version = "0.1", path = "../../workspace-build-acceleration" }
|
||||
workspace-build-acceleration = { workspace = true }
|
||||
|
||||
# Internal
|
||||
enums = { workspace = true }
|
||||
errors = { workspace = true }
|
||||
tokens = { workspace = true }
|
||||
|
||||
# External
|
||||
elasticsearch = "8.5.0-alpha.1"
|
||||
@@ -32,7 +32,6 @@ once_cell = "1.19.0"
|
||||
|
||||
# Serialization
|
||||
chrono = { version = "0.4.22", features = ["serde"] }
|
||||
regex = "1.10.2"
|
||||
serde = { version = "1.0.152", features = ["derive"] }
|
||||
serde_json = "1.0.108"
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ use tokens::tokens::users::UserToken;
|
||||
use crate::documents::media_file_document::{MEDIA_FILE_INDEX, MediaFileDocument};
|
||||
|
||||
static JSON_QUERY : Lazy<Value> = Lazy::new(|| {
|
||||
const QUERY_TEMPLATE : &str = include_str!("../../../../../_elasticsearch/searches/media_files/search.json");
|
||||
const QUERY_TEMPLATE : &str = include_str!("../../../../../../_elasticsearch/searches/media_files/search.json");
|
||||
|
||||
let json : Value = serde_json::from_str(QUERY_TEMPLATE)
|
||||
.expect("json should parse");
|
||||
+1
-1
@@ -16,7 +16,7 @@ use crate::searches::search_model_weights::predicates::{creator_user_token_predi
|
||||
use crate::searches::search_model_weights::sort::add_sort;
|
||||
|
||||
static JSON_QUERY : Lazy<Value> = Lazy::new(|| {
|
||||
const QUERY_TEMPLATE : &str = include_str!("../../../../../../_elasticsearch/searches/model_weights/search.json");
|
||||
const QUERY_TEMPLATE : &str = include_str!("../../../../../../../_elasticsearch/searches/model_weights/search.json");
|
||||
|
||||
let json : Value = serde_json::from_str(QUERY_TEMPLATE)
|
||||
.expect("json should parse");
|
||||
+10
-11
@@ -20,18 +20,17 @@ normal = ["workspace-build-acceleration"]
|
||||
workspace-build-acceleration = { workspace = true }
|
||||
|
||||
# Internal
|
||||
bucket_paths = { path = "../bucket_paths" }
|
||||
composite_identifiers = { path = "../../_types/composite_identifiers" }
|
||||
enums = { path = "../../_types/enums" }
|
||||
bucket_paths = { path = "../../../lib/bucket_paths" }
|
||||
composite_identifiers = { path = "../../../schema/public/composite_identifiers" }
|
||||
enums = { workspace = true }
|
||||
errors = { workspace = true }
|
||||
idempotency = { path = "../idempotency" }
|
||||
primitives = { path = "../data/primitives" }
|
||||
reusable_types = { path = "../../_types/reusable_types" }
|
||||
tokens = { path = "../../_types/tokens" }
|
||||
idempotency = { workspace = true }
|
||||
reusable_types = { path = "../../../schema/public/reusable_types" }
|
||||
tokens = { workspace = true }
|
||||
|
||||
# External
|
||||
anyhow = { workspace = true }
|
||||
chrono = { version = "0.4.22", features = ["serde"] }
|
||||
chrono = { workspace = true }
|
||||
log = { workspace = true }
|
||||
|
||||
# Needed to safety check some queries we can't use escaping for
|
||||
@@ -42,13 +41,13 @@ regex = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_derive = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
serial_test = "3.0.0"
|
||||
|
||||
# BigNum
|
||||
num-traits = "0.2.19"
|
||||
|
||||
tokio = { version = "1.38.0", features = ["full"] }
|
||||
rand = "0.8"
|
||||
rand = { workspace = true }
|
||||
sqlx = { version = "0.7.2", features = [ "mysql", "runtime-tokio", "tls-rustls", "chrono", "bigdecimal" ] }
|
||||
|
||||
|
||||
[dev-dependencies]
|
||||
serial_test = "3.0.0"
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user